/// <summary> /// Allows two AI players to play against each other. Records the state of the game after each turn to /// allow the game to be replayed /// </summary> /// <param name="board"></param> private static void AiVsAi(Board board) { Square currentPlayer = Square.Red; // list for storing all subsequent states of the game List <State> states = new List <State>(); // add initial state of the game to the list State firstState = new State(board.GetState(), currentPlayer); states.Add(firstState); // initialize pointer variable and point it to the initial state of the game int pointer = 0; Ai bot = new Ai(); // continue the game as long as current player has any pieces left while (board.GetPlayersPieces(currentPlayer).Any()) { Console.WriteLine("\n\nTurn #{0} Player: {1}", pointer + 1, currentPlayer); board.PrintBoard(); // get the list of pieces belonging to current player var playersPieces = board.GetPlayersPieces(currentPlayer); // get the list of legal non-jump moves that player can make var legalMoves = board.GetLegalMoves(playersPieces); // get the list of legal jumps that player can (have to) make var legalJumps = board.GetLegalJumps(playersPieces); // if current player has no jumps and no regular moves to make, he's lost if (legalJumps.Count + legalMoves.Count == 0) { break; } State state = new State(board.GetState(), currentPlayer); // get the move from the AI player based on the current state of the board Move bestMove = bot.GetBestMove(board, state); // AI is jumping if (bestMove.IsJump) { while (legalJumps.Any()) { Piece jumpingPiece = playersPieces.Find(piece => piece.X == bestMove.FromRow && piece.Y == bestMove.FromCol); bool kingBeforeJump = jumpingPiece.IsKing; board.DoJump(bestMove, jumpingPiece); Console.WriteLine("AI's move: from {0} to {1}", bestMove.CoordinateFrom, bestMove.CoordinateTo); // update variables of the piece that has just jumped jumpingPiece.HasJustJumped = true; jumpingPiece.X = bestMove.ToRow; jumpingPiece.Y = bestMove.ToCol; // all pieces other than the one that has just jumped are irrelevant when checking if more jumps can be made playersPieces.RemoveAll(piece => piece.HasJustJumped == false); legalJumps = board.GetLegalJumps(playersPieces); // update position of the jumping piece on the board board.UpdatePosition(jumpingPiece, bestMove.FromRow, bestMove.FromCol); // no further jumps can be made if piece became a king after the first jump if (!kingBeforeJump && bestMove.ToRow == 0 | bestMove.ToRow == 7) { break; } // make a subsequent jump if there is one if (legalJumps.Any()) { bestMove = legalJumps.First(); } } } else { board.MovePiece(bestMove); Console.WriteLine("AI's move: from {0} to {1}", bestMove.CoordinateFrom, bestMove.CoordinateTo); } currentPlayer = ChangeTurn(currentPlayer); // create new state of the game after move was made State newState = new State(board.GetState(), currentPlayer); // move was made after performing undo operation since pointer is not pointing to the last state if (pointer < states.Count - 1) { // newState now becomes the last state, remove all states that happened after it states.RemoveAll(other => states.IndexOf(other) > pointer); } states.Add(newState); // set pointer to the new state pointer = states.IndexOf(newState); } Console.WriteLine("\n\n{0} player won!", ChangeTurn(currentPlayer)); // print the final state of the board once the game has ended board.PrintBoard(); // add states all subsequent states of the game to the list of previous games previousGames.Add(states); Console.WriteLine("Replay the game? Plase answer Y/N"); string answer = Console.ReadLine(); while (!answer.Equals("y") && !answer.Equals("n")) { Console.WriteLine("Please type 'Y' to replay the game or 'N' to skip"); answer = Console.ReadLine(); } if (answer.Equals("y")) { ReplayGame(states); } }
/// <summary> /// Allows human player to play against AI player. Records the state of the game after each turn to provide /// undo/redo/replay functionalities /// </summary> /// <param name="board"></param> private static void HumanVsAi(Board board) { Square currentPlayer = Square.Red; // list for storing all subsequent states of the game List <State> states = new List <State>(); // add initial state of the game to the list State firstState = new State(board.GetState(), currentPlayer); states.Add(firstState); // initialize pointer variable and point it to the initial state of the game int pointer = 0; Ai bot = new Ai(); // continue the game as long as current player has any pieces left while (board.GetPlayersPieces(currentPlayer).Any()) { Console.WriteLine("\n\nTurn #{0} Player: {1}", pointer + 1, currentPlayer); board.PrintBoard(); // get the list of pieces belonging to current player var playersPieces = board.GetPlayersPieces(currentPlayer); // get the list of legal non-jump moves that player can make var legalMoves = board.GetLegalMoves(playersPieces); // get the list of legal jumps that player can (have to) make var legalJumps = board.GetLegalJumps(playersPieces); // if current player has no jumps and no regular moves to make, he's lost if (legalJumps.Count + legalMoves.Count == 0) { break; } // human player's turn if (currentPlayer == Square.Red) { Console.WriteLine("What would you like to do? Type 'Undo', 'Redo', or press enter to carry on"); var choice = Console.ReadLine(); if (choice.Equals("undo", StringComparison.CurrentCultureIgnoreCase)) { // check whether there were any states before current state if (pointer > 0) { pointer -= 2; // get a deep copy of the previous state of the game State previousState = states[pointer].DeepCopy(); //Console.WriteLine("RESTORED STATE: " + pointer); // set previous state of the game to be the current state and reverse player's turn board.SetState(previousState.BoardState); currentPlayer = previousState.CurrentPlayer; } else { Console.WriteLine("You can't go back any further"); } } else if (choice.Equals("redo", StringComparison.CurrentCultureIgnoreCase)) { // check whether there were any states after current state if (pointer < states.Count - 1) { pointer += 2; // get a deep copy of the next state of the game State redoState = states[pointer].DeepCopy(); //Console.WriteLine("RESTORED STATE: " + pointer); // set next state of the game to be the current state and reverse player's turn board.SetState(redoState.BoardState); currentPlayer = redoState.CurrentPlayer; } else { Console.WriteLine("There are no moves to redo"); } } else { var move = RequestMove(); // no jumps can be made so a regular move has to be made if (!legalJumps.Any()) { while (!legalMoves.Contains(move)) { Console.WriteLine("--------------------Please provide a legal move--------------------"); move = RequestMove(); } // move can be made as it's in the list of legal moves, perform it board.MovePiece(move); } // force the player to make a jump while (legalJumps.Any()) { // see if player's move matches any of the possible jumps if (legalJumps.Contains(move)) { // get reference to the piece that will be jumping Piece jumpingPiece = playersPieces.Find(piece => piece.X == move.FromRow && piece.Y == move.FromCol); bool kingBeforeJump = jumpingPiece.IsKing; board.DoJump(move, jumpingPiece); // update variables of the piece that has just jumped jumpingPiece.HasJustJumped = true; jumpingPiece.X = move.ToRow; jumpingPiece.Y = move.ToCol; // all pieces other than the one that has just jumped are irrelevant when checking if more jumps can be made playersPieces.RemoveAll(piece => piece.HasJustJumped == false); legalJumps = board.GetLegalJumps(playersPieces); // update position of the jumping piece on the board board.UpdatePosition(jumpingPiece, move.FromRow, move.FromCol); // show the state of the board after first jump if another one can be made if (legalJumps.Any()) { board.PrintBoard(); } // no further jumps can be made if piece became a king after the first jump if (!kingBeforeJump && move.ToRow == 0 | move.ToRow == 7) { break; } } else { Console.WriteLine("--------------------You have to jump--------------------"); move = RequestMove(); } } // change turn currentPlayer = ChangeTurn(currentPlayer); // create new state of the game after move was made State newState = new State(board.GetState(), currentPlayer); // move was made after performing undo operation since pointer is not pointing to the last state if (pointer < states.Count - 1) { // newState now becomes the last state, remove all states that happened after it states.RemoveAll(other => states.IndexOf(other) > pointer); } states.Add(newState); // set pointer to the new state pointer = states.IndexOf(newState); } } // AI player's turn else if (currentPlayer == Square.White) { State state = new State(board.GetState(), currentPlayer); // get the move from the AI player based on the current state of the board Move bestMove = bot.GetBestMove(board, state); // AI is jumping if (bestMove.IsJump) { while (legalJumps.Any()) { Piece jumpingPiece = playersPieces.Find(piece => piece.X == bestMove.FromRow && piece.Y == bestMove.FromCol); bool kingBeforeJump = jumpingPiece.IsKing; board.DoJump(bestMove, jumpingPiece); Console.WriteLine("AI's move from {0} to {1}", bestMove.CoordinateFrom, bestMove.CoordinateTo); // update variables of the piece that has just jumped jumpingPiece.HasJustJumped = true; jumpingPiece.X = bestMove.ToRow; jumpingPiece.Y = bestMove.ToCol; // all pieces other than the one that has just jumped are irrelevant when checking if more jumps can be made playersPieces.RemoveAll(piece => piece.HasJustJumped == false); legalJumps = board.GetLegalJumps(playersPieces); // update position of the jumping piece on the board board.UpdatePosition(jumpingPiece, bestMove.FromRow, bestMove.FromCol); // no further jumps can be made if piece became a king after the first jump if (!kingBeforeJump && bestMove.ToRow == 0 | bestMove.ToRow == 7) { break; } // make a subsequent jump if there is one if (legalJumps.Any()) { bestMove = legalJumps.First(); } } } else { board.MovePiece(bestMove); Console.WriteLine("AI's move from {0} to {1}", bestMove.CoordinateFrom, bestMove.CoordinateTo); } currentPlayer = ChangeTurn(currentPlayer); // create new state of the game after move was made State newState = new State(board.GetState(), currentPlayer); // move was made after performing undo operation since pointer is not pointing to the last state if (pointer < states.Count - 1) { // newState now becomes the last state, remove all states that happened after it states.RemoveAll(other => states.IndexOf(other) > pointer); } states.Add(newState); // set pointer to the new state pointer = states.IndexOf(newState); } } Console.WriteLine("\n\n{0} player won!", ChangeTurn(currentPlayer)); // print the final state of the board once the game has ended board.PrintBoard(); // add states all subsequent states of the game to the list of previous games previousGames.Add(states); Console.WriteLine("Replay the game? Plase answer Y/N"); string answer = Console.ReadLine(); while (!answer.Equals("y") && !answer.Equals("n")) { Console.WriteLine("Please type 'Y' to replay the game or 'N' to skip"); answer = Console.ReadLine(); } if (answer.Equals("y")) { ReplayGame(states); } }