private static void Play(ZhedBoard board) { while (!board.isOver) { board.PrintBoard(); Console.Write("Select tile (X, Y) / H for hint: "); string input = Console.ReadLine(); if (input.ToLower() == "h") { ShowHint(board); continue; } string[] coordsInput = input.Split(); int X, Y; if (coordsInput.Length != 2 || !int.TryParse(coordsInput[0], out X) || !int.TryParse(coordsInput[1], out Y)) { Console.WriteLine("Invalid input"); continue; } Console.Write("Select direction (U D L R): "); char dirInput = Console.ReadKey().KeyChar; Console.WriteLine(); switch(char.ToUpper(dirInput)) { case 'U': board = board.GoUp(new Coords(X, Y)); break; case 'D': board = board.GoDown(new Coords(X, Y)); break; case 'L': board = board.GoLeft(new Coords(X, Y)); break; case 'R': board = board.GoRight(new Coords(X, Y)); break; default: Console.WriteLine("Invalid direction."); break; } } Console.WriteLine("You win!"); board.PrintBoard(); }
private int Heuristic1(ZhedBoard board) { int minZhedDistance = int.MaxValue; foreach (int[] valueTile in board.GetValueTiles()) { foreach (int[] finishTile in board.GetFinishTiles()) { int zhedDistance; if (valueTile[0] == finishTile[0]) { zhedDistance = CalcZhedDistance(valueTile, finishTile, board, true); } else if (valueTile[1] == finishTile[1]) { zhedDistance = CalcZhedDistance(valueTile, finishTile, board, false); } else { continue; } //Console.WriteLine("Min zhed distance calculated: {0}", zhedDistance); if (zhedDistance < minZhedDistance) { minZhedDistance = zhedDistance; } } } return(minZhedDistance); }
public static ZhedBoard SpreadTile(ZhedBoard board, Coords coords, Func <Coords, Coords> moveFunction) { int tileValue = board.TileValue(coords); if (tileValue <= 0) { return(board); } ZhedBoard newBoard = new ZhedBoard(board); newBoard.SetTile(coords, USED_TILE); newBoard.boardValue += 2 * tileValue; newBoard.UpdateValueTiles(coords); while (tileValue > 0) { coords = moveFunction(coords); if (!newBoard.inbounds(coords)) { break; } switch (newBoard.TileValue(coords)) { case EMPTY_TILE: newBoard.SetTile(coords, USED_TILE); tileValue--; break; case FINISH_TILE: newBoard.SetTile(coords, WINNER_TILE); newBoard.isOver = true; break; default: break; } } return(newBoard); }
public static int Heuristic2(ZhedBoard board) { if (board.isOver) { return(0); } List <int[]> valueTiles = board.GetValueTiles(); List <int[]> finishTiles = board.GetFinishTiles(); int numAligned = 0; foreach (int[] finishTile in finishTiles) { foreach (int[] valueTile in valueTiles) { if (new Coords(valueTile[0], valueTile[1]).AlignedWith(new Coords(finishTile[0], finishTile[1]))) { numAligned++; } } } if (numAligned == 0) { return(9999); } int a = 1 / numAligned; //Console.WriteLine(a); return(a); }
/* Heuristic 1 * Minimum zhed Distance between a value tile and a finish tile. */ public static int Heuristic1(ZhedBoard board) { int minZhedDistance = int.MaxValue; foreach (int[] valueTile in board.GetValueTiles()) { foreach (int[] finishTile in board.GetFinishTiles()) { int zhedDistance; if (valueTile[0] == finishTile[0]) { zhedDistance = CalcZhedDistance(valueTile, finishTile, board, true); } else if (valueTile[1] == finishTile[1]) { zhedDistance = CalcZhedDistance(valueTile, finishTile, board, false); } else { continue; } if (zhedDistance < minZhedDistance) { minZhedDistance = zhedDistance; } } } return(minZhedDistance); }
/* Heuristic 4 * Similar to heuristic 3, but takes into account the average in all 4 directions on each tile */ public static int Heuristic4(ZhedBoard board) { if (board.isOver) { return(0); } return((int)(1000 / board.getBoardTotalValue())); }
/* Heuristic 3 * 1 / Sum of the number of tiles that can be covered with the current layout */ public static int Heuristic3(ZhedBoard board) { if (board.isOver) { return(0); } return(1000 / board.getBoardMaxValue()); }
public int Heuristic5(ZhedBoard board) { int a = Heuristic2(board); int b = Heuristic4(board); //Console.WriteLine(a + " " + b); return(a + b); }
private static void ShowHint(ZhedBoard board) { ZhedStep hint = new Solver(board).GetHint(); if (hint == null) Console.WriteLine("We couldn't solve this...\n"); else { Console.Write("Perhaps... "); hint.Print(); Console.WriteLine(); } }
public int Heuristic4(ZhedBoard board) { if (board.isOver) { return(0); } int a = (int)(1000 / board.getBoardTotalMaxValue()); //Console.WriteLine(a); return(a); }
public int Heuristic3(ZhedBoard board) { if (board.isOver) { return(0); } int a = 1000 / board.getBoardMaxValue(); //Console.WriteLine(a); return(a); }
public ZhedStep zhedStep; //Zhed Step that created this node public Node(ZhedBoard board, Node parent, ZhedStep zhedStep, int value) { this.board = board; this.parent = parent; this.zhedStep = zhedStep; this.value = value; this.height = 0; while (parent != null) { this.height += 1; parent = parent.parent; } }
/* Heuristic 1 auxiliary * Calculates number of used tiles between a value tile and finish tile */ private static int GetNumUsedTiles(int[] valueTile, int[] finishTile, ZhedBoard board, Boolean alignedVertically) { int numUsedTiles = 0; Func <Coords, Coords> moveFunction; if (alignedVertically) { if (valueTile[1] > finishTile[1]) { moveFunction = Coords.MoveUp; } else { moveFunction = Coords.MoveDown; } } else { if (valueTile[0] < finishTile[0]) { moveFunction = Coords.MoveRight; } else { moveFunction = Coords.MoveLeft; } } Coords coords = moveFunction(new Coords(valueTile[0], valueTile[1])); int tileValue = board.TileValue(coords); while (tileValue != ZhedBoard.FINISH_TILE) { if (tileValue == ZhedBoard.USED_TILE) { numUsedTiles++; // Console.WriteLine("Num used tiles: {0}", numUsedTiles); } coords = moveFunction(coords); tileValue = board.TileValue(coords); } // if (numUsedTiles != 0) //Console.WriteLine("Num used tiles: {0}", numUsedTiles); return(numUsedTiles); }
public ZhedBoard(ZhedBoard zhedBoard) { this.width = zhedBoard.width; this.height = zhedBoard.height; this.board = new List <List <int> >(); this.valueTilesCoords = new List <Coords>(zhedBoard.valueTilesCoords); this.valueTiles = new List <int[]>(zhedBoard.valueTiles); this.finishTiles = new List <int[]>(zhedBoard.finishTiles); this.boardValue = zhedBoard.boardValue; for (int i = 0; i < this.height; i++) { this.board.Add(new List <int>(zhedBoard.board[i])); } }
private List <Node> GetNextGeneration(Node parent, Func <ZhedBoard, int> heuristic) { List <Node> nextGeneration = new List <Node>(); List <Coords> valueTiles = parent.board.GetValueTilesCoords(); foreach (Coords coords in valueTiles) { ZhedBoard up = parent.board.GoUp(coords); ZhedBoard down = parent.board.GoDown(coords); ZhedBoard left = parent.board.GoLeft(coords); ZhedBoard right = parent.board.GoRight(coords); nextGeneration.Add(new Node(up, parent, new ZhedStep(Operations.MoveUp, coords), heuristic(up))); nextGeneration.Add(new Node(down, parent, new ZhedStep(Operations.MoveDown, coords), heuristic(down))); nextGeneration.Add(new Node(left, parent, new ZhedStep(Operations.MoveLeft, coords), heuristic(left))); nextGeneration.Add(new Node(right, parent, new ZhedStep(Operations.MoveRight, coords), heuristic(right))); } return(nextGeneration); }
public ZhedStep zhedStep; //Zhed Step that created this node public Node(ZhedBoard board, Node parent, ZhedStep zhedStep, int value, int cost) { this.board = board; this.parent = parent; this.zhedStep = zhedStep; this.value = value; if (parent == null) { this.cost = cost; } else { this.cost = parent.cost + cost; } while (parent != null) { this.height += 1; parent = parent.parent; } }
static void Main(string[] args) { ZhedBoard board = null; try { board = new ZhedBoard(Menu.LevelPickerMenu()); } catch { Console.WriteLine("Invalid board file!"); return; } Solver solver = new Solver(board); Menu.ShowMenu(); switch(Menu.GetOption()) { case SearchOption.Human: Play(board); break; case SearchOption.SolveDFS: ShowZhedSteps(solver, SearchMethod.DFS, Solver.Heuristic0); break; case SearchOption.SolveBFS: ShowZhedSteps(solver, SearchMethod.BFS, Solver.Heuristic0); break; case SearchOption.SolveGreedy: ShowZhedSteps(solver, SearchMethod.Greedy, GetHeuristic()); break; case SearchOption.SolveAstar: ShowZhedSteps(solver, SearchMethod.Astar, GetHeuristic()); break; case SearchOption.SolveUniform: ShowZhedSteps(solver, SearchMethod.Uniform, Solver.Heuristic0); break; } }
/* Heuristic 5 * Combines heuristic 3 and 4 */ public static int Heuristic5(ZhedBoard board) { return(Heuristic2(board) + Heuristic4(board)); }
/* Cost function * Simply assumes that expanding a tile is more beneficial than not expanding it */ private int Cost(ZhedBoard board, Coords coords) { return(-30); }
public int Heuristic0(ZhedBoard board) { return(1); }
public Solver(ZhedBoard board) { this.board = board; }
private int CalcZhedDistance(int [] valueTile, int[] finishTile, ZhedBoard board, Boolean alignedVertically) { int actualDistance = ((alignedVertically) ? Math.Abs(finishTile[1] - valueTile[1]) : Math.Abs(finishTile[0] - valueTile[0])); return(actualDistance - valueTile[2] - GetNumUsedTiles(valueTile, finishTile, alignedVertically)); }