/// <summary> /// Counts the amount of leafNode at the parameter input depth, /// by an inorder recursive tree traversion algorithm. /// It checks all legal moves with the parameter input depth, /// and increments the leafNode counter when the "last" move /// (the leaf) has been located. /// </summary> /// <param name="depth"> The depth to traverse </param> /// <param name="board"> The chess board operate on </param> /// <exception cref="Exception"></exception> public void _Perft(int depth, Board board) // For counting the TOTAL available moves { Debug.Assert(BoardOperations.CheckBoard(board)); // Increment leafNode and return. if (depth == 0) { LeafNodes++; return; } // Generate moves for rootposition MoveList list = new MoveList(); MoveGen.GenerateAllMoves(board, list, false); for (int i = 0; i < list.Count; ++i) { if (!MakeMove.Make_Move(board, list.Moves[i].Move)) { continue; } _Perft(depth - 1, board); MakeMove.TakeMove(board); } }
public void Perft_Test(int depth, Board board) // Also prints information regarding the moves { Debug.Assert(BoardOperations.CheckBoard(board)); var startTime = Variables.Watch.ElapsedMilliseconds; Console.Write("\nStarting Perft Test to Depth {0}", depth); BoardOperations.PrintBoard(board); LeafNodes = 0; MoveList list = new MoveList(); MoveGen.GenerateAllMoves(board, list, false); for (int i = 0; i < list.Count; ++i) { int move = list.Moves[i].Move; if (!MakeMove.Make_Move(board, list.Moves[i].Move)) { continue; } long cumulativeNodes = LeafNodes; _Perft(depth - 1, board); MakeMove.TakeMove(board); long oldNodes = LeafNodes - cumulativeNodes; Console.Write("\nmove {0} : {1} : {2}", i + 1, Io.MoveToString(move), oldNodes); } Console.Write("\nTest Complete: {0} nodes visited in {1} miliseconds\n", LeafNodes, Variables.Watch.ElapsedMilliseconds - startTime); }
protected override ActionContext DoAction(ActionContext context) { if (context.Game == null) { throw new InvalidOperationException("Action context missing required property (Game)"); } if (context.Board == null) { throw new InvalidOperationException("Action context missing required property (Board)"); } GameActionData actionData = MakeActionData(context); Game game = context.Game; Board board = context.Board; string[] turnOrder = game.TurnOrder; game.CurrentTurn++; game.CurrentTurn %= turnOrder.Length; game.turnCount++; game.TilesActiveThisTurn = new int[0]; if (game.FirstPlayer != game.CurrentPlayer) { game.AddGameAction(actionData); return(context); } game.CurrentTurn++; game.CurrentTurn %= turnOrder.Length; game.FirstPlayer = turnOrder[game.CurrentTurn]; game.SunPosition = (SunPosition)(((int)game.SunPosition + 1) % Enum.GetNames(typeof(SunPosition)).Length); if (game.SunPosition == SunPosition.NorthWest) { game.Revolution++; if (game.Revolution == game.LengthOfGame) { game.Status = GameStatus.Ended; game.AddGameAction(actionData); context.Game = game; context.Board = board; return(context); } } board.Tiles = Shadow.UpdateAllShadows(board, game.SunPosition); foreach (string playerId in game.TurnOrder) { PlayerBoard playerBoard = PlayerBoard.Get(game, playerId); int earnedLight = BoardOperations.CountLight(board, playerBoard.TreeType); Console.WriteLine($"{playerId} - {earnedLight}"); playerBoard.RecoverLight(earnedLight); game.SetPlayerBoard(playerId, playerBoard); } game.AddGameAction(actionData); return(context); }
private void PrintIfGameOver() { var winner = BoardOperations.GetBoardWinner(_grid.Cells, toWin); if (winner == Winner.Draw && BoardOperations.HasAnyMovesLeft(_grid.Cells)) { return; } _text.SetText(winner == Winner.Draw ? "Draw" : winner == (player == CellType.X ? Winner.X : Winner.O) ? "You won" : "You lose"); _text.gameObject.SetActive(true); StartCoroutine(WaitAndExit()); }
public void Should_AddWorkItemToBoard() { //Arrange var boardOperations = new BoardOperations(); var mockBoard = new Mock <IBoard>(); var mockWorkitem = new Mock <IBug>(); mockBoard.Setup(x => x.WorkItems).Returns(new List <IWorkItem>()); //Act boardOperations.AddWorkitemToBoard(mockBoard.Object, mockWorkitem.Object); //Assert Assert.IsTrue(mockBoard.Object.WorkItems.Contains(mockWorkitem.Object)); }
public void Should_AddActivityHistoryToBoard() { //Arrange var boardOperations = new BoardOperations(); var mockBoard = new Mock <IBoard>(); var mockWorkItem = new Mock <IBug>(); mockBoard.Setup(x => x.WorkItems).Returns(new List <IWorkItem>()); mockWorkItem.Setup(x => x.Title).Returns("Bug1234567"); mockBoard.Setup(x => x.ActivityHistory).Returns(new List <IActivityHistory>()); //Act boardOperations.AddActivityHistoryToBoard(mockBoard.Object, mockWorkItem.Object); //Assert Assert.AreEqual(mockBoard.Object.ActivityHistory.First().Message, "A IBugProxy with Title: Bug1234567"); }
public void Should_AddActivityHistoryToBoardForAssignAndUnassign() { //Arrange var boardOperations = new BoardOperations(); var mockBoard = new Mock <IBoard>(); var mockMemberAssign = new Mock <IMember>(); var mockMemberUnassign = new Mock <IMember>(); mockBoard.Setup(x => x.WorkItems).Returns(new List <IWorkItem>()); mockMemberAssign.Setup(x => x.Name).Returns("Edward"); mockMemberUnassign.Setup(x => x.Name).Returns("Kiro"); mockBoard.Setup(x => x.ActivityHistory).Returns(new List <IActivityHistory>()); string type = "bug"; string workItemTitle = "bug1234567"; //Act boardOperations.AddActivityHistoryAfterAssignUnsignToBoard(mockBoard.Object, type, workItemTitle, mockMemberAssign.Object, mockMemberUnassign.Object); //Assert Assert.AreEqual(mockBoard.Object.ActivityHistory.First().Message, "A bug with Title: bug1234567 was unassigned from Kiro and assigned to Edward"); }
public void DepthK(int k) { for (int i = 0; i < perftSuite.Length - 1; ++i) { string line = perftSuite[i]; string fen = ""; int index = 0; // Locate the FEN for (int j = 0; j < line.Length; j++) { if (line[j] == ';') { fen = line.Substring(0, j - 1); index = j; break; } } for (int j = 1; j < k; j++) { FindNextSemiColon(ref index, line); index++; } FindNextSemiColon(ref index, line); index += 4; int depthInt = FindExpectedDepthVal(index, line); BoardOperations.ParseFen(fen, board); MoveGen.GenerateAllMoves(board, moveList, false); perft.Perft_Test(k, board); Assert.AreEqual(perft.LeafNodes, depthInt); } }
// should read "position fen" // "position startpos" // which could possibly be followed by "... moves a2a3 a3a4" etc. public void ParsePosition(string lineIn, Board board) { int stringIndex = 9; // starts at 9 cause position is length 8 int moveIndex = lineIn.IndexOf("moves"); // is there any moves to consider? if (lineIn.Length >= stringIndex + 8 && lineIn.Substring(stringIndex, 8).Equals("startpos")) { BoardOperations.ParseFen(Fens.START_FEN, board); } else // Else "position fen fenstring" { if (lineIn.Length >= stringIndex + 3 && lineIn.Substring(stringIndex, 3).Equals("fen")) { stringIndex += 4; // should be at start of fenstring now. if (moveIndex == -1) { BoardOperations.ParseFen(lineIn.Substring(stringIndex), board); } else { BoardOperations.ParseFen( lineIn.Substring(stringIndex, moveIndex - stringIndex - 1), board); } } else { BoardOperations.ParseFen(Fens.START_FEN, board); } } if (moveIndex != -1) // moves were found. { stringIndex = moveIndex + 6; // We are now at start of command moves. moves |a2a3 int move = Variables.NO_MOVE; while (stringIndex <= lineIn.Length - 1) { stringIndex += 5; if (lineIn.Length > stringIndex && lineIn[stringIndex - 1] == ' ') { move = Io.ParseMove(board, lineIn.Substring(stringIndex - 5, 4).ToCharArray()); // not a promotion move. } else if (stringIndex == lineIn.Length + 1) // if at last move { move = Io.ParseMove(board, lineIn.Substring(stringIndex - 5, 4).ToCharArray()); } else if (stringIndex == lineIn.Length) // promotion move at end of line { move = Io.ParseMove(board, lineIn.Substring(stringIndex - 5, 5).ToCharArray()); } else if (lineIn.Length >= stringIndex && lineIn[stringIndex - 1] != ' ') { move = Io.ParseMove(board, lineIn.Substring(stringIndex - 5, 5).ToCharArray()); stringIndex++; } if (move == Variables.NO_MOVE) { break; } MakeMove.Make_Move(board, move); board.Ply = 0; } } BoardOperations.PrintBoard(board); }
/// <summary> /// Validates whether the parameter square is attacked by input side. /// </summary> /// <param name="sq"> The square to validate </param> /// <param name="side"> The side to check for attacks </param> /// <param name="board"> The current board </param> /// <returns> True or false depending on whether the sq is attacked </returns> /// <exception cref="Exception"></exception> public static bool IsSqAttacked(int sq, int side, Board.Board board) { Debug.Assert(Validators.SqOnBoard(sq), String.Format("Square {0} on board is invalid", sq)); Debug.Assert(Validators.SideValid(side), String.Format("Side {0} on board is invalid", side)); Debug.Assert(BoardOperations.CheckBoard(board), String.Format("Checkboard is false")); // first checking pawns if (side == (int)Colour.WHITE) { if (board[sq - 9] == (int)Piece.wP || board[sq - 11] == (int)Piece.wP) { return(true); } } else { // side black if (board[sq + 9] == (int)Piece.bP || board[sq + 11] == (int)Piece.bP) { return(true); } } // knights for (var i = 0; i < Attack.KN_DIR.Length; ++i) { var piece = board[sq + Attack.KN_DIR[i]]; if (piece == (int)Piece.EMPTY || piece == (int)Square.NO_SQ) { continue; } if (Data.IsPieceKnight(piece) && (int)Data.PIECE_COLOURS[piece] == side) { return(true); } } // Rooks queens for (var i = 0; i < Attack.RK_DIR.Length; ++i) { var square = sq + Attack.RK_DIR[i]; var piece = board[square]; while (Validators.IsSq(square)) { if (piece != (int)Piece.EMPTY) { if (Data.IsPieceRookQueen(piece) && (int)Data.PIECE_COLOURS[piece] == side) { return(true); } break; } square += Attack.RK_DIR[i]; piece = board[square]; } } // Bishop queens for (var i = 0; i < Attack.BI_DIR.Length; ++i) { var square = sq + Attack.BI_DIR[i]; var piece = board[square]; while (Validators.IsSq(square)) { if (piece != (int)Piece.EMPTY) { if (Data.IsPieceBishopQueen(piece) && (int)Data.PIECE_COLOURS[piece] == side) { return(true); } break; } square += Attack.BI_DIR[i]; piece = board[square]; } } // Kings for (var i = 0; i < Attack.KI_DIR.Length; ++i) { var piece = board[sq + Attack.KI_DIR[i]]; if (piece == (int)Piece.EMPTY || piece == (int)Square.NO_SQ) { continue; } if (Data.IsPieceKing(piece) && (int)Data.PIECE_COLOURS[piece] == side) { return(true); } } return(false); }
private void Awake() { boardOperations = GetComponent <BoardOperations>(); uI = GameObject.FindWithTag("UserPanel").GetComponent <UpdateUI>(); }
/// <summary> /// Generates all available moves for the current position on the board in the parameter MoveList. /// If the onlyCaptures parameter is true, it will only generate capture moves. /// </summary> /// <param name="board"> The current board position </param> /// <param name="list"> The MoveList to parse the available moves to. </param> /// <param name="onlyCaptures"> True if only generating for captures. </param> public static void GenerateAllMoves(Board.Board board, MoveList list, bool onlyCaptures) { Debug.Assert(BoardOperations.CheckBoard(board)); list.Count = 0; var side = (Colour)board.Side; var piece = side == Colour.WHITE ? (int)Piece.wP : (int)Piece.bP; for (var pceNum = 0; pceNum < board.PceNum[piece]; ++pceNum) { var sq = board.PList[piece, pceNum]; Debug.Assert(Validators.IsSq(sq), String.Format("Sq {0} is invalid", sq)); var leftCaptureSq = side == Colour.WHITE ? sq + 9 : sq - 9; var rightCaptureSq = side == Colour.WHITE ? sq + 11 : sq - 11; if (!onlyCaptures) { var sqInfront = side == Colour.WHITE ? sq + 10 : sq - 10; if (board[sqInfront] == (int)Piece.EMPTY && Validators.SqOnBoard(sqInfront)) { if (side == Colour.WHITE) { MoveGen.AddWhitePawnMove(board, sq, sqInfront, list); // Check if the number two square infront of the pawn is empty and that the rank is 2. if (Conversion.getRanksBrd(sq) == (int)Rank.RANK_2 && board[sq + 20] == (int)Piece.EMPTY) { MoveGen.AddQuietMove(board, MoveOperations.CreateMove(sq, sq + 20, (int)Piece.EMPTY, (int)Piece.EMPTY, MoveOperations.MoveFlagPawnStart), list); } } else // BLACK { MoveGen.AddBlackPawnMove(board, sq, sqInfront, list); // Check if the number two square infront of the pawn is empty and that the rank is 7. if (Conversion.getRanksBrd(sq) == (int)Rank.RANK_7 && board[sq - 20] == (int)Piece.EMPTY) { MoveGen.AddQuietMove(board, MoveOperations.CreateMove(sq, sq - 20, (int)Piece.EMPTY, (int)Piece.EMPTY, MoveOperations.MoveFlagPawnStart), list); } } } } if (Validators.IsSq(leftCaptureSq) && Data.PIECE_COLOURS[board[leftCaptureSq]] == (Colour)((int)side ^ 1)) { if (side == Colour.WHITE) { MoveGen.AddWhitePawnCapMove(board, sq, leftCaptureSq, board[leftCaptureSq], list); } else { // BLACK MoveGen.AddBlackPawnCapMove(board, sq, leftCaptureSq, board[leftCaptureSq], list); } } if (Validators.IsSq(rightCaptureSq) && Data.PIECE_COLOURS[board[rightCaptureSq]] == (Colour)((int)side ^ 1)) { if (side == Colour.WHITE) { MoveGen.AddWhitePawnCapMove(board, sq, rightCaptureSq, board[rightCaptureSq], list); } else { // BLACK MoveGen.AddBlackPawnCapMove(board, sq, rightCaptureSq, board[rightCaptureSq], list); } } if (Validators.IsSq(board.EnPas)) { if (leftCaptureSq == board.EnPas) { MoveGen.AddEnPassantMove(board, MoveOperations.CreateMove(sq, leftCaptureSq, (int)Piece.EMPTY , (int)Piece.EMPTY, MoveOperations.MoveFlagEnPas), list); } else if (rightCaptureSq == board.EnPas) { MoveGen.AddEnPassantMove(board, MoveOperations.CreateMove(sq, rightCaptureSq, (int)Piece.EMPTY , (int)Piece.EMPTY, MoveOperations.MoveFlagEnPas), list); } } } // Castling if (!onlyCaptures) { if (side == Colour.WHITE) { // If there is White King Castle Permission. if ((board.CastlePerm & (int)Castling.WKCA) != 0) { // Check if squares are empty before we call the less efficient SqAttacked method. var isSqG1F1Empty = board[(int)Square.F1] == (int)Piece.EMPTY && board[ (int)Square.G1] == (int)Piece.EMPTY; if (isSqG1F1Empty) { var IsSqE1OrF1NotAtt = !Attack.IsSqAttacked((int)Square.F1, (int)Colour.BLACK, board) && !Attack.IsSqAttacked((int)Square.E1, (int)Colour.BLACK, board); if (IsSqE1OrF1NotAtt) { MoveGen.AddQuietMove(board, MoveOperations.CreateMove((int)Square.E1, (int)Square.G1, (int)Piece.EMPTY, (int)Piece.EMPTY, MoveOperations.MoveFlagCastle), list); } } } // If there is White Queen Castle Permission. if ((board.CastlePerm & (int)Castling.WQCA) != 0) { var isSqB1C1D1Empty = board[(int)Square.B1] == (int)Piece.EMPTY && board[(int)Square.C1] == (int)Piece.EMPTY && board[(int)Square.D1] == (int)Piece.EMPTY; if (isSqB1C1D1Empty) { var isSqE1OrD1NotAtt = !Attack.IsSqAttacked((int)Square.E1, (int)Colour.BLACK, board) && !Attack.IsSqAttacked((int)Square.D1, (int)Colour.BLACK, board); if (isSqE1OrD1NotAtt) { MoveGen.AddQuietMove(board, MoveOperations.CreateMove((int)Square.E1, (int)Square.C1, (int)Piece.EMPTY, (int)Piece.EMPTY, MoveOperations.MoveFlagCastle), list); } } } } else { // If there is Black King Castle Permission. if ((board.CastlePerm & (int)Castling.BKCA) != 0) { // Check if squares are empty before we call the less efficient SqAttacked method. var isSqG8F8Empty = board[(int)Square.F8] == (int)Piece.EMPTY && board[(int)Square.G8] == (int)Piece.EMPTY; if (isSqG8F8Empty) { var isSqE8F8NotAttacked = !Attack.IsSqAttacked((int)Square.E8, (int)Colour.WHITE, board) && !Attack.IsSqAttacked((int)Square.F8, (int)Colour.WHITE, board); if (isSqE8F8NotAttacked) { MoveGen.AddQuietMove(board, MoveOperations.CreateMove((int)Square.E8, (int)Square.G8, (int)Piece.EMPTY, (int)Piece.EMPTY, MoveOperations.MoveFlagCastle), list); } } } // If there is White Queen Castle Permission. if ((board.CastlePerm & (int)Castling.BQCA) != 0) { // Check if squares are empty before we call the less efficient SqAttacked method. var isSqB8C8D8Empty = board[(int)Square.B8] == (int)Piece.EMPTY && board[(int)Square.C8] == (int)Piece.EMPTY && board[(int)Square.D8] == (int)Piece.EMPTY; if (isSqB8C8D8Empty) { var isSqE8D8NotAttacked = !Attack.IsSqAttacked((int)Square.E8, (int)Colour.WHITE, board) && !Attack.IsSqAttacked((int)Square.D8, (int)Colour.WHITE, board); if (isSqE8D8NotAttacked) { MoveGen.AddQuietMove(board, MoveOperations.CreateMove((int)Square.E8, (int)Square.C8, (int)Piece.EMPTY, (int)Piece.EMPTY, MoveOperations.MoveFlagCastle), list); } } } } } // Loop sliding pieces var pceIndex = MoveGen.LOOP_SLIDE_INDEX[board.Side]; // Increments AFTER it's run var pce = MoveGen.LOOP_SLIDE_PCE[pceIndex++]; while (pce != 0) { Debug.Assert(Validators.PieceValid(pce), String.Format("You have reached an invalid sliding piece {0}", pce)); for (var pceNum = 0; pceNum < board.PceNum[pce]; ++pceNum) { var sq = board.PList[pce, pceNum]; // Square check Debug.Assert(Validators.IsSq(sq), String.Format("Sq {0} is false", sq)); for (var index = 0; index < MoveGen.NUM_DIR[pce]; ++index) { var t_sq = sq + MoveGen.PCE_DIR[pce, index]; // Check if offboard if (!Validators.SqOnBoard(t_sq)) { continue; } while (Validators.SqOnBoard(t_sq)) { if (board[t_sq] != (int)Piece.EMPTY) { // 0 EXCLUSIVE OR 1 returns 1 = COLOUR.WHITE // 1 EXCLUSIVE OR 1 returns 0 = COLOUR.BLACK if ((int)Data.PIECE_COLOURS[board[t_sq]] == (board.Side ^ 1)) { AddCaptureMove(board, MoveOperations.CreateMove(sq, t_sq, board[t_sq], (int)Piece.EMPTY, 0), list); } break; } if (!onlyCaptures) { AddQuietMove(board, MoveOperations.CreateMove(sq, t_sq, (int)Piece.EMPTY, (int)Piece.EMPTY, 0), list); } t_sq += MoveGen.PCE_DIR[pce, index]; } } } pce = MoveGen.LOOP_SLIDE_PCE[pceIndex++]; } // Loop non_sliding pieces pceIndex = MoveGen.LOOP_NON_SLIDE_INDEX[board.Side]; pce = MoveGen.LOOP_NON_SLIDE_PCE[pceIndex++]; while (pce != 0) { Debug.Assert(Validators.PieceValid(pce), String.Format("You have reached an invalid sliding piece {0}", pce)); for (var pceNum = 0; pceNum < board.PceNum[pce]; ++pceNum) { var sq = board.PList[pce, pceNum]; // Square check Debug.Assert(Validators.IsSq(sq), String.Format("Sq {0} is invalid", sq)); for (var index = 0; index < MoveGen.NUM_DIR[pce]; ++index) { var t_sq = sq + MoveGen.PCE_DIR[pce, index]; // Check if offboard if (!Validators.SqOnBoard(t_sq)) { continue; } if (board[t_sq] != (int)Piece.EMPTY) { // 0 EXCLUSIVE OR 1 returns 1 = COLOUR.WHITE // 1 EXCLUSIVE OR 1 returns 0 = COLOUR.BLACK if ((int)Data.PIECE_COLOURS[board[t_sq]] == (board.Side ^ 1)) { AddCaptureMove(board, MoveOperations.CreateMove(sq, t_sq, board[t_sq], (int)Piece.EMPTY, 0), list); } continue; } if (!onlyCaptures) { AddQuietMove(board, MoveOperations.CreateMove(sq, t_sq, (int)Piece.EMPTY, (int)Piece.EMPTY, 0), list); } } } pce = MoveGen.LOOP_NON_SLIDE_PCE[pceIndex++]; } }
public int AlphaBeta(int alpha, int beta, int depth, ref S_SearchInfo info, bool DoNull) { Debug.Assert(BoardOperations.CheckBoard(board)); if (depth == 0) { return(Quiescence(alpha, beta, ref info)); } if ((info.Nodes & 2047) == 0) { CheckUp(ref info); } info.Nodes++; // If position is a draw. if ((IsRepetition() || board.FiftyMoves >= 100) && board.Ply != 0) { return(0); } if (board.Ply > Variables.MAX_DEPTH - 1) { return(Evaluate.Position(board)); } bool kingInCheck = Attack.IsSqAttacked(board.KingSq[board.Side], board.Side ^ 1, board); // If king is in check, search deeper to get out of check. if (kingInCheck) { depth++; // The two following lines are possibly ERROR. long timeInc = (info.StopTime - info.StartTime) * (1 / 2); info.StopTime += timeInc; } MoveList list = new MoveList(); MoveGen.GenerateAllMoves(board, list, false); int oldAlpha = alpha; int score = -infinite; int legal = 0; // Will increment when we find a legal move. int bestMove = Variables.NO_MOVE; int PvMove = PvTable.Probe(board); // Prioritize Principle Variation move if it's found. if (PvMove != Variables.NO_MOVE) { for (int i = 0; i < list.Count; ++i) { var move = list.Moves[i].Move; if (move == PvMove) { list.Moves[i].Score = 2000000; break; } } } for (int i = 0; i < list.Count; ++i) { PickNextMove(i, list); var move = list.Moves[i].Move; if (!MakeMove.Make_Move(board, move)) { continue; } legal++; score = -AlphaBeta(-beta, -alpha, depth - 1, ref info, true); MakeMove.TakeMove(board); // Take back the made move. if (info.Stopped) { return(0); // Back up to the root if times up. } // We have a new alpha or beta cutoff. if (score > alpha) { bool isCaptureMove = (move & MoveOperations.MoveFlagCapture) != 0; // beta cutoff? if (score >= beta) { if (legal == 1) { info.Fhf++; // We searched the best move first. } info.Fh++; // If beta cutoff, but no capture move. if (!isCaptureMove) { board.SearchKillers[1, board.Ply] = board.SearchKillers[0, board.Ply]; board.SearchKillers[0, board.Ply] = move; } return(beta); } // Alpha cutoff alpha = score; bestMove = move; if (!isCaptureMove) { int from = MoveOperations.FromSq(move); int to = MoveOperations.ToSq(move); board.SearchHistory[board[from], to] += depth; // Prioritizes move near the root of the tree. } } } // If we haven't had any legal moves. if (legal == 0) { // If in check with no legal moves checkmate. if (kingInCheck) { return(-mate + board.Ply); // Return the amount of moves it takes to mate. // Returning in this way, allows the method to "prefer" the fastest checkmate combination. } else { return(0); // Stalemate. } } if (alpha != oldAlpha) { PvTable.StoreMove(board, bestMove); } return(alpha); }
protected override ActionContext DoAction(ActionContext context) { if (context.Game == null) { throw new InvalidOperationException("Action context missing required property (Game)"); } if (context.Board == null) { throw new InvalidOperationException("Action context missing required property (Board)"); } if (context.Origin == null) { throw new InvalidOperationException("Action context missing required property (Origin)"); } GameActionData actionData = MakeActionData(context); Game game = context.Game; Board board = context.Board; Hex origin = (Hex)context.Origin; PlayerBoard playerBoard = PlayerBoard.Get(game, context.PlayerId); int tileCode = context.Board.Get(origin); tileCode = Tile.SetPieceType(tileCode, PieceType.SmallTree); TreeType treeType = playerBoard.TreeType; tileCode = Tile.SetTreeType(tileCode, treeType); playerBoard.Pieces(PieceType.SmallTree).DecreaseAvailable(); PlayerBoard.Set(game, context.PlayerId, playerBoard); context.Board.Set(origin, tileCode); PlayerBoard.Set(game, context.PlayerId, playerBoard); board = BoardOperations.CastShadow(board, origin, game.SunPosition); game.AddGameAction(actionData); switch (game.Status) { case GameStatus.PlacingFirstTrees when game.CurrentTurn == game.TurnOrder.Length - 1: game.Status = GameStatus.PlacingSecondTrees; return(context); case GameStatus.PlacingFirstTrees: game.CurrentTurn++; return(context); case GameStatus.PlacingSecondTrees when game.CurrentTurn == 0: foreach (string id in game.TurnOrder) { PlayerBoard pb = PlayerBoard.Get(game, id); pb.Light = (BoardOperations.CountLight(context.Board, pb.TreeType)); game.SetPlayerBoard(id, pb); } game.Status = GameStatus.InProgress; return(context); case GameStatus.PlacingSecondTrees: game.CurrentTurn--; return(context); case GameStatus.Preparing: break; case GameStatus.InProgress: break; case GameStatus.Ended: break; default: throw new ArgumentOutOfRangeException(); } context.Game = game; context.Board = board; return(context); }
// Possibly not static // Returns true if legal move, or false otherwise /// <summary> /// Makes the input move on the board, if the move is legal. /// If illegal, nothing happens and the method returns false. /// </summary> /// <param name="board"> The board to make the move on </param> /// <param name="move"> The move to perform </param> public static bool Make_Move(Board.Board board, int move) { Debug.Assert(BoardOperations.CheckBoard(board), "The CheckBoard method returned false."); int from = MoveOperations.FromSq(move); int to = MoveOperations.ToSq(move); int side = board.Side; Debug.Assert(Validators.SqOnBoard(from), String.Format("Invalid From Square {0}", Io.SqToString(from))); Debug.Assert(Validators.SqOnBoard(to), String.Format("Invalid To Square {0}", Io.SqToString(to))); Debug.Assert(Validators.SideValid(side), String.Format("Invalid Side with integer value {0}", side)); Debug.Assert(Validators.PieceValid(board[from]), String.Format("Invalid From Square {0}", Io.SqToString(from))); board.History[board.HistoryPly].PosKey = board.PosKey; // Now we check for special moves. if ((move & MoveOperations.MoveFlagEnPas) != 0) { if (side == (int)Colour.WHITE) // If EnPas move we need to kill the pawn { ClearPiece(to - 10, board); } else // Else black { ClearPiece(to + 10, board); } } else if ((move & MoveOperations.MoveFlagCastle) != 0) { // If castle we need to move the rook. switch (to) { case (int)Square.C1: MovePiece((int)Square.A1, (int)Square.D1, board); break; case (int)Square.C8: MovePiece((int)Square.A8, (int)Square.D8, board); break; case (int)Square.G1: MovePiece((int)Square.H1, (int)Square.F1, board); break; case (int)Square.G8: MovePiece((int)Square.H8, (int)Square.F8, board); break; default: throw new Exception( "The move is a castling move, but the to square doesn't match any eligible moves"); } } if (board.EnPas != (int)Square.NO_SQ) { MakeMove.HashEnPas(board); } MakeMove.HashCastle(board); // POSSIBLE ERROR, MAYBE IT SHOULD BE IN IF STATEMENT ABOVE. // Store information in history array. board.History[board.HistoryPly].Move = move; board.History[board.HistoryPly].EnPas = board.EnPas; board.History[board.HistoryPly].CastlePerm = board.CastlePerm; board.History[board.HistoryPly].FiftyMoves = board.FiftyMoves; // Adjust castle permissions if rook or king has moved. board.CastlePerm &= MakeMove.castlePerm[from]; board.CastlePerm &= MakeMove.castlePerm[to]; board.EnPas = (int)Square.NO_SQ; HashCastle(board); int captured = MoveOperations.Captured(move); board.FiftyMoves++; // If there is a piece captured if (captured != (int)Piece.EMPTY) { // Test if the piece is valid. Debug.Assert(Validators.PieceValid(captured), String.Format("Invalid piece ID integer {0}", captured)); ClearPiece(to, board); board.FiftyMoves = 0; // reset 50moves, cuz a piece has been captured. } board.HistoryPly++; board.Ply++; if (Data.IsPiecePawn(board[from])) { board.FiftyMoves = 0; // Reset 50moves, cuz a pawn has moved. if ((move & MoveOperations.MoveFlagPawnStart) != 0) { if (side == (int)Colour.WHITE) { board.EnPas = from + 10; Debug.Assert(Conversion.getRanksBrd(board.EnPas) == (int)Rank.RANK_3, String.Format("Invalid board state: the enPas square {0} is wrong", Io.SqToString(board.EnPas))); } else { board.EnPas = from - 10; Debug.Assert(Conversion.getRanksBrd(board.EnPas) == (int)Rank.RANK_6, String.Format("Invalid board state: the enPas square {0} is wrong", Io.SqToString(board.EnPas))); } HashEnPas(board); } } MovePiece(from, to, board); int promotedPce = MoveOperations.Promoted(move); if (promotedPce != (int)Piece.EMPTY) // If there is a promoted piece // A piece cannot be promoted to a pawn. { Debug.Assert(Validators.PieceValid(promotedPce) && !Data.IsPiecePawn(promotedPce), String.Format("Promoted piece {0} is invalid", (Piece)promotedPce)); ClearPiece(to, board); AddPiece(to, board, promotedPce); } if (Data.IsPieceKing(board[to])) { // If piece is king set the KingSQ board.KingSq[side] = to; } // Exclusive or, changes the side from white to black or black to white. board.Side ^= 1; HashSide(board); Debug.Assert(BoardOperations.CheckBoard(board)); // Make sure that the new king square isn't attacked. if (Attack.IsSqAttacked(board.KingSq[side], board.Side, board)) { TakeMove(board); return(false); } return(true); }
public static void TakeMove(Board.Board board) { Debug.Assert(BoardOperations.CheckBoard(board)); // Decrement the plys. board.HistoryPly--; board.Ply--; int move = board.History[board.HistoryPly].Move; int from = MoveOperations.FromSq(move); int to = MoveOperations.ToSq(move); Debug.Assert(Validators.SqOnBoard(from), String.Format("Invalid From Square {0}", Io.SqToString(from))); Debug.Assert(Validators.SqOnBoard(to), String.Format("Invalid To Square {0}", Io.SqToString(to))); // If there is an EnPas square, hash it out. if (board.EnPas != (int)Square.NO_SQ) { HashEnPas(board); } HashCastle(board); // Reverse relevant board structures. board.CastlePerm = board.History[board.HistoryPly].CastlePerm; board.FiftyMoves = board.History[board.HistoryPly].FiftyMoves; board.EnPas = board.History[board.HistoryPly].EnPas; // If the previous move have an EnPas square set, we need to hash it back in if (board.EnPas != (int)Square.NO_SQ) { HashEnPas(board); } // Hash the castling back incase it's changed. HashCastle(board); // Change the side to move back. board.Side ^= 1; HashSide(board); if ((move & MoveOperations.MoveFlagEnPas) != 0) { if (board.Side == (int)Colour.WHITE) // If EnPas move we need to add the pawn { AddPiece(to - 10, board, (int)Piece.bP); } else // Else black { AddPiece(to + 10, board, (int)Piece.wP); } } else if ((move & MoveOperations.MoveFlagCastle) != 0) { // If castle we need to move the rook. switch (to) { case (int)Square.C1: MovePiece((int)Square.D1, (int)Square.A1, board); break; case (int)Square.C8: MovePiece((int)Square.D8, (int)Square.A8, board); break; case (int)Square.G1: MovePiece((int)Square.F1, (int)Square.H1, board); break; case (int)Square.G8: MovePiece((int)Square.F8, (int)Square.H8, board); break; default: throw new Exception( "The move is a castling move, but the to square doesn't match any eligible moves"); } } // Move the piece back to the original square. MovePiece(to, from, board); if (Data.IsPieceKing(board[from])) { board.KingSq[board.Side] = from; } int captured = MoveOperations.Captured(move); if (captured != (int)Piece.EMPTY) { Debug.Assert(Validators.PieceValid(captured), "Invalid piece captured"); AddPiece(to, board, captured); } int promotedPce = MoveOperations.Promoted(move); if (promotedPce != (int)Piece.EMPTY) // If there is a promoted piece // A piece cannot be promoted to a pawn. { Debug.Assert((Validators.PieceValid(promotedPce) || !Data.IsPiecePawn(promotedPce)), String.Format("Promoted piece {0} is invalid. PieceValid returned {1}, and IsPiecePawn returned {2}", (Piece)promotedPce, Validators.PieceValid(promotedPce), Data.IsPiecePawn(promotedPce))); ClearPiece(from, board); AddPiece(from, board, ((Data.PIECE_COLOURS[promotedPce] == Colour.WHITE) ? (int)Piece.wP : (int)Piece.bP)); } Debug.Assert(BoardOperations.CheckBoard(board)); }
/// <summary> /// Search all capture positions, to help avoid the Horizon effect. /// </summary> private int Quiescence(int alpha, int beta, ref S_SearchInfo info) { Debug.Assert(BoardOperations.CheckBoard(board)); if ((info.Nodes & 2047) == 0) { CheckUp(ref info); } info.Nodes++; // If position is a draw. if ((IsRepetition() || board.FiftyMoves >= 100) && board.Ply != 0) { return(0); } int score = Evaluate.Position(board); // Stand_pat. if (board.Ply > Variables.MAX_DEPTH - 1) { return(score); } if (score >= beta) { return(beta); } if (score > alpha) { alpha = score; } MoveList list = new MoveList(); MoveGen.GenerateAllMoves(board, list, true); // Only capture moves int oldAlpha = alpha; score = -infinite; int legal = 0; // Will increment when we find a legal move. int bestMove = Variables.NO_MOVE; int PvMove = PvTable.Probe(board); for (int i = 0; i < list.Count; ++i) { PickNextMove(i, list); var move = list.Moves[i].Move; if (!MakeMove.Make_Move(board, move)) { continue; } legal++; score = -Quiescence(-beta, -alpha, ref info); MakeMove.TakeMove(board); // Take back the made move. if (info.Stopped) { return(0); } // We have a new alpha or beta cutoff. if (score > alpha) { bool isCaptureMove = (move & MoveOperations.MoveFlagCapture) != 0; // beta cutoff? if (score >= beta) { if (legal == 1) { info.Fhf++; // We searched the best move first. } info.Fh++; return(beta); } // Alpha cutoff alpha = score; bestMove = move; } } if (alpha != oldAlpha) { PvTable.StoreMove(board, bestMove); } return(alpha); }