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.