// Holds the move for negamax public CalculatedMove(float value, Position moveFrom, MoveSet moveset) { // Automatically does the negating Value = -value; MoveFrom = moveFrom; Moveset = moveset; }
public MoveSet(MoveSet moveset) { _moves = new List <Position>(); if (moveset.NumberOfStages() > 0) { foreach (Position p in moveset.Moves) { _moves.Add(p); } } }
// Non recursive checking the 4 moves around the piece public override List <MoveSet> GetNonTakeMoves(Board board) { List <MoveSet> Moves = new List <MoveSet>(); // Adds backwards non take moves Position LB = this.CurrentPosition.GetLeftBack(IsWhite); Position RB = this.CurrentPosition.GetRightBack(IsWhite); Position LF = this.CurrentPosition.GetLeftForward(IsWhite); Position RF = this.CurrentPosition.GetRightForward(IsWhite); if (LF.InBoard()) { if (board.GetPiece(LF) == null) { MoveSet moveset = new MoveSet(LF); Moves.Add(moveset); } } if (RF.InBoard()) { if (board.GetPiece(RF) == null) { MoveSet moveset = new MoveSet(RF); Moves.Add(moveset); } } if (LB.InBoard()) { if (board.GetPiece(LB) == null) { MoveSet moveset = new MoveSet(LB); Moves.Add(moveset); } } if (RB.InBoard()) { if (board.GetPiece(RB) == null) { MoveSet moveset = new MoveSet(RB); Moves.Add(moveset); } } return(Moves); }
// Searches Depth moves ahead in the game and finds the best move private CalculatedMove NegaMax(int Depth, int PlayerColour, float alpha, float beta, Board board, BackgroundWorker worker) { // Setup float BestValue = float.MinValue; bool FoundTakeMove = false; bool AppliedTakeMove = false; List <MoveSet> possibleMovesets; List <Position> usablepieces = new List <Position>(); if (PlayerColour == 1) { usablepieces = board.GetWhitePositions(); } else { usablepieces = board.GetBlackPositions(); } //Show the tree (to the console) if (Debug && Depth > 0) { Console.WriteLine(); for (int p = 0; p < (DepthOfSearch - Depth); p++) { Console.Write("\t"); } if ((DepthOfSearch % 2 == Depth % 2 && IsWhite) || (DepthOfSearch % 2 != Depth % 2 && !IsWhite)) { Console.Write("> MAX | "); } else { Console.Write("> MIN | "); } Console.Write("Depth: " + Depth.ToString()); Console.WriteLine(); } if (Debug) { ShowBoard(board, Depth + 1); } // detect if we should stop if (Depth == 0 || usablepieces.Count == 0 || board.WhiteHasWon() || board.BlackHasWon()) { return(new CalculatedMove(PlayerColour * board.EvaluateBoard(), new Position(-1, -1), new MoveSet())); } // If we can carry on searching, setup BestPiece and BestMoveset with first valid move we come accross Position BestPiecePosition = new Position(-1, -1); MoveSet BestMoveset = new MoveSet(); foreach (Position p in usablepieces) { BestPiecePosition = p; if (board.GetPiece(p).GetMoves(board).Count > 0) { BestMoveset = board.GetPiece(p).GetMoves(board).First(); break; } } // Counts the number of pieces we have searched int piececount = 0; foreach (Position pieceposition in usablepieces) { if (Debug) { Console.WriteLine(); for (int p = -1; p < (DepthOfSearch - Depth); p++) { Console.Write("\t"); } Console.WriteLine("NEW PIECE at " + pieceposition.ToString()); } // generate all possible take movesets possibleMovesets = board.GetPiece(pieceposition).GetTakeMovesOnly(board); if (possibleMovesets.Count > 0) { if (!FoundTakeMove && !AppliedTakeMove) { // if this is the first piece that has take movesets, mark it so that every move is better than what we had. FoundTakeMove = true; } } else if (!FoundTakeMove) { possibleMovesets = board.GetPiece(pieceposition).GetMoves(board); } if (Debug) { for (int p = 0; p < (DepthOfSearch - Depth); p++) { Console.Write("\t"); } Console.WriteLine("Take Moves found: " + FoundTakeMove); } bool BreakOuterLoop = false; foreach (MoveSet moveset in possibleMovesets) { // Make test board Board testboard = board.MakeNewCopyOf(); // Make move Position oldpos = pieceposition; foreach (Position move in moveset.Moves) { testboard.MovePeice(oldpos, move); oldpos = move; } // Run the search CalculatedMove Move = NegaMax(Depth - 1, -PlayerColour, -beta, -alpha, testboard, worker); // Change the best result if we need to if (BestValue < Move.Value || (FoundTakeMove && !AppliedTakeMove)) { if (FoundTakeMove && !AppliedTakeMove) { AppliedTakeMove = true; } BestMoveset = moveset; BestPiecePosition = pieceposition; if (Debug && Move.Moveset.NumberOfStages() > 0) { for (int p = 0; p < (DepthOfSearch - Depth); p++) { Console.Write("\t"); } Console.WriteLine("New best move from " + Move.MoveFrom.ToString() + " to " + Move.Moveset.Last().ToString() + " with score of: " + Move.Value.ToString() + " breating previous of: " + BestValue.ToString()); } BestValue = Move.Value; } alpha = Math.Max(alpha, BestValue); if (Debug) { for (int p = -1; p < (DepthOfSearch - Depth); p++) { Console.Write("\t"); } Console.WriteLine(" | Current Board Score: " + (PlayerColour * testboard.EvaluateBoard()).ToString() + " | Best Value: " + BestValue.ToString()); } if (alpha >= beta && UsePruning) { if (Debug) { for (int p = 0; p < (DepthOfSearch - Depth); p++) { Console.Write("\t"); } Console.WriteLine(alpha.ToString() + " " + beta.ToString() + "Broke"); } BreakOuterLoop = true; break; } } // If its the first call (highest depth) and we have finished a piece, report back to the worker our progress if (Depth == DepthOfSearch) { worker.ReportProgress((int)(100f * piececount) / usablepieces.Count); } piececount++; if (BreakOuterLoop) { break; } } return(new CalculatedMove(BestValue, BestPiecePosition, BestMoveset)); }
// recursive structure to find multi-step moves around the piece private List <MoveSet> GetTakeMoves(Board board, Position position, bool iswhite, MoveSet moveset) { List <MoveSet> Moves = new List <MoveSet>(); Position LB = position.GetLeftBack(iswhite); Position LBT = position.GetLeftBackTake(IsWhite); Position RB = position.GetRightBack(IsWhite); Position RBT = position.GetRightBackTake(IsWhite); Position LF = position.GetLeftForward(iswhite); Position LFT = position.GetLeftForwardTake(IsWhite); Position RF = position.GetRightForward(IsWhite); Position RFT = position.GetRightForwardTake(IsWhite); MoveSet CurrentMove = new MoveSet(moveset); if (LB.InBoard() && LBT.InBoard()) { if (board.GetPiece(LB) != null && board.GetPiece(LBT) == null) { if (board.GetPiece(LB).IsWhite != this.IsWhite) { Board testboard = board.MakeNewCopyOf(); testboard.RemovePeice(testboard.GetPiece(LB)); CurrentMove.Add(LBT); Moves.Add(CurrentMove); moveset.Add(LBT); Moves.AddRange(GetTakeMoves(testboard, LBT, IsWhite, moveset)); moveset.Remove(LBT); } } } CurrentMove = new MoveSet(moveset); if (RB.InBoard() && RBT.InBoard()) { if (board.GetPiece(RB) != null && board.GetPiece(RBT) == null) { if (board.GetPiece(RB).IsWhite != this.IsWhite) { Board testboard = board.MakeNewCopyOf(); testboard.RemovePeice(testboard.GetPiece(RB)); CurrentMove.Add(RBT); Moves.Add(CurrentMove); moveset.Add(RBT); Moves.AddRange(GetTakeMoves(testboard, RBT, IsWhite, moveset)); moveset.Remove(RBT); } } } CurrentMove = new MoveSet(moveset); if (LF.InBoard() && LFT.InBoard()) { if (board.GetPiece(LF) != null && board.GetPiece(LFT) == null) { if (board.GetPiece(LF).IsWhite != this.IsWhite) { Board testboard = board.MakeNewCopyOf(); testboard.RemovePeice(testboard.GetPiece(LF)); CurrentMove.Add(LFT); Moves.Add(CurrentMove); moveset.Add(LFT); Moves.AddRange(GetTakeMoves(testboard, LFT, IsWhite, moveset)); moveset.Remove(LFT); } } } CurrentMove = new MoveSet(moveset); if (RF.InBoard() && RFT.InBoard()) { if (board.GetPiece(RF) != null && board.GetPiece(RFT) == null) { if (board.GetPiece(RF).IsWhite != this.IsWhite) { Board testboard = board.MakeNewCopyOf(); testboard.RemovePeice(testboard.GetPiece(RF)); CurrentMove.Add(RFT); Moves.Add(CurrentMove); moveset.Add(RFT); Moves.AddRange(GetTakeMoves(testboard, RFT, IsWhite, moveset)); moveset.Remove(RFT); } } } return(Moves); }