public static List <string> PlanB(State state, bool debug, Func <StateMetadata, bool> terminatingCondition) { string moves = "WASD"; var transpositionTable = new HashSet <Point>() { state.Position }; var priorityQueue = new PriorityQueue <StateMetadata>((rhs, lhs) => lhs.Depth == rhs.Depth ? CompareMetadata(lhs, rhs) : lhs.Depth < rhs.Depth); var initialState = new StateMetadata() { State = state }; priorityQueue.Push(initialState); while (!priorityQueue.IsEmpty()) { var currentMetadata = priorityQueue.Pop(); var currentBoard = currentMetadata.State.Board; var currentPosition = currentMetadata.State.Position; if (terminatingCondition(currentMetadata)) { return(currentMetadata.ToList().Select(i => i.Move).ToList()); } foreach (var move in moves) { var newState = currentMetadata.State.Move(move); if (newState != null) { var newMetadata = new StateMetadata() { State = newState.Item1, Depth = currentMetadata.Depth + 1, Move = move.ToString(), PreviousState = currentMetadata }; newMetadata.State.Board.Undo(newState.Item2); if (!transpositionTable.Contains(newState.Item1.Position)) { priorityQueue.Push(newMetadata); transpositionTable.Add(newMetadata.State.Position); } } } } return(null); }
private static bool CompareMetadata(StateMetadata lhs, StateMetadata rhs) { foreach (var metric in GetMetrics(lhs).Zip(GetMetrics(rhs), (l, r) => l - r)) { if (metric != 0) { return(metric < 0); } } return(false); }
public static List <string> PlanA(State state, bool debug) { var middle = new Point(state.Board.MaxX / 2, state.Board.MaxY / 2); string moves = "FWASDQE"; StateMetadata bestMove = null; var metadata = new StateMetadata() { State = state, Redo = new BoardUndo(), Debug = state.Board.Clone() }; var transpositionTable = new Dictionary <object, StateMetadata>() { { state.GetHashTuple(), metadata } }; var priorityQueue = new PriorityQueue <StateMetadata>((rhs, lhs) => lhs.Depth == rhs.Depth ? CompareMetadata(lhs, rhs) : lhs.Depth < rhs.Depth); priorityQueue.Push(metadata); while (!priorityQueue.IsEmpty()) { var currentMetadata = priorityQueue.Pop(); if (bestMove != null && bestMove.State.UnpaintedCount == 0 || currentMetadata.Depth >= MaxDepth) { if (bestMove.State.UnpaintedCount == state.UnpaintedCount) { return(null); } return(bestMove.ToList().Select(i => i.Move).ToList()); } var undoBase = currentMetadata.State.Board.Redo(currentMetadata.Redo); //currentMetadata.State.Board.Compare(currentMetadata.Debug); foreach (var move in moves.Where(m => currentMetadata.Depth == 0 || m != 'F' && m != 'L')) { var afterMove = currentMetadata.State.Move(move); if (afterMove != null) { var newState = afterMove.Item1; var undoMove = afterMove.Item2; var newPoints = undoMove == null ? 0 : undoMove.Points.Sum(p => 1 + GetWallCount(state.Board, p.Item1)); var newMetadata = new StateMetadata() { Score = currentMetadata.Score + newPoints, State = newState, Depth = currentMetadata.Depth + 1, Move = move.ToString(), PreviousState = currentMetadata }; var isBetterMove = bestMove == null || CompareMetadata(newMetadata, bestMove); if (isBetterMove) { bestMove = newMetadata; } if (debug) { var betterMoveString = isBetterMove ? " *" : ""; if (isBetterMove) { Console.WriteLine($"{newMetadata}{betterMoveString}"); } } if (!transpositionTable.ContainsKey(newState.GetHashTuple())) { //newMetadata.Debug = state.Board.Clone(); newMetadata.Redo = new BoardUndo(); newMetadata.Redo.Points.AddRange(currentMetadata.Redo.Points); newMetadata.Redo.Points.AddRange(state.Board.GetRedo(undoMove).Points); priorityQueue.Push(newMetadata); transpositionTable[newMetadata.State] = null; } currentMetadata.State.Board.Undo(undoMove); } } currentMetadata.State.Board.Undo(undoBase); } throw new Exception("No moves found"); }
// Heuristics: // Maximize boosts collected. // Maximize score unpainted squares. // private static IEnumerable <int> GetMetrics(StateMetadata metadata) { yield return(-metadata.State.BoostsCollected); yield return(-metadata.Score); }