internal static MoveContent AlphaBetaRoot(ChessBoard examineBoard, byte depth) { nodesSearched = 0; SearchResult result = new SearchResult(); //We are going to store our result boards here List<ChessBoard> validBoards = getValidBoards(examineBoard); Thread threadOne = new Thread(() => { result = getBestMove(examineBoard, validBoards, depth); }); threadOne.Start(); threadOne.Join(); System.Diagnostics.Debug.WriteLine("Node Searched: " + nodesSearched); return result.bestMove; }
/// <summary> /// Allows the game to perform any initialization it needs to before starting to run. /// This is where it can query for any required services and load any non-graphic /// related content. Calling base.Initialize will enumerate through any components /// and initialize them as well. /// </summary> protected override void Initialize() { boardInfo = new ChessBoard(); boardInfo.WhoseMove = ChessPieceColor.White; boardInfo.pieces = new ChessPiece[] { new ChessPiece(ChessPieceType.Rook,0,true), new ChessPiece(ChessPieceType.Knight,0,true), new ChessPiece(ChessPieceType.Bishop,0,true), new ChessPiece(ChessPieceType.Queen,0,true), new ChessPiece(ChessPieceType.King,0,true), new ChessPiece(ChessPieceType.Bishop,1,true), new ChessPiece(ChessPieceType.Knight,1,true), new ChessPiece(ChessPieceType.Rook,1,true), new ChessPiece(ChessPieceType.Pawn,0,true), new ChessPiece(ChessPieceType.Pawn,1,true), new ChessPiece(ChessPieceType.Pawn,2,true), new ChessPiece(ChessPieceType.Pawn,3,true), new ChessPiece(ChessPieceType.Pawn,4,true), new ChessPiece(ChessPieceType.Pawn,5,true), new ChessPiece(ChessPieceType.Pawn,6,true), new ChessPiece(ChessPieceType.Pawn,7,true), null,null,null,null,null,null,null,null, null,null,null,null,null,null,null,null, null,null,null,null,null,null,null,null, null,null,null,null,null,null,null,null, new ChessPiece(ChessPieceType.Pawn,0,false), new ChessPiece(ChessPieceType.Pawn,1,false), new ChessPiece(ChessPieceType.Pawn,2,false), new ChessPiece(ChessPieceType.Pawn,3,false), new ChessPiece(ChessPieceType.Pawn,4,false), new ChessPiece(ChessPieceType.Pawn,5,false), new ChessPiece(ChessPieceType.Pawn,6,false), new ChessPiece(ChessPieceType.Pawn,7,false), new ChessPiece(ChessPieceType.Rook,0,false), new ChessPiece(ChessPieceType.Knight,0,false), new ChessPiece(ChessPieceType.Bishop,0,false), new ChessPiece(ChessPieceType.Queen,0,false), new ChessPiece(ChessPieceType.King,0,false), new ChessPiece(ChessPieceType.Bishop,1,false), new ChessPiece(ChessPieceType.Knight,1,false), new ChessPiece(ChessPieceType.Rook,1,false), }; PieceMoves.InitiateChessPieceMotion(); PieceValidMoves.GenerateValidMoves(boardInfo); Evaluation.EvaluateBoardScore(boardInfo); boardHistory.Add(new ChessBoard(boardInfo)); base.Initialize(); }
private static void GenerateValidMovesKingCastle(ChessBoard board, ChessPiece king) { if (king == null || king.Moved) { return; } if (king.PieceColor == ChessPieceColor.White && board.whiteCastled) { return; } if (king.PieceColor == ChessPieceColor.Black && board.blackCastled) { return; } if (king.PieceColor == ChessPieceColor.Black && board.blackInCheck) { return; } if (king.PieceColor == ChessPieceColor.White && board.whiteInCheck) { return; } //This code will add the castleling move to the pieces available moves if (king.PieceColor == ChessPieceColor.White) { if (board.whiteInCheck) { return; } if (board.pieces[63] != null && board.pieces[63].Identifier == ChessPieceType.Rook && board.pieces[63].PieceColor == king.PieceColor && board.pieces[62] == null && board.pieces[61] == null && BlackAttackBoard[61] == false && BlackAttackBoard[62] == false) { //Ok looks like move is valid lets add it king.ValidMoves.Push(62); WhiteAttackBoard[62] = true; } if (board.pieces[56] != null && board.pieces[56].Identifier == ChessPieceType.Rook && board.pieces[56].PieceColor == king.PieceColor && board.pieces[57] == null && board.pieces[58] == null && board.pieces[59] == null && BlackAttackBoard[58] == false && BlackAttackBoard[59] == false) { //Ok looks like move is valid lets add it king.ValidMoves.Push(58); WhiteAttackBoard[58] = true; } } else if (king.PieceColor == ChessPieceColor.Black) { if (board.blackInCheck) { return; } //There are two ways to castle, scenario 1: if (board.pieces[7] != null) { //Check if the Right Rook is still in the correct position if (board.pieces[7].Identifier == ChessPieceType.Rook && !board.pieces[7].Moved) { if (board.pieces[7].PieceColor == king.PieceColor) { //Move one column to right see if its empty if (board.pieces[6] == null) { if (board.pieces[5] == null) { if (WhiteAttackBoard[5] == false && WhiteAttackBoard[6] == false) { //Ok looks like move is valid lets add it king.ValidMoves.Push(6); BlackAttackBoard[6] = true; } } } } } } //There are two ways to castle, scenario 2: if (board.pieces[0] != null) { //Check if the Left Rook is still in the correct position if (board.pieces[0].Identifier == ChessPieceType.Rook && !board.pieces[0].Moved) { if (board.pieces[0].PieceColor == king.PieceColor) { //Move one column to right see if its empty if (board.pieces[1] == null) { if (board.pieces[2] == null) { if (board.pieces[3] == null) { if (WhiteAttackBoard[2] == false && WhiteAttackBoard[3] == false) { //Ok looks like move is valid lets add it king.ValidMoves.Push(2); BlackAttackBoard[2] = true; } } } } } } } } }
private static void GenerateValidMovesKing(ChessPiece piece, ChessBoard board, byte srcPosition) { if (piece == null) { return; } byte length = MoveArrays.KingTotalMoves[srcPosition]; for (byte i = 0; i < length; ++i) { byte dstPos = MoveArrays.KingMoves[srcPosition][i]; if (piece.PieceColor == ChessPieceColor.White) { //I can't move where I am being attacked if (BlackAttackBoard[dstPos]) { WhiteAttackBoard[dstPos] = true; continue; } } else if (WhiteAttackBoard[dstPos]) { BlackAttackBoard[dstPos] = true; continue; } AnalyzeMove(board, dstPos, piece); } }
private static void CheckValidMovesPawn(byte[] moves, ChessPiece pcMoving, byte srcPosition, ChessBoard board, byte count) { for (byte i = 0; i < count; ++i) { byte dstPos = moves[i]; // Piece in capture position if (dstPos % 8 != srcPosition % 8) { //If there is a piece there I can potentialy kill AnalyzeMovePawn(board, dstPos, pcMoving); if (pcMoving.PieceColor == ChessPieceColor.White) { WhiteAttackBoard[dstPos] = true; } else { BlackAttackBoard[dstPos] = true; } } // if there is something in front pawns can't move there else if (board.pieces[dstPos] != null) { return; } //if there is nothing in front of me (blocked == false) else { pcMoving.ValidMoves.Push(dstPos); } } }
private static void AnalyzeMovePawn(ChessBoard board, byte dstPos, ChessPiece movingPiece) { bool movingPieceIsWhite = movingPiece.PieceColor == ChessPieceColor.White; //Because Pawns only kill diagonaly we handle the En Passant scenario specialy if (board.EnPassantPosition == dstPos && board.EnPassantPosition > 0 && movingPiece.PieceColor != board.EnPassantColor) { //We have an En Passant Possible movingPiece.ValidMoves.Push(dstPos); if (movingPieceIsWhite) { WhiteAttackBoard[dstPos] = true; } else { BlackAttackBoard[dstPos] = true; } } ChessPiece pcAttacked = board.pieces[dstPos]; //If there no piece there I can potentialy kill if (pcAttacked == null) return; //Regardless of what is there I am attacking this square if (movingPieceIsWhite) { WhiteAttackBoard[dstPos] = true; //if that piece is the same color if (pcAttacked.PieceColor == movingPiece.PieceColor) { pcAttacked.DefendedValue += movingPiece.PieceActionValue; return; } pcAttacked.AttackedValue += movingPiece.PieceActionValue; //If this is a king set it in check if (pcAttacked.Identifier == ChessPieceType.King) { board.blackInCheck = true; } else { //Add this as a valid move movingPiece.ValidMoves.Push(dstPos); } } else { BlackAttackBoard[dstPos] = true; //if that piece is the same color if (pcAttacked.PieceColor == movingPiece.PieceColor) { pcAttacked.DefendedValue += movingPiece.PieceActionValue; return; } pcAttacked.AttackedValue += movingPiece.PieceActionValue; //If this is a king set it in check if (pcAttacked.Identifier == ChessPieceType.King) { board.whiteInCheck = true; } else { //Add this as a valid move movingPiece.ValidMoves.Push(dstPos); } } return; }
private static bool AnalyzeMove(ChessBoard board, byte dstPos, ChessPiece movingPiece) { //If I am not a pawn everywhere I move I can attack bool movingPieceIsWhite = movingPiece.PieceColor == ChessPieceColor.White; if (movingPieceIsWhite) { WhiteAttackBoard[dstPos] = true; } else { BlackAttackBoard[dstPos] = true; } ChessPiece pcAttacked = board.pieces[dstPos]; //If there no piece there I can potentialy kill just add the move and exit if (pcAttacked == null) { movingPiece.ValidMoves.Push(dstPos); return true; } if (pcAttacked.PieceColor != movingPiece.PieceColor) { // Different color I am attacking pcAttacked.AttackedValue += movingPiece.PieceActionValue; //If this is a king set it in check if (pcAttacked.Identifier == ChessPieceType.King) { if (movingPieceIsWhite) { board.blackInCheck = true; } else { board.whiteInCheck = true; } } else { //Add this as a valid move movingPiece.ValidMoves.Push(dstPos); } //We don't continue movement past this piece return false; } else { //Same Color I am defending pcAttacked.DefendedValue += movingPiece.PieceActionValue; //Since this piece is of my kind I can't move there return false; } }
internal static void GenerateValidMoves(ChessBoard board) { // Reset Board board.blackInCheck = false; board.whiteInCheck = false; WhiteAttackBoard = new bool[64]; BlackAttackBoard = new bool[64]; //Generate Moves for (byte x = 0; x < 64; ++x) { ChessPiece piece = board.pieces[x]; if (piece == null) continue; piece.ValidMoves = new Stack<byte>(piece.LastValidMoveCount); switch (piece.Identifier) { case ChessPieceType.Pawn: { if (piece.PieceColor == ChessPieceColor.White) { CheckValidMovesPawn(MoveArrays.WhitePawnMoves[x],piece, x, board, MoveArrays.WhitePawnTotalMoves[x]); break; } if (piece.PieceColor == ChessPieceColor.Black) { CheckValidMovesPawn(MoveArrays.BlackPawnMoves[x], piece, x, board, MoveArrays.BlackPawnTotalMoves[x]); break; } break; } case ChessPieceType.Knight: { byte length = MoveArrays.KnightTotalMoves[x]; for (byte i = 0; i < length; ++i) { AnalyzeMove(board, MoveArrays.KnightMoves[x][i], piece); } break; } case ChessPieceType.Bishop: { byte length = MoveArrays.BishopTotalMoves1[x]; for (byte i = 0; i < length; ++i) { if (!AnalyzeMove(board, MoveArrays.BishopMoves1[x][i], piece)) { break; } } length = MoveArrays.BishopTotalMoves2[x]; for (byte i = 0; i < length; ++i) { if (!AnalyzeMove(board, MoveArrays.BishopMoves2[x][i], piece)) { break; } } length = MoveArrays.BishopTotalMoves3[x]; for (byte i = 0; i < length; ++i) { if (!AnalyzeMove(board, MoveArrays.BishopMoves3[x][i], piece)) { break; } } length = MoveArrays.BishopTotalMoves4[x]; for (byte i = 0; i < length; ++i) { if (!AnalyzeMove(board, MoveArrays.BishopMoves4[x][i], piece)) { break; } } break; } case ChessPieceType.Rook: { byte length = MoveArrays.RookTotalMoves1[x]; for (byte i = 0; i < length; ++i) { if (!AnalyzeMove(board, MoveArrays.RookMoves1[x][i], piece)) { break; } } length = MoveArrays.RookTotalMoves2[x]; for (byte i = 0; i < length; ++i) { if (!AnalyzeMove(board, MoveArrays.RookMoves2[x][i], piece)) { break; } } length = MoveArrays.RookTotalMoves3[x]; for (byte i = 0; i < length; ++i) { if (!AnalyzeMove(board, MoveArrays.RookMoves3[x][i], piece)) { break; } } length = MoveArrays.RookTotalMoves4[x]; for (byte i = 0; i < length; ++i) { if (!AnalyzeMove(board, MoveArrays.RookMoves4[x][i], piece)) { break; } } break; } case ChessPieceType.Queen: { // Bishop Moves byte length = MoveArrays.BishopTotalMoves1[x]; for (byte i = 0; i < length; ++i) { if (!AnalyzeMove(board, MoveArrays.BishopMoves1[x][i], piece)) { break; } } length = MoveArrays.BishopTotalMoves2[x]; for (byte i = 0; i < length; ++i) { if (!AnalyzeMove(board, MoveArrays.BishopMoves2[x][i], piece)) { break; } } length = MoveArrays.BishopTotalMoves3[x]; for (byte i = 0; i < length; ++i) { if (!AnalyzeMove(board, MoveArrays.BishopMoves3[x][i], piece)) { break; } } length = MoveArrays.BishopTotalMoves4[x]; for (byte i = 0; i < length; ++i) { if (!AnalyzeMove(board, MoveArrays.BishopMoves4[x][i], piece)) { break; } } // Rook Moves length = MoveArrays.RookTotalMoves1[x]; for (byte i = 0; i < length; ++i) { if (!AnalyzeMove(board, MoveArrays.RookMoves1[x][i], piece)) { break; } } length = MoveArrays.RookTotalMoves2[x]; for (byte i = 0; i < length; ++i) { if (!AnalyzeMove(board, MoveArrays.RookMoves2[x][i], piece)) { break; } } length = MoveArrays.RookTotalMoves3[x]; for (byte i = 0; i < length; ++i) { if (!AnalyzeMove(board, MoveArrays.RookMoves3[x][i], piece)) { break; } } length = MoveArrays.RookTotalMoves4[x]; for (byte i = 0; i < length; ++i) { if (!AnalyzeMove(board, MoveArrays.RookMoves4[x][i], piece)) { break; } } break; } case ChessPieceType.King: { if (piece.PieceColor == ChessPieceColor.White) { whiteKingPosition = x; } else { blackKingPosition = x; } break; } } } if (board.WhoseMove == ChessPieceColor.White) { GenerateValidMovesKing(board.pieces[blackKingPosition], board, blackKingPosition); GenerateValidMovesKing(board.pieces[whiteKingPosition], board, whiteKingPosition); } else { GenerateValidMovesKing(board.pieces[whiteKingPosition], board, whiteKingPosition); GenerateValidMovesKing(board.pieces[blackKingPosition], board, blackKingPosition); } //Now that all the pieces were examined we know if the king is in check GenerateValidMovesKingCastle(board, board.pieces[whiteKingPosition]); GenerateValidMovesKingCastle(board, board.pieces[blackKingPosition]); }
internal static List<Position> EvaluateMoves(ChessBoard board, byte depth) { //We are going to store our result boards here List<Position> positions = new List<Position>(); for (byte x = 0; x < 64; ++x) { ChessPiece piece = board.pieces[x]; //Make sure there is a piece on the square //Make sure the color is the same color as the one we are moving. if (piece == null || piece.PieceColor != board.WhoseMove) continue; //For each valid move for this piece foreach (byte dst in piece.ValidMoves) { Position move = new Position(); move.SrcPosition = x; move.DstPosition = dst; ChessPiece pieceAttacked = board.pieces[move.DstPosition]; //If the move is a capture add it's value to the score if (pieceAttacked != null) { move.Score += pieceAttacked.PieceValue; if (piece.PieceValue < pieceAttacked.PieceValue) { move.Score += pieceAttacked.PieceValue - piece.PieceValue; } } if (!piece.Moved) { move.Score += 10; } move.Score += piece.PieceActionValue; //Add Score for Castling if (!board.whiteCastled && board.WhoseMove == ChessPieceColor.White) { if (piece.Identifier == ChessPieceType.King) { if (move.DstPosition != 62 && move.DstPosition != 58) { move.Score -= 40; } else { move.Score += 40; } } if (piece.Identifier == ChessPieceType.Rook) { move.Score -= 40; } } if (!board.blackCastled && board.WhoseMove == ChessPieceColor.Black) { if (piece.Identifier == ChessPieceType.King) { if (move.DstPosition != 6 && move.DstPosition != 2) { move.Score -= 40; } else { move.Score += 40; } } if (piece.Identifier == ChessPieceType.Rook) { move.Score -= 40; } } positions.Add(move); } } return positions; }
private static List<ChessBoard> getValidBoards(ChessBoard examineBoard) { List<ChessBoard> validBoards = new List<ChessBoard>(); for (byte x = 0; x < 64; ++x) { ChessPiece piece = examineBoard.pieces[x]; //Make sure there is a piece on the square //Make sure the color is the same color as the one we are moving. if (piece == null || piece.PieceColor != examineBoard.WhoseMove) continue; //For each valid move for this piece foreach (byte dst in piece.ValidMoves) { //We make copies of the board and move so that we can move it without effecting the parent board ChessBoard board = new ChessBoard(examineBoard); //Make move so we can examine it ChessEngine.MoveContent(board, x, dst, ChessPieceType.Queen); //We Generate Valid Moves for Board PieceValidMoves.GenerateValidMoves(board); //Invalid Move if (board.whiteInCheck && examineBoard.WhoseMove == ChessPieceColor.White) { continue; } //Invalid Move if (board.blackInCheck && examineBoard.WhoseMove == ChessPieceColor.Black) { continue; } //We calculate the board score Evaluation.EvaluateBoardScore(board); //Invert Score to support Negamax board.Score = SideToMoveScore(board.Score, board.WhoseMove); validBoards.Add(board); } } return validBoards; }
private static SearchResult getBestMove(ChessBoard examineBoard, List<ChessBoard> validBoards, byte depth) { int alpha = -400000000; const int beta = 400000000; SearchResult result = new SearchResult(); // Sort by score, this increases te chance we can prune moves early on validBoards.Sort(ChessBoard.Sort); //Can I make an instant mate? foreach (ChessBoard pos in validBoards) { int value = -AlphaBeta(pos, 1, -beta, -alpha); if (value >= Constants.GameOverValue) { result.alpha = value; result.bestMove = pos.LastMove; return result; } } --depth; byte plyDepthReached = ModifyDepth(depth, validBoards.Count); int currentBoard = 0; alpha = -400000000; ChessBoard bestBoard = new ChessBoard(short.MinValue); foreach (ChessBoard board in validBoards) { ++currentBoard; int value = -AlphaBeta(board, plyDepthReached, -beta, -alpha); board.Score = value; //If value is greater then alpha this is the best board if (value > alpha) { alpha = value; bestBoard = new ChessBoard(board); } } result.alpha = alpha; result.bestMove = bestBoard.LastMove; return result; }
private static int AlphaBeta(ChessBoard examineBoard, byte depth, int alpha, int beta) { if (examineBoard == null || examineBoard.pieces == null) return 0; ++nodesSearched; if (examineBoard.FiftyMove >= 50 || examineBoard.RepeatedMove >= 3) return 0; if (depth == 0) { //Evaluate Score Evaluation.EvaluateBoardScore(examineBoard); //Invert Score to support Negamax return SideToMoveScore(examineBoard.Score, examineBoard.WhoseMove); } List<Position> positions = EvaluateMoves(examineBoard,depth); int length = positions.Count; if (examineBoard.whiteInCheck || examineBoard.blackInCheck || length == 0) { if (SearchForMate(examineBoard.WhoseMove, examineBoard, ref examineBoard.blackInMate, ref examineBoard.whiteInMate, ref examineBoard.staleMate)) { if (examineBoard.blackInMate) { if (examineBoard.WhoseMove == ChessPieceColor.Black) return -Constants.GameOverValue - depth; else return Constants.GameOverValue + depth; } if (examineBoard.whiteInMate) { if (examineBoard.WhoseMove == ChessPieceColor.Black) return Constants.GameOverValue + depth; else return -Constants.GameOverValue - depth; } //If Not Mate then StaleMate return 0; } } // Sort by score, this increases te chance we can prune moves early on positions.Sort(Sort); for (int i = 0; i < length; ++i) { Position move = positions[i]; //Make a copy ChessBoard board = new ChessBoard(examineBoard); //Move Piece ChessEngine.MoveContent(board, move.SrcPosition, move.DstPosition, ChessPieceType.Queen); //We Generate Valid Moves for Board PieceValidMoves.GenerateValidMoves(board); if (board.blackInCheck && examineBoard.WhoseMove == ChessPieceColor.Black) { //Invalid Move continue; } if (board.whiteInCheck && examineBoard.WhoseMove == ChessPieceColor.White) { //Invalid Move continue; } int value = -AlphaBeta(board, (byte)(depth - 1), -beta, -alpha); if (value >= beta) { // Beta cut-off return beta; } if (value > alpha) { alpha = value; } } return alpha; }
internal static bool SearchForMate(ChessPieceColor movingSide, ChessBoard examineBoard, ref bool blackMate, ref bool whiteMate, ref bool staleMate) { bool foundNonCheckBlack = false; bool foundNonCheckWhite = false; for (byte x = 0; x < 64; ++x) { ChessPiece piece = examineBoard.pieces[x]; //Make sure there is a piece on the square //Make sure the color is the same color as the one we are moving. if (piece == null || piece.PieceColor != movingSide) continue; //For each valid move for this piece foreach (byte dst in piece.ValidMoves) { //We make copies of the board and move so we don't change the original ChessBoard board = new ChessBoard(examineBoard); //Make move so we can examine it ChessEngine.MoveContent(board, x, dst, ChessPieceType.Queen); //We Generate Valid Moves for Board PieceValidMoves.GenerateValidMoves(board); if (!board.blackInCheck) { foundNonCheckBlack = true; } else if (movingSide == ChessPieceColor.Black) { continue; } if (!board.whiteInCheck) { foundNonCheckWhite = true; } else if (movingSide == ChessPieceColor.White) { continue; } } } if (!foundNonCheckBlack) { if (examineBoard.blackInCheck) { blackMate = true; return true; } if (!examineBoard.whiteInMate && movingSide != ChessPieceColor.White) { staleMate = true; return true; } } if (!foundNonCheckWhite) { if (examineBoard.whiteInCheck) { whiteMate = true; return true; } if (!examineBoard.blackInMate && movingSide != ChessPieceColor.Black) { staleMate = true; return true; } } return false; }
/// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); if (boardInfo.WhoseMove == ChessPieceColor.Black && blackIsAI) { ++waitASecond; if (waitASecond > 5) { waitASecond = 0; ChessEngine.EngineMove(boardInfo); } /* if(boardHistory.Count >= 20) { boardHistory.RemoveAt(0); } boardHistory.Add(new ChessBoard(boardInfo)); */ } else { // Let AI play vs AI /* ++waitASecond; if (waitASecond > 5) { waitASecond = 0; ChessEngine.EngineMove(boardInfo); } * */ MouseState state = Mouse.GetState(); if (state.LeftButton == ButtonState.Pressed) { int xPos = (int)(state.X / Constants.SquareSize); int yPos = (int)(state.Y / Constants.SquareSize); if (xPos < Constants.NumberOfFiles && yPos < Constants.NumberOfRanks) { if (selectedIndex > boardInfo.pieces.Length) { byte index = (byte)(yPos * Constants.NumberOfFiles + xPos); if (boardInfo.pieces[index] != null && boardInfo.pieces[index].PieceColor == boardInfo.WhoseMove) { selectedIndex = index; } } else { byte index = (byte)(yPos * Constants.NumberOfFiles + xPos); if (index != selectedIndex) { //SourceIndex has no piece if (boardInfo.pieces[selectedIndex] == null) { return; } //Select new piece if same color if (boardInfo.pieces[index] != null && boardInfo.pieces[index].PieceColor == boardInfo.WhoseMove) { selectedIndex = index; } //Check if this is infact a valid move if (!ChessEngine.IsValidMove(boardInfo, selectedIndex, index)) { return; } ChessEngine.MovePiece(boardInfo, selectedIndex, index); selectedIndex = 99; } } } else if(undoRectangle.Contains(new Point(state.X,state.Y))) { System.Diagnostics.Debug.WriteLine("UNDO PRESSED"); selectedIndex = 99; if(boardHistory.Count > 1) { boardHistory.RemoveAt(boardHistory.Count - 1); } if(boardHistory.Count > 0) { boardInfo = new ChessBoard(boardHistory[boardHistory.Count - 1]); PieceValidMoves.GenerateValidMoves(boardInfo); } } else if (selectedIndex < boardInfo.pieces.Length) { selectedIndex = 99; } } } base.Update(gameTime); }