/// <summary> /// This function is for handling any checker piece actions. /// Function take a checkers piece as parameter, and set it as the active game piece. /// Function will also make the piece determine all its possible moves. /// </summary> /// <param name="activePiece">A piece to do an action on</param> public void doGamePieceAction(CheckersPiece activePiece) { if (activePiece.getCaptureStatus() == false && activePiece.getColor() == turnColor) { activeGamePiece = activePiece; activePiece.determineMoves(gameBoard, this); } }
/// <summary> /// Function that is called whenever it is the turn of the AI to do its move /// </summary> public void doAiMove() { if (didAiMove == false) { bool onlyOneMove = false; //Check if theres only 1 moveable piece if (currentState.moveablePieces.Count == 1) { //If there only 1 moveable piece and only 1 available action, set best move to that move if (currentState.moveablePieces.First().getPossibleMoves().Count == 1) { bestMove = currentState.moveablePieces.First().getPossibleMoves().First(); onlyOneMove = true; Console.WriteLine("Only one move was available - Alpha-beta wasn't required" + "\n--------------------------------------------------------"); } } //If there is more than one move run algorithm if (onlyOneMove == false) { int bestMoveValue = AlphaBetaSearch(new CheckersGameState(currentState)); //if the algorithm determines that the AI will win or lose regardless of which move, //then make the ai do the first possible move it can if (bestMoveValue == MIN_INT || bestMoveValue == MAX_INT) { bestMove = currentState.moveablePieces.First().getPossibleMoves()[0]; } //if algorithm took 50 or more seconds to run, it has reach time cutoff if ((endTime - startTime).TotalSeconds >= 55) { Console.Write("Tree reached time cutoff of 55 seconds" + "\n--Max Depth: " + maxDepth + "\n--Cut Off Depth: " + (cutoff + iterativeDepth)); //Reached time cutoff - reduce the cutoff by 1/4 float actualCutoff = 0.75f * (cutoff + iterativeDepth); iterativeDepth = (((int)actualCutoff - cutoff) > 0) ? (int)actualCutoff - cutoff : 0; } //Else if maxDepth is equal to the cutoff depth, that means the tree reached cutoff level else if (maxDepth == cutoff + iterativeDepth) { Console.Write("Tree reached cut off" + "\n--Cut Off Depth: " + (cutoff + iterativeDepth)); //Since alpha-beta was able to finish in reasonable time (< 50s) // and the cutoff was reached, increased by 1 + (1/4)number of turns passed iterativeDepth = 1 + (int)(currentState.numTurnsPassed * 0.25); } //else the tree completed before reaching cutoff else { Console.Write("Tree completed before reaching cut off" + "\n--Max Depth: " + maxDepth + "\n--Cut Off Depth: " + (cutoff + iterativeDepth)); } Console.WriteLine("\n--Nodes Generated: " + nodes + "\n--# times pruning occured in MAX-VALUE: " + maxPruned + "\n--# times pruning occured in MIN-VALUE: " + minPruned + "\nFound Move in: " + (endTime - startTime).TotalSeconds + "seconds\n--------------------------------------------------------"); //AI is completed sleep the thread Thread.Sleep(1000); } //Do the actual move CheckersPiece movePiece = bestMove.movePiece; currentState.doGamePieceAction(currentState.getPiece(movePiece.getColor(), movePiece.position)); //Set now to when the delay for the AI to actually do the move to now didAiMove = true; aiMoveStart = DateTime.Now; } else { //If the delay for an AI to do the move has been reached do the move if ((DateTime.Now - aiMoveStart).TotalSeconds > aiTimeDelay) { if (currentState.doTileAction(currentState.gameBoard.getTileAt(bestMove.destinationPosition)) == true) { currentState.activeGamePiece.Update(currentState); didAiMove = false; } } } }
/// <summary> /// Function that handles all drawings in the game /// This function is called everytime after an update /// </summary> /// <param name="spriteBatch">Spritebatch initialized by main</param> public void Draw(SpriteBatch spriteBatch) { spriteBatch.Begin(); //Draw the board currentState.gameBoard.Draw(spriteBatch, checkerGameBoardTexture); //Draw all white pieces foreach (CheckersPiece piece in currentState.whiteGamePieces) { if (piece.getCaptureStatus() == false) { piece.Draw(spriteBatch, whitePieceTexture); } } //Draw all black pieces foreach (CheckersPiece piece in currentState.blackGamePieces) { if (piece.getCaptureStatus() == false) { piece.Draw(spriteBatch, blackPieceTexture); } } //Draw the active game piece marking CheckersPiece active = currentState.activeGamePiece; if (active != null) { if (active.getColor() == PieceColor.White) { currentState.activeGamePiece.Draw(spriteBatch, activePieceTexture2, true); } else { currentState.activeGamePiece.Draw(spriteBatch, activePieceTexture, true); } } //Draw any marked tiles BoardTile[,] tiles = currentState.gameBoard.getTiles(); for (int x = 0; x < CheckersBoard.MAX_HORIZONTAL_TILES; x++) { for (int y = 0; y < CheckersBoard.MAX_VERTICAL_TILES; y++) { if (tiles[x, y].getStatus() == TileStatus.MOVE) { tiles[x, y].Draw(spriteBatch, moveTileTexture); } else if (tiles[x, y].getStatus() == TileStatus.JUMP) { tiles[x, y].Draw(spriteBatch, jumpTileTexture); } } } //Draw the text and buttons for the UI spriteBatch.DrawString(textFont, "Select a color to start a new game", new Vector2(10, 610), Color.Bisque); spriteBatch.Draw(blackButtonTexture, blackButton, Color.White); spriteBatch.Draw(whiteButtonTexture, whiteButton, Color.White); //Below displays the player's turn, or the winner if there exists if (currentState.winner == PieceColor.None && currentState.turnColor != PieceColor.None) { String message = currentState.turnColor + " turn"; spriteBatch.DrawString(font, message, new Vector2(400, 630), Color.Bisque); } else { if (currentState.winner == PieceColor.Black) { String message = "Black Wins!"; spriteBatch.DrawString(font, message, new Vector2(385, 630), Color.Red); } if (currentState.winner == PieceColor.White) { String message = "White Wins!"; spriteBatch.DrawString(font, message, new Vector2(385, 630), Color.Blue); } } spriteBatch.End(); }