简体   繁体   中英

Trying to convert a C++ console app into a C# class library

I am trying to convert the C++ console app detailed here into a C# class library so that you can provide the class library a set of source coordinates, destination coordinates and a 3D double array and it take a 2D slice of that array and use it as a grid. I want the C# class library to return the path steps as a list or array of coordinates and error status.

So far i have the following C# code.

using System;
using System.Collections.Generic;

namespace AStarLibrary
{
    public class AStar
    {
        private int cols_ = 0;
        private int rows_ = 0;

        public void InitAStar(int cols, int rows, int srcX, int srcY, int destX, int destY)
        {
            cols_ = cols;
            rows_ = rows;
        }

        public int GetRow(int row)
        {
            return row;
        }

        // A structure to hold the neccesary parameters 
        struct cell
        {
            // Row and Column index of its parent 
            // Note that 0 <= i <= ROW-1 & 0 <= j <= COL-1 
            public int parent_i, parent_j;
            // f = g + h 
            public double f, g, h;
        };

        // A Utility Function to check whether given cell (row, col) 
        // is a valid cell or not. 
        bool isValid(int row, int col)
        {
            // Returns true if row number and column number 
            // is in range 
            return (row >= 0) && (row < rows_) &&
                (col >= 0) && (col < cols_);
        }

        // A Utility Function to check whether the given cell is 
        // blocked or not 
        bool isUnBlocked(double[,,] grid, int row, int col)
        {
            // Returns true if the cell is not blocked else false 
            if (grid[col, row, 0] != -1)
                return (true);
            else
                return (false);
        }

        // A Utility Function to check whether destination cell has 
        // been reached or not 
        bool isDestination(int col, int row, int[] dest)
        {
            if (col == dest[0] && row == dest[1])
                return (true);
            else
                return (false);
        }

        // A Utility Function to calculate the 'h' heuristics. 
        double calculateHValue(int row, int col, int[] dest)
        {
            // Return using the distance formula 
            return ((double)Math.Sqrt((row - dest[0]) * (row - dest[0])
                + (col - dest[1]) * (col - dest[1])));
        }


        //trace path


        // A Function to find the shortest path between 
        // a given source cell to a destination cell according 
        // to A* Search Algorithm 
        public void aStarSearch(double[,,] grid, int[] src, int[] dest)
        {
            // If the source is out of range 
            if (isValid(src[0], src[1]) == false)
            {
                Console.WriteLine("Source is invalid\n");
                return;
            }

            // If the destination is out of range 
            if (isValid(dest[0], dest[1]) == false)
            {
                Console.WriteLine("Destination is invalid\n");
                return;
            }

            // Either the source or the destination is blocked 
            if (isUnBlocked(grid, src[0], src[1]) == false ||
                isUnBlocked(grid, dest[0], dest[1]) == false)
            {
                Console.WriteLine("Source or the destination is blocked\n");
                return;
            }

            // If the destination cell is the same as source cell 
            if (isDestination(src[0], src[1], dest) == true)
            {
                Console.WriteLine("We are already at the destination\n");
                return;
            }

            // Create a closed list and initialise it to false which means 
            // that no cell has been included yet 
            // This closed list is implemented as a boolean 2D array 
            bool[,] closedList = new bool[cols_, rows_];

            // Declare a 2D array of structure to hold the details 
            //of that cell 
            cell[,] cellDetails = new cell[cols_, rows_];

            int i, j;

            for (i = 0; i < cols_; i++)
            {
                for (j = 0; j < rows_; j++)
                {
                    cellDetails[i,j].f = float.MaxValue;
                    cellDetails[i,j].g = float.MaxValue;
                    cellDetails[i,j].h = float.MaxValue;
                    cellDetails[i,j].parent_i = -1;
                    cellDetails[i,j].parent_j = -1;
                }
            }

            // Initialising the parameters of the starting node 
            i = src[0];
            j = src[1];
            cellDetails[i, j].f = 0.0;
            cellDetails[i, j].g = 0.0;
            cellDetails[i, j].h = 0.0;
            cellDetails[i, j].parent_i = i;
            cellDetails[i, j].parent_j = j;

            /*
            Create an open list having information as-
            <f, <i, j>>
            where f = g + h,
            and i, j are the row and column index of that cell
            Note that 0 <= i <= ROW-1 & 0 <= j <= COL-1
            This open list is implenented as a set of pair of pair.*/
            List<double[]> openList = new List<double[]>();

            // Put the starting cell on the open list and set its 
            // 'f' as 0 
            openList.Add(new double[] {i, j, 0 });

            // We set this boolean value as false as initially 
            // the destination is not reached. 
            bool foundDest = false;

            while (openList.Count > 0)
            {
                double[] p = openList[0];

                // Remove this vertex from the open list 
                openList.RemoveAt(0);

                // Add this vertex to the closed list 
                i = p.second.first;
                j = p.second.second;
                closedList[i, j] = true;

                /*
                    Generating all the 8 successor of this cell

                        N.W N N.E
                        \ | /
                        \ | /
                        W----Cell----E
                            / | \
                        / | \
                        S.W S S.E

                    Cell-->Popped Cell (i, j)
                    N --> North  (i-1, j)
                    S --> South  (i+1, j)
                    E --> East   (i, j+1)
                    W --> West       (i, j-1)
                    N.E--> North-East (i-1, j+1)
                    N.W--> North-West (i-1, j-1)
                    S.E--> South-East (i+1, j+1)
                    S.W--> South-West (i+1, j-1)*/

                // To store the 'g', 'h' and 'f' of the 8 successors 
                double gNew, hNew, fNew;

                //----------- 1st Successor (North) ------------ 

                // Only process this cell if this is a valid one 
                if (isValid(i - 1, j) == true)
                {
                    // If the destination cell is the same as the 
                    // current successor 
                    if (isDestination(i - 1, j, dest) == true)
                    {
                        // Set the Parent of the destination cell 
                        cellDetails[i - 1, j].parent_i = i;
                        cellDetails[i - 1, j].parent_j = j;
                        Console.WriteLine("The destination cell is found\n");
                        //tracePath(cellDetails, dest);
                        foundDest = true;
                        return;
                    }
                    // If the successor is already on the closed 
                    // list or if it is blocked, then ignore it. 
                    // Else do the following 
                    else if (closedList[i - 1, j] == false &&
                        isUnBlocked(grid, i - 1, j) == true)
                    {
                        gNew = cellDetails[i, j].g + 1.0;
                        hNew = calculateHValue(i - 1, j, dest);
                        fNew = gNew + hNew;

                        // If it isn’t on the open list, add it to 
                        // the open list. Make the current square 
                        // the parent of this square. Record the 
                        // f, g, and h costs of the square cell 
                        //           OR 
                        // If it is on the open list already, check 
                        // to see if this path to that square is better, 
                        // using 'f' cost as the measure. 
                        if (cellDetails[i - 1, j].f == float.MaxValue ||
                            cellDetails[i - 1, j].f > fNew)
                        {
                            openList.Add(make_pair(fNew,
                                make_pair(i - 1, j)));

                            // Update the details of this cell 
                            cellDetails[i - 1, j].f = fNew;
                            cellDetails[i - 1, j].g = gNew;
                            cellDetails[i - 1, j].h = hNew;
                            cellDetails[i - 1, j].parent_i = i;
                            cellDetails[i - 1, j].parent_j = j;
                        }
                    }
                }

            }

            // When the destination cell is not found and the open 
            // list is empty, then we conclude that we failed to 
            // reach the destiantion cell. This may happen when the 
            // there is no way to destination cell (due to blockages) 
            if (foundDest == false)
                Console.WriteLine("Failed to find the Destination Cell\n");

            return;
        }
    }
}

I am mostly confused about how to replicate this part in c#.

// Add this vertex to the closed list 
        i = p.second.first;
        j = p.second.second;

p is the following in C++

// Creating a shortcut for int, int pair type 
typedef pair<int, int> Pair;

// Creating a shortcut for pair<int, pair<int, int>> type 
typedef pair<double, pair<int, int>> pPair;

I know im close but this bit has be stumped.

I would suggest using ValueTuple . You can declare the type as

(double Cost, int X, int Y) 

or possibly

(double Cost, (int X, int Y) Position)

I have guessed the names, replace with whatever is appropriate. This greatly assists with readability since you can give the fields proper names instead of 'first' and 'second' (but you can still skipp names and use 'Item1', 'Item2' if you want). The downside is that there is no direct equivalent to typedef in c# so you will need to use the full typename in place of pPair

An alternative would be to declare a small struct with appropriate names for the fields.

Declare the list as

var openList = new List<(double Cost, int X, int Y)>();

Insert like

openList.Add((0, i, j))

Use like

    // Add this vertex to the closed list 
    closedList[p.X, p.Y] = true

I would discourage the use of double array, since it is much less clear what the values mean. It could also result in issues since doubles are real numbers, and this might not work right when indexing into an array.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM