A* pathfinding algorithm INFINITE WHILE LOOP (c#)(unity) - c#

I'm trying to come up with my "own" a* pathfinding algorithm following the explanation of this article : https://www.redblobgames.com/pathfinding/a-star/introduction.html
But it seems that my pathfinding code runs into some sort of infinte-while-loop which inmediatly crashes Unity. But I honestly do not know what am I doing wrong
Here's my code
EDIT : it seems that unity editor crashes due to an OutOfMemory exception. I do not know what is going on
public class PathFinding {
List<PathNode> openList;
List<PathNode> closedList;
Grid_Ian<PathNode> grid;
public PathFinding(Grid_Ian<PathNode> grid)
{
openList = new List<PathNode>();
closedList = new List<PathNode>();
this.grid = grid;
}
public List<PathNode> makePath(PathNode startNode, PathNode endNode)
{
if (startNode == null || endNode == null)
{
return new List<PathNode>();
}
if(grid.getGridObject(startNode.x,startNode.y) == null
|| grid.getGridObject(endNode.x, endNode.y) == null)
{
return new List<PathNode>();
}
startNode.hCost = calculateDistanceCost(startNode, endNode);
startNode.gCost = 0;
startNode.calculateFCost();
startNode.cameFrom = null;
openList.Add(startNode);
PathNode currentNode = startNode;
while (openList.Count > 0)
{
Debug.Log("LOOPING");
currentNode = getLowestFcost(openList);
openList.Remove(currentNode);
closedList.Add(currentNode);
if (currentNode.x == endNode.x &&
currentNode.y == endNode.y)
{
return getPath(currentNode);
}
foreach (PathNode next in getNeighbors(currentNode))
{
int newCost = currentNode.fCost + calculateDistanceCost(currentNode, next);
if (closedList.Contains(next)) continue;
if (next.cameFrom == null || newCost < next.fCost)
{
Debug.Log("NUEVO VECINO");
int nextCost = calculateDistanceCost(currentNode, next);
next.gCost = currentNode.gCost + nextCost;
next.hCost = currentNode.hCost + nextCost;
next.calculateFCost();
next.cameFrom = currentNode;
openList.Add(next);
}
}
}
return new List<PathNode>();
}
public List<PathNode> getNeighbors(PathNode currentNode)
{
List<PathNode> neighborNodes = new List<PathNode>();
if (currentNode.x - 1 >= 0)
{
//left
neighborNodes.Add(getNode(currentNode.x - 1, currentNode.y));
}
if (currentNode.x + 1 >= 0)
{
//right
neighborNodes.Add(getNode(currentNode.x + 1, currentNode.y));
}
//up
if (currentNode.y + 1 >= 0)
{
neighborNodes.Add(getNode(currentNode.x, currentNode.y + 1));
}
//down
if (currentNode.y - 1 >= 0)
{
neighborNodes.Add(getNode(currentNode.x, currentNode.y - 1));
}
return neighborNodes;
}
public PathNode getNode(int x, int y)
{
if(grid.getGridObject(x,y) == null)
{
}
return grid.getGridObject(x, y);
}
private PathNode getLowestFcost(List<PathNode> nodeList)
{
PathNode lowestNode = getNode(0,0); // TODO : ARREGLAR
int fCost = 0;
foreach (PathNode node in nodeList)
{
if (fCost > node.fCost)
{
fCost = node.fCost;
lowestNode = node;
}
}
return lowestNode;
}
private int calculateDistanceCost(PathNode a, PathNode b)
{
return Mathf.Abs(a.x - b.x) + Mathf.Abs(a.y - b.y);
}
private List<PathNode> getPath(PathNode currentNode ){
List<PathNode> path = new List<PathNode>();
path.Add(currentNode);
while (currentNode.cameFrom != null)
{
currentNode = currentNode.cameFrom;
path.Add(currentNode);
}
path.Reverse();
return path;
}
public void getXY(Vector3 worldPosition, out int x, out int y)
{
grid.GetXY(worldPosition, out x, out y);
}
}
public class PathNode {
public int x, y;
public int hCost, gCost,fCost;
public PathNode cameFrom;
// G = start
// H = end
// F = G + H
public PathNode(int x,int y)
{
this.x = x;
this.y = y;
}
public void calculateFCost()
{
fCost = hCost + gCost;
}
}

I tried to check your Code with my and 2 Ideas you could try.
First is I think you shouldn't set the in the foreach the newCost before the if. So you could try:
foreach (PathNode next in getNeighbors(currentNode))
{
if (closedList.Contains(next)) continue;
int newCost = currentNode.fCost + calculateDistanceCost(currentNode, next);
if (next.cameFrom == null || newCost < next.fCost)
{
Debug.Log("NUEVO VECINO");
int nextCost = calculateDistanceCost(currentNode, next);
next.gCost = currentNode.gCost + nextCost;
next.hCost = currentNode.hCost + nextCost;
next.calculateFCost();
next.cameFrom = currentNode;
openList.Add(next);
}
}
Or one more thing. I have for some Reasons again a openList.Contains check before I add it to the openList. I do not know why again I did this but I think maybe you can try it, don't know if this helps. I made it quite a long time ago:
foreach (PathNode next in getNeighbors(currentNode))
{
int newCost = currentNode.fCost + calculateDistanceCost(currentNode, next);
if (closedList.Contains(next)) continue;
if (next.cameFrom == null || newCost < next.fCost)
{
Debug.Log("NUEVO VECINO");
int nextCost = calculateDistanceCost(currentNode, next);
next.gCost = currentNode.gCost + nextCost;
next.hCost = currentNode.hCost + nextCost;
next.calculateFCost();
next.cameFrom = currentNode;
if(!openList.Contains(next))
{
openList.Add(next);
}
}
}

I found two more things.
First your getNode function shouldn't look like this:
public PathNode getNode(int x, int y)
{
if(grid.getGridObject(x,y) == null)
{
}
return grid.getGridObject(x, y);
}
It should be:
public PathNode getNode(int x, int y)
{
if(grid.getGridObject(x,y) != null)
{
return grid.getGridObject(x, y);
}
return null; //need error handling
}
And the Second thing is for your getNeighbors. I do not know exactly how you create the Nodes, but for example they are in a Grid you should check if there is something for X and Y and not OutOfIndex.
Here my check out of my Code for one NeighborNode:
if (checkX >= 0 && checkX < gridSizeX)
{
if (checkY >= 0 && checkY < gridSizeY)
{
neighborList.Add(nodeArray[checkX, checkY]);
}
}
Because of getNode function you add to the openList NULL

Related

Wave Function Collapse in Unity using BFS

I have been trying to implement the Wave Function Collapse(link) Algorithm in Unity using Best first search.
For this I use various helper classes,namely:
Wave_Tiles.cs
using UnityEngine;
using UnityEngine.Tilemaps;
using System.Collections.Generic;
[CreateAssetMenu(menuName = "2D/Tiles/WaveFunctionTiles")]
public class Wave_Tiles : ScriptableObject
{
public bool ongroundtilemap;
public TileBase tiletoinstantiate;
public List<Wave_Tiles> up;
public List<Wave_Tiles> down;
public List<Wave_Tiles> left;
public List<Wave_Tiles> right;
}
This class stores the information for the tiles to use.The tiletoinstantiate is the actual tile that is to be put in the place and its valid neighbours are storedd in the respective lists.
Node.cs
using UnityEngine;
using UnityEngine.Tilemaps;
using System.Collections.Generic;
[System.Serializable]
public class Nodes
{
public bool iscollapsed;
public Vector3Int position;
public List<TileBase> ValidTiles;
public Nodes(Vector3Int pos)
{
position = pos;
ValidTiles = new List<TileBase>();
}
public Nodes(int x, int y)
{
position = new Vector3Int(x, y, 0);
ValidTiles = new List<TileBase>();
}
public TileBase coll(Tilemap ground)
{
if (iscollapsed)
return null;
iscollapsed = true;
TileBase tmp = null;
if (ValidTiles.Count > 0)
{
int rand = Random.Range(0, ValidTiles.Count);
ground.SetTile(position, ValidTiles[rand]);
tmp = ValidTiles[rand];
}
return tmp;
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
if (obj is Nodes)
return Equals(obj as Nodes);
return false;
}
public override int GetHashCode()
{
return position.x ^ position.y;
}
public bool Equals(Nodes obj)
{
if (obj == null)
{
return false;
}
return (position.x == obj.position.x) && (position.y == obj.position.y);
}
}
This class is used to traverse the grid and stores the valid tiles for the position.The collapse function collapses on a random tile from the ValidTile List.
Wave_Func.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
using System.Linq;
public class Wave_Func : MonoBehaviour
{
public bool working;
public float wait_time;
public Tilemap Grid;
public Vector2Int LimitsMin, LimitsMax;
public Nodes startNode;
WaitForSeconds wait;
public List<Wave_Tiles> Game_Tiles;
public List<Nodes> Openlist, ClosedList, openneighbour, closedneighbour;
private void Start()
{
StartCoroutine(wavefunccoll());
}
public IEnumerator wavefunccoll()
{
working = true;
wait = new WaitForSeconds(wait_time);
Openlist.Add(startNode);
yield return wait;
while (Openlist.Count > 0)
{
Nodes current = Openlist[0];
Openlist.Remove(current);
ClosedList.Add(current);
yield return wait;
yield return StartCoroutine(collapse(current));
Openlist = Openlist.OrderBy(a => a.ValidTiles.Count).ToList();
}
working = false;
}
IEnumerator collapse(Nodes current)
{
closedneighbour.Clear();
yield return null;
TileBase parenttofind = current.coll(Grid);
Wave_Tiles parent = null;
foreach (Wave_Tiles wtf in Game_Tiles)
if (wtf.tiletoinstantiate == parenttofind)
{
parent = wtf;
break;
}
if (parent != null)
foreach (Nodes neighbour in getneighbours(current, parent))
{
if (openneighbour.Contains(neighbour))
openneighbour.RemoveAll(item => item == neighbour);
openneighbour.Add(neighbour);
}
yield return null;
while (openneighbour.Count > 0)
{
current = openneighbour[0];
openneighbour.Remove(current);
closedneighbour.Add(current);
foreach (Wave_Tiles wtf in Game_Tiles)
if (wtf.tiletoinstantiate == parenttofind)
{
parent = wtf;
break;
}
yield return null;
foreach (Nodes neighbour in getneighbours(current))
{
if (openneighbour.Contains(neighbour))
openneighbour.RemoveAll(item => item == neighbour);
openneighbour.Add(neighbour);
}
}
foreach (Nodes neighbour in closedneighbour)
{
yield return null;
if (Openlist.Contains(neighbour))
Openlist.RemoveAll(item => item == neighbour);
Openlist.Add(neighbour);
}
}
List<Nodes> getneighbours(Nodes current, Wave_Tiles parent)
{
List<Nodes> neighbours = new List<Nodes>();
Vector3Int curpos;
for (int i = -1; i < 2; i++)
{
for (int j = -1; j < 2; j++)
{
if ((i == 0 && j == 0) || (Mathf.Abs(i) + Mathf.Abs(j) == 2))
continue;
curpos = current.position + new Vector3Int(i, j);
if (curpos.x >= LimitsMax.x || curpos.x < LimitsMin.x || curpos.y >= LimitsMax.y || curpos.y < LimitsMin.y)
continue;
Nodes neighbour = new Nodes(curpos);
if (ClosedList.Contains(neighbour))
continue;
if (Openlist.Contains(neighbour))
neighbour = Openlist[Openlist.IndexOf(neighbour)];
List<TileBase> inter = null;
if (i == 1 && j == 0)
{
if (parent.right == null)
continue;
if (neighbour.ValidTiles.Count < 1)
{
foreach (Wave_Tiles wtf in parent.right)
neighbour.ValidTiles.Add(wtf.tiletoinstantiate);
}
else
{
inter = new List<TileBase>();
foreach (Wave_Tiles wtf in parent.right)
if (neighbour.ValidTiles.Contains(wtf.tiletoinstantiate))
inter.Add(wtf.tiletoinstantiate);
}
}
if (i == -1 && j == 0)
{
if (parent.left == null)
continue;
if (neighbour.ValidTiles.Count < 1)
{
foreach (Wave_Tiles wtf in parent.left)
neighbour.ValidTiles.Add(wtf.tiletoinstantiate);
}
else
{
inter = new List<TileBase>();
foreach (Wave_Tiles wtf in parent.left)
if (neighbour.ValidTiles.Contains(wtf.tiletoinstantiate))
inter.Add(wtf.tiletoinstantiate);
}
}
if (i == 0 && j == -1)
{
if (parent.down == null)
continue;
if (neighbour.ValidTiles.Count < 1)
{
foreach (Wave_Tiles wtf in parent.down)
neighbour.ValidTiles.Add(wtf.tiletoinstantiate);
}
else
{
inter = new List<TileBase>();
foreach (Wave_Tiles wtf in parent.down)
if (neighbour.ValidTiles.Contains(wtf.tiletoinstantiate))
inter.Add(wtf.tiletoinstantiate);
}
}
if (i == 0 && j == 1)
{
if (parent.up == null)
continue;
if (neighbour.ValidTiles.Count < 1)
{
foreach (Wave_Tiles wtf in parent.up)
neighbour.ValidTiles.Add(wtf.tiletoinstantiate);
}
else
{
inter = new List<TileBase>();
foreach (Wave_Tiles wtf in parent.up)
if (neighbour.ValidTiles.Contains(wtf.tiletoinstantiate))
inter.Add(wtf.tiletoinstantiate);
}
}
if (inter != null)
neighbour.ValidTiles = inter;
neighbours.Add(neighbour);
}
}
return neighbours;
}
List<Nodes> getneighbours(Nodes current)
{
List<Nodes> neighbours = new List<Nodes>();
Vector3Int curpos;
for (int i = -1; i < 2; i++)
{
for (int j = -1; j < 2; j++)
{
if ((i == 0 && j == 0) || (Mathf.Abs(i) + Mathf.Abs(j) == 2))
continue;
curpos = current.position + new Vector3Int(i, j);
if (curpos.x >= LimitsMax.x || curpos.x < LimitsMin.x || curpos.y >= LimitsMax.y || curpos.y < LimitsMin.y)
continue;
Nodes neighbour = new Nodes(curpos);
if (ClosedList.Contains(neighbour) || closedneighbour.Contains(neighbour) || Openlist.Contains(neighbour))
continue;
if (openneighbour.Contains(neighbour))
neighbour = openneighbour[openneighbour.IndexOf(neighbour)];
neighbours.Add(neighbour);
}
}
return neighbours;
}
}
This class implements the main logic of the algorithm. So the startnode is populated with all the tiles from Game_Tiles and is added to the Openlist which runs a Best first Search and collapses the tile that has the least Count of ValidTiles. The collapse Function randomly choses a tile and "Collapses" the current tile after which it finds the rules for this tile and populates its neighbours' validlist and adds it to the openneighbour.
So my question is that Can I achieve the Wave function collapse using the above mentioned technique?
If so could you please point out the problems with this script/technique and some ways to fix it.
Thanks in advance.

Quick Sort using C#

Hello I trying to do a QuickSort but didn't appear the result, For example the user input "cdabe" so the expected result is "abcde". May I know what is the cause why the result didn't display?
because There is no error in the code. I'm using MVC. My MergeSort is working properly but my QuickSort didn't.
Model :
public string QuickSort()
{
string arrangedSort = "";
string Word= "cdabe";
List<string> ListLetters = new List<string>();
for (int i = 0; i < Word.Length; i++)
{
ListLetters.Add(Word.Substring(i, 1));
}
aQuicksort(Word, 0, ListLetters.Count - 1);
void aQuicksort(string Word, int left, int right)
{
int i = left;
int j = right;
var pivot = Word[(left + right) / 2];
while (i <= j)
{
while (char.Parse(ListLetters[i]) < pivot)
i++;
while (char.Parse(ListLetters[i]) > pivot)
j--;
if (i <= j)
{
var tmp = ListLetters[i];
ListLetters[i] = ListLetters[j];
ListLetters[j] = tmp;
i++;
j--;
}
}
if (left < j)
aQuicksort(Word, left, j);
if (i < right)
aQuicksort(Word, i, right);
foreach (var listLetter in ListLetters)
{
arrangedSort += listLetter;
}
}
return arrangedSort;
}
Try this implementation, it uses LinQ using System.linq
public static IEnumerable<int> QSort3(IEnumerable<int> source)
{
if (!source.Any())
return source;
int first = source.First();
QSort3Helper myHelper =
source.GroupBy(i => i.CompareTo(first))
.Aggregate(new QSort3Helper(), (a, g) =>
{
if (g.Key == 0)
a.Same = g;
else if (g.Key == -1)
a.Less = g;
else if (g.Key == 1)
a.More = g;
return a;
});
IEnumerable<int> myResult = Enumerable.Empty<int>();
if (myHelper.Less != null)
myResult = myResult.Concat(QSort3(myHelper.Less));
if (myHelper.Same != null)
myResult = myResult.Concat(myHelper.Same);
if (myHelper.More != null)
myResult = myResult.Concat(QSort3(myHelper.More));
return myResult;
}
public class QSort3Helper
{
public IEnumerable<int> Less;
public IEnumerable<int> Same;
public IEnumerable<int> More;
}
code from this post

MiniMax Algorithm with Chess in C# not working properly

I've been trying to implement minimax algorithm in my C# chess engine for a week now and it makes legal moves but not meaningful moves. I cannot find the error, hopefully someone can spot it. I have tried to isolate the problem by testing each method and they all seem to work correctly except minimax.
public enum Piece
{
Empty, Pawn_W, Pawn_B, Knight_W, Knight_B,
Bishop_W, Bishop_B, Rook_W, Rook_B,
Queen_W, Queen_B, King_W, King_B
}
public bool IsPieceWhite(Piece piece)
{
if (piece == Piece.Pawn_W || piece == Piece.Knight_W ||
piece == Piece.Bishop_W || piece == Piece.Rook_W ||
piece == Piece.Queen_W || piece == Piece.King_W)
return true;
else return false;
}
public bool IsPieceBlack(Piece piece)
{
if (piece == Piece.Pawn_B || piece == Piece.Knight_B ||
piece == Piece.Bishop_B || piece == Piece.Rook_B ||
piece == Piece.Queen_B || piece == Piece.King_B)
return true;
else return false;
}
public int GetPieceWorth(Piece piece)
{
if (piece == Piece.Pawn_W || piece == Piece.Pawn_B)
return 1;
if (piece == Piece.Knight_W || piece == Piece.Knight_B)
return 3;
if (piece == Piece.Bishop_W || piece == Piece.Bishop_B)
return 3;
if (piece == Piece.Rook_W || piece == Piece.Rook_B)
return 5;
if (piece == Piece.Queen_W || piece == Piece.Queen_B)
return 9;
if (piece == Piece.King_W || piece == Piece.King_B)
return 9999999;
return 0;
}
Piece[,] CurrentBoard = GetStartingBoard();
Piece[,] bestMove;
public int depthB = 3;
public double minimax(Piece[,] board, int depth, bool maximizingPlayer)
{
if (depth == 0)
{
double result = EvaluatePosition(board, maximizingPlayer);
return result;
}
if (maximizingPlayer)
{
double best = Double.MinValue;
double value = Double.MinValue;
foreach (var move in GenerateMoves(board, maximizingPlayer))
{
Piece[,] clonedMove = CloneBoard(move);
value = Math.Max(value, minimax(clonedMove, depth - 1, false));
if (depth == depthB && value >= best)
{
best = value;
bestMove = clonedMove;
}
}
return value;
}
else
{
double best = Double.MaxValue;
double value = Double.MaxValue;
foreach (var move in GenerateMoves(board, maximizingPlayer))
{
Piece[,] clonedMove = CloneBoard(move);
value = Math.Min(value, minimax(clonedMove, depth - 1, true));
if (depth == depthB && value <= best)
{
best = value;
bestMove = clonedMove;
}
}
return value;
}
}
public Piece[,] CloneBoard(Piece[,] boardPos)
{
Piece[,] copy = boardPos.Clone() as Piece[,];
return copy;
}
public double EvaluatePosition(Piece[,] boardPos, bool ForWhite)
{
double eval = 0;
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
if (boardPos[i, j] != Piece.Empty)
{
if (IsPieceWhite(boardPos[i, j]))
{
eval += GetPieceWorth(boardPos[i, j]);
}
else if (IsPieceBlack(boardPos[i, j]))
{
eval -= GetPieceWorth(boardPos[i, j]);
}
}
}
}
if (ForWhite)
return eval;
else
return eval * -1;
}
//a-h,0-7
//Piece[,] board = new Piece[8, 8];
public static Piece[,] GetStartingBoard()
{
Piece[,] board = new Piece[8, 8];
for (int i = 0; i < 8; i++)
{
//initiate pawns
board[1, i] = Piece.Pawn_W;
board[6, i] = Piece.Pawn_B;
}
//white pieces
board[0, 0] = Piece.Rook_W;
board[0, 1] = Piece.Knight_W;
board[0, 2] = Piece.Bishop_W;
board[0, 3] = Piece.Queen_W;
board[0, 4] = Piece.King_W;
board[0, 5] = Piece.Bishop_W;
board[0, 6] = Piece.Knight_W;
board[0, 7] = Piece.Rook_W;
//black pieces
board[7, 0] = Piece.Rook_B;
board[7, 1] = Piece.Knight_B;
board[7, 2] = Piece.Bishop_B;
board[7, 3] = Piece.Queen_B;
board[7, 4] = Piece.King_B;
board[7, 5] = Piece.Bishop_B;
board[7, 6] = Piece.Knight_B;
board[7, 7] = Piece.Rook_B;
//test
//board[1, 4] = Piece.Pawn_B;
//board[6, 2] = Piece.Pawn_W;
return board;
}
I have uploaded a short clip of the engine playing against itself, to show the wierd moves: https://www.youtube.com/watch?v=A0HVgXYSciY
Finally was able to make the minimax function work. Thanks for all the help!
Working method:
public int minimax(Piece[,] board, int depth, bool maximizingPlayer, bool WhiteToPlay)
{
if (depth == 0)
{
int result = EvaluatePosition(board, WhiteToPlay);
return result;
}
var moves = GenerateMoves(board, WhiteToPlay);
if (maximizingPlayer)
{
int value = int.MinValue;
foreach (var move in moves)
{
int minmaxResult = minimax(move, depth - 1, false, !WhiteToPlay);
value = Math.Max(value, minmaxResult);
if (depth == depthB)
{
moveScores.Add(move, minmaxResult);
}
}
return value;
}
else
{
int value = int.MaxValue;
foreach (var move in moves)
{
int minmaxResult = minimax(move, depth - 1, true, !WhiteToPlay);
value = Math.Min(value, minmaxResult);
if (depth == depthB)
{
moveScores.Add(move, minmaxResult);
}
}
return value;
}
}

Adding algebraic X notation

I am trying for the last few hours on how to parse a string with algebric notation.
For example if I have the input:
X+8X-21X+21X+16
The output should be:
9X+16
so far if I tried to see if there exists a number behind X and tried many cases, however I keep on getting an index out of bounds error, and rightufully so. Any suggestions on how to fix it?
int getXPosition= LHSString.IndexOf("X");
int noOfXs = LHSString.Split('X').Length - 1;
int XCount = 0;
if (getXPosition > -1)
{
while (XCount <= noOfXs)
{
int posX = getPositionX(s);
Regex noBeforeX = new Regex(#"\d+");
if ((posX - 1) > -1 && noBeforeX.IsMatch(LHSString.Substring(posX-1,1)))
{
string getNumber = LHSString.Substring(posX-1, 1);
sum += Convert.ToInt32(getNumber);
}
if ((posX - 2) > -1 && noBeforeX.IsMatch(LHSString.Substring(posX - 2, 1)))
{
string gotNumber = LHSString.Substring(posX - 1, 1);
int Number=Convert.ToInt32(gotNumber);
sum += Number;
}
XCount++;
s = s.Substring(posX + 1);
}
}
I would use a more maintainable approach. separate different code parts and use collection of class that will represent the "part" in the algebraic equation.
here is my suggestion:
class Program
{
static void Main(string[] args)
{
string[] operators = { "+", "-", "/", "*" };
string test = "X+8X-21X+21X+16";
int locationcounter = 0;
string part = string.Empty;
List<Part> partsList = new List<Part>();
for (int i = 0; i < test.Length; i++)
{
if (operators.Contains(test[i].ToString()))
{
var operatorbeofore = (partsList.Count <= 0 ? "" : partsList[partsList.Count - 1].OperatorAfter);
partsList.Add(new Part(part, operatorbeofore, test[i].ToString(), locationcounter));
locationcounter++;
part = string.Empty;
}
else
{
part += test[i].ToString();
}
}
// last part that remain
if (part != string.Empty)
{
partsList.Add(new Part(part, partsList[partsList.Count() - 1].OperatorAfter, "", locationcounter++));
}
// output
Console.WriteLine(GetResultOutput(partsList));
Console.ReadLine();
}
private static string GetResultOutput(List<Part> algebraicexpression)
{
// reduce all vars
var vars = algebraicexpression.Where(x => x.IsVar).OrderBy(x => x.locationInEqution).ToList();
int lastVarResult = 0;
int varResult = 0;
if (vars.Count() > 1)
{
lastVarResult = GetCalculation(vars[0].Value, vars[1].Value, vars[1].OperatorBefore);
for (int i = 2; i < vars.Count(); i++)
{
varResult = GetCalculation(lastVarResult, vars[i].Value, vars[i].OperatorBefore);
lastVarResult = varResult;
}
}
else if (vars.Count() == 1)
{
lastVarResult = vars[0].Value;
}
// calculate all "free" numbers
var numbers = algebraicexpression.Where(x => x.IsVar == false).OrderBy(x => x.locationInEqution).ToList();
int lastResult = 0;
int Result = 0;
if (numbers.Count() > 1)
{
lastResult = GetCalculation(vars[0].Value, vars[1].Value, vars[1].OperatorBefore);
for (int i = 2; i < vars.Count(); i++)
{
Result = GetCalculation(lastResult, vars[i].Value, vars[i].OperatorBefore);
lastResult = varResult;
}
}
else if (numbers.Count() == 1)
{
Result = numbers[0].Value;
}
string stringresult = string.Empty;
if (varResult != 0)
{
stringresult = varResult.ToString() + vars[0].Notation;
}
if (Result > 0)
{
stringresult = stringresult + "+" + Result.ToString();
}
else if (Result < 0)
{
stringresult = stringresult + "-" + Result.ToString();
}
return stringresult;
}
private static int GetCalculation(int x, int y, string eqoperator)
{
if (eqoperator == "+")
{
return x + y;
}
else if (eqoperator == "-")
{
return x - y;
}
else if (eqoperator == "*")
{
return x * y;
}
else if (eqoperator == "/")
{
return x / y;
}
else
{
return 0;
}
}
}
class Part
{
public string MyAlgebricPart;
public string OperatorBefore;
public string OperatorAfter;
public int locationInEqution;
public Part(string part, string operatorbefore, string operatorafter, int location)
{
this.MyAlgebricPart = part;
this.OperatorAfter = operatorafter;
this.OperatorBefore = operatorbefore;
this.locationInEqution = location;
}
public int Value
{
get
{
if (MyAlgebricPart.Count() == 1 && Notation != string.Empty)
{
return 1;
}
else
{
string result = new String(MyAlgebricPart.Where(Char.IsDigit).ToArray());
return Convert.ToInt32(result);
}
}
}
public string Notation
{
get
{
var onlyLetters = new String(MyAlgebricPart.Where(Char.IsLetter).ToArray());
if (onlyLetters != "")
{
return onlyLetters[0].ToString();
}
else
{
return string.Empty;
}
}
}
public bool IsVar
{
get
{
if (Notation == string.Empty)
return false;
else
return true;
}
}
}

converting from breadth first search to depth first limited search

as all newbies to the searching algorithms, i am working on an example of the old fashion 8-problem puzzle, i have done the breadth first algorithm which is in the code below, and i was wondering how can convert it to the depth first limited search.
how can I convert from the breadth first algorithm to the depth first limited search algorithm??
code :
class BFS
{
int[] GoalState = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
private Queue<Node> Frontier;
private HashSet<Node> Solution;
private Node RootNode;
public BFS(int[] StartState)
{
this.RootNode = new Node(StartState, -1, "\0");
Solution = new HashSet<Node>();
Frontier = new Queue<Node>();
}
public void Solve()
{
Node ActiveNode = RootNode;
bool IsSolved = false;
while (!IsGoalState(ActiveNode.GetState()))
{
Solution.Add(ActiveNode);
foreach (Node successor in GenerateSuccessor(ActiveNode))
{
Frontier.Enqueue(successor);
if (IsGoalState(successor.GetState()))
{
IsSolved = true;
Solution.Add(successor);
break;
}
}
if (IsSolved)
break;
ActiveNode = Frontier.Dequeue();
}
WriteSolution();
}
public IEnumerable<Node> GenerateSuccessor(Node ParentNode)
{
int[] ParentState = ParentNode.GetState();
int EmptySpacePosition = 0;
int temp;
for (int x = 0; x < 9; x++)
{
if (ParentState[x] == 0)
{
EmptySpacePosition = x;
break;
}
}
//Can move empty space to LEFT?
if (EmptySpacePosition != 0 && EmptySpacePosition != 3 && EmptySpacePosition != 6)
{
int[] _State = (int[])ParentState.Clone();
_State[EmptySpacePosition] = _State[EmptySpacePosition - 1];
_State[EmptySpacePosition - 1] = 0;
yield return new Node(_State, ParentNode.GetId(), "Left ");
}
//Can move empty space to RIGHT?
if (EmptySpacePosition != 2 && EmptySpacePosition != 5 && EmptySpacePosition != 8)
{
int[] _State = (int[])ParentState.Clone();
_State[EmptySpacePosition] = _State[EmptySpacePosition + 1];
_State[EmptySpacePosition + 1] = 0;
yield return new Node(_State, ParentNode.GetId(),"Right ");
}
//Can move empty space to UP?
if (EmptySpacePosition > 2)
{
int[] _State = (int[])ParentState.Clone();
_State[EmptySpacePosition] = _State[EmptySpacePosition - 3];
_State[EmptySpacePosition - 3] = 0;
yield return new Node(_State, ParentNode.GetId(), "Up ");
}
//Can move empty space to DOWN?
if (EmptySpacePosition < 6)
{
int[] _State = (int[])ParentState.Clone();
_State[EmptySpacePosition] = _State[EmptySpacePosition + 3];
_State[EmptySpacePosition + 3] = 0;
yield return new Node(_State, ParentNode.GetId(),"Down ");
}
}
public bool IsGoalState(int[] State)
{
for (int x = 0; x < 9; x++)
{
if (State[x] != GoalState[x])
return false;
}
return true;
}
public void WriteSolution()
{
StringBuilder s = new StringBuilder();
int ParentId = 0;
#region InfoPrint
Console.Write("Puzzle= ");
foreach (int i in RootNode.GetState())
{
Console.Write(i);
}
Console.WriteLine();
Console.WriteLine("Nodes Generated= " + (Solution.Count + Frontier.Count));
#endregion
foreach (Node n in Solution.Reverse())
{
if (ParentId == 0 || n.GetId() == ParentId)
{
s.Append(n.GetMove());
ParentId = n.GetParentId();
}
}
Console.WriteLine("Solution Length= " + (s.Length - 1));
Console.WriteLine("Solution= " + s.ToString());
}
}
and here is my class node
class Node
{
static int _IdCnt = 0;
private int[] State;
private int Id;
private int ParentId;
private string Move;
public Node(int[] State, int ParentId, string Move)
{
Id = _IdCnt++;
this.State = State;
this.ParentId = ParentId;
this.Move = Move;
}
public void SetState(int[] State)
{
this.State = State;
}
public int[] GetState()
{
return (int[])State.Clone();
}
public int GetId()
{
return Id;
}
public int GetParentId()
{
return ParentId;
}
public string GetMove()
{
return Move;
}
}
In the DFS, you'll need to use stack instead of queue. Basically, you add the root node to a stack, and while stack contains a node, you pop the node, do your logic, add its neighbors to the stack and continue.
1. Add root to a stack.
2. while(stack.Count > 0)
{
3. pop the stack
4. if matches, return
5. else add neighbors to stack
}
return not found

Categories

Resources