public override CheckersMove NextMove(CheckersGame game) { const int minValue = int.MaxValue; int maxValue = int.MinValue; CheckersMove bestMove = null; // Enumerate all moves foreach (CheckersMove move in game.EnumLegalMoves()) { if (!game.IsPlaying) { break; } CheckersGame nextGameState = game.Clone(); nextGameState.MovePiece(move.Clone(nextGameState)); int curValue = minMove(game, nextGameState, 1, maxValue, minValue); if ((curValue > maxValue) || (bestMove == null)) { maxValue = curValue; bestMove = move; } OnTick(game); } return(bestMove); }
public void Evaluate_ChromosomeForwardMoveAndCanCaptureAnotherOne_Fitness2() { var board = new CheckersBoard(8); var target = new CheckersFitness(board); var move = new CheckersMove(new CheckersPiece(CheckersPlayer.PlayerOne) { CurrentSquare = new CheckersSquare(3, 2) }, new CheckersSquare(4, 3)); Assert.IsTrue(board.MovePiece(move)); move = new CheckersMove(new CheckersPiece(CheckersPlayer.PlayerTwo) { CurrentSquare = new CheckersSquare(6, 5) }, new CheckersSquare(5, 4)); Assert.IsTrue(board.MovePiece(move)); var chromosome = new CheckersChromosome(2, 8); chromosome.Moves.Clear(); chromosome.Moves.Add(new CheckersMove(new CheckersPiece(CheckersPlayer.PlayerOne) { CurrentSquare = new CheckersSquare(4, 3) }, new CheckersSquare(6, 5))); target.Update(chromosome); Assert.AreEqual(2, target.Evaluate(chromosome)); }
public void MovePiece_ValidMove_True() { var target = new CheckersBoard(8); // Move to occupied square to right side. var move = new CheckersMove(new CheckersPiece(CheckersPlayer.PlayerOne) { CurrentSquare = new CheckersSquare(3, 2) }, new CheckersSquare(4, 3)); Assert.IsTrue(target.MovePiece(move)); move = new CheckersMove(new CheckersPiece(CheckersPlayer.PlayerTwo) { CurrentSquare = new CheckersSquare(6, 5) }, new CheckersSquare(5, 4)); Assert.IsTrue(target.MovePiece(move)); move = new CheckersMove(new CheckersPiece(CheckersPlayer.PlayerOne) { CurrentSquare = new CheckersSquare(4, 3) }, new CheckersSquare(6, 5)); Assert.IsTrue(target.MovePiece(move)); move = new CheckersMove(new CheckersPiece(CheckersPlayer.PlayerTwo) { CurrentSquare = new CheckersSquare(5, 6) }, new CheckersSquare(7, 4)); Assert.IsTrue(target.MovePiece(move)); }
public override CheckersMove NextMove(CheckersGame game) { int maxJumps = 0; CheckersPiece[] movables = game.EnumMovablePieces(); ArrayList possibleMoves = new ArrayList(movables.Length); foreach (CheckersPiece movable in movables) { possibleMoves.Add(game.BeginMove(movable)); } // Get all possible jump combos ArrayList finishedMoves = new ArrayList(); while (possibleMoves.Count > 0) { CheckersMove move = (CheckersMove)possibleMoves[0]; possibleMoves.RemoveAt(0); Point[] points = move.EnumMoves(); if (points.Length == 0) { // Move is complete; add to finished moves and test for current max jumps finishedMoves.Add(move); if (maxJumps < move.Jumped.Length) { maxJumps = move.Jumped.Length; } continue; } // Enumerate all moves from this point and append them to the possible moves array foreach (Point p in points) { CheckersMove next = move.Clone(); next.Move(p); possibleMoves.Add(next); } } // Get list of max jumps ArrayList moveList = new ArrayList(); foreach (CheckersMove move in finishedMoves) { if (move.Jumped.Length != maxJumps) { continue; } moveList.Add(move); } // Choose at random between any path with same number of jumps if (moveList.Count == 0) { return(null); } return((CheckersMove)moveList[rand.Next(moveList.Count)]); }
public override CheckersMove NextMove(CheckersGame game) { CheckersPiece[] movable = game.EnumMovablePieces(); CheckersMove move = game.BeginMove(movable[rand.Next(movable.Length)]); while (move.MustMove) { Point[] moves = move.EnumMoves(); move.Move(moves[rand.Next(moves.Length)]); } return(move); }
private void handleEndOfMove(Button i_ButtonStartOfMove, Button i_ButtonClicked) { int colOfStartButton = (i_ButtonStartOfMove.Left - m_Board[0, 0].Location.X) / k_ButtonSize; int rowOfStartButton = (i_ButtonStartOfMove.Location.Y - m_Board[0, 0].Location.Y) / k_ButtonSize; int colOfButtonClicked = (i_ButtonClicked.Left - m_Board[0, 0].Location.X) / k_ButtonSize; int rowOfButtonClicked = (i_ButtonClicked.Location.Y - m_Board[0, 0].Location.Y) / k_ButtonSize; bool theClickedButtonIsTheSameAsStartButtom = i_ButtonStartOfMove.Equals(i_ButtonClicked); if (theClickedButtonIsTheSameAsStartButtom) { i_ButtonStartOfMove.BackColor = Color.White; m_MouseDown = false; } else { CheckersMove move = new CheckersMove( rowOfStartButton, colOfStartButton, rowOfButtonClicked, colOfButtonClicked); eMoveStatusCode moveStatusCode = m_CheckersData.CheckIfMoveIsValid(move); switch (moveStatusCode) { case eMoveStatusCode.InvalidPosition: showTryAgainMessage("Invalid move"); break; case eMoveStatusCode.MustEat: showTryAgainMessage("Eating Move is available"); break; case eMoveStatusCode.Successful: m_CheckersData.DoMakeMove(move); break; default: break; } i_ButtonStartOfMove.BackColor = Color.White; m_MouseDown = false; } }
private void initLPieceLocations(CheckersPiece.ePieceType i_PieceType) { int sumOfRowsToLocate = (r_BoardSize / 2) - 1; CheckersMove currentMove = new CheckersMove(this); for (int row = 0; row < sumOfRowsToLocate; row++) { int currentRow = (i_PieceType == CheckersPiece.ePieceType.X) ? row + sumOfRowsToLocate + 2 : row; int curretnColumn = (currentRow % 2 == 0) ? 1 : 0; for (int column = curretnColumn; column < r_BoardSize; column += 2) { r_CheckersBoard[currentRow, column].Piece = new CheckersPiece(i_PieceType, new int[2] { currentRow, column }); currentMove.UpdatePossibleSimpleMoves(r_CheckersBoard[currentRow, column].Piece); } } }
public void MoveCurrentPieceTo(SquareController square) { if (m_lastSelectedPiece != null && m_lastSelectedPiece.CurrentSquare.Model.CurrentPiece != null) { var move = new CheckersMove(m_lastSelectedPiece.CurrentSquare.Model.CurrentPiece, square.Model); var fitness = GAController.Instance.Fitness; if (fitness.Board.GetMoveKind(move) == CheckersMoveKind.Invalid) { HudController.IsInvalidMove = true; } else { HudController.IsInvalidMove = false; fitness.Board.MovePiece(move); GAController.Instance.MovePiece(); } } }
int maxMove(CheckersGame initGame, CheckersGame curGame, int depth, int alpha, int beta) { // Check algorithm limits..end prematurely, but with an educated approximation if (doCutOff(initGame, curGame, depth)) { return(doCalculateStrength(initGame, curGame)); } // Make move with all possibilities foreach (CheckersMove move in curGame.EnumLegalMoves()) { // Create next move CheckersGame nextGameState = move.Game.Clone(); CheckersMove nextMoveState = move.Clone(nextGameState); // Make next move and search move space if (!nextGameState.MovePiece(nextMoveState)) { continue; } int value = minMove(initGame, nextGameState, depth + 1, alpha, beta); if (value > alpha) { // Get new max value alpha = value; } if (alpha > beta) { // Return max value with pruning return(beta); } } // Return alpha (max value) return(alpha); }
/// <summary> /// Get all of the horizontal moves. The vertical moves are dependant on the vertical modifier. The direction of the hotizontal move is dependant on the modifier /// </summary> /// <param name="currentLocation">The current location.</param> /// <param name="checkerBoard">The checker board.</param> /// <param name="oneAdjacentRow">The one adjacent row.</param> /// <param name="verticalModifier">The vertical modifier.</param> /// <param name="horizontalModifier">The horizontal modifier.</param> /// <returns>List of moves</returns> private List <CheckersMove> ProcessBoardHorizontal(CheckersPoint currentLocation, CheckerBoard checkerBoard, int oneAdjacentRow, int verticalModifier, int horizontalModifier) { List <CheckersMove> list = new List <CheckersMove>(); int adjacentCol = currentLocation.Column + (1 * horizontalModifier); //Check our bounds if (adjacentCol >= 0 && adjacentCol < 8) { CheckerPiece possibleCheckerOnPossiblePoint = checkerBoard.BoardArray[oneAdjacentRow][adjacentCol].CheckersPoint.Checker; if (possibleCheckerOnPossiblePoint == null || possibleCheckerOnPossiblePoint is NullCheckerPiece) { //we can go here list.Add(new CheckersMove(currentLocation, new CheckersPoint(oneAdjacentRow, adjacentCol))); } else { //can we jump this guy? if ((possibleCheckerOnPossiblePoint is IRedPiece && this is IBlackPiece) || (possibleCheckerOnPossiblePoint is IBlackPiece && this is IRedPiece)) { //go another row up and another column to the right int twoAdjacentRow = oneAdjacentRow + (1 * verticalModifier); int twoColAdjacent = adjacentCol + (1 * horizontalModifier); //Check bounds if (twoColAdjacent >= 0 && twoColAdjacent < 8 && twoAdjacentRow >= 0 && twoAdjacentRow < 8) { CheckerPiece possibleCheckerOnPossibleJumpPoint = checkerBoard.BoardArray[twoAdjacentRow][twoColAdjacent].CheckersPoint.Checker; if (possibleCheckerOnPossibleJumpPoint == null || possibleCheckerOnPossibleJumpPoint is NullCheckerPiece) { //we can go here CheckersMove jumpMove = new CheckersMove(currentLocation, new CheckersPoint(twoAdjacentRow, twoColAdjacent), new CheckersPoint(oneAdjacentRow, adjacentCol)); //This is a jump move //Get all possible moves for destination point //For each possible move that is a jump move, make a new move and link it //make the move on a temp clone of the board and pass that to find any more multimoves CheckerBoard clonedBoard = (CheckerBoard)checkerBoard.GetMinimaxClone(); clonedBoard.MakeMoveOnBoard((CheckersMove)jumpMove.GetMinimaxClone(), false); List <CheckersMove> movesAfterJump = this.GetPossibleMoves(jumpMove.DestinationPoint, clonedBoard); List <CheckersMove> processedList = GetJumpMoves(movesAfterJump); if (processedList.Count > 0) { foreach (CheckersMove move in processedList) { CheckersMove clonedMove = (CheckersMove)jumpMove.GetMinimaxClone(); clonedMove.NextMove = move; list.Add(clonedMove); } } else { list.Add(jumpMove); } } } } } } return(list); }
/// <summary> /// Sends the player's move to the opponent's game. /// </summary> private void DoMovePieceNet(CheckersMove move) { try { BinaryWriter bw = new BinaryWriter(new NetworkStream(remotePlayer.Socket, false)); bw.Write((byte)ClientMessage.MakeMove); bw.Write(move.InitialPiece.Location.X); bw.Write(move.InitialPiece.Location.Y); bw.Write(move.Path.Length); foreach(Point point in move.Path) { bw.Write(point.X); bw.Write(point.Y); } bw.Close(); } catch(IOException) { AppendMessage("", "Connection closed"); CloseNetGame(); remotePlayer = null; } catch(SocketException ex) { AppendMessage("", "Disconnected from opponent: " + ex.Message); CloseNetGame(); remotePlayer = null; } catch(InvalidOperationException ex) { AppendMessage("", "Disconnected from opponent: " + ex.Message); CloseNetGame(); remotePlayer = null; } }
public void MovePiece_InvalidMove_False() { var target = new CheckersBoard(8); // Horizontal move. var move = new CheckersMove(new CheckersPiece(CheckersPlayer.PlayerOne) { CurrentSquare = new CheckersSquare(1, 0) }, new CheckersSquare(3, 0)); Assert.IsFalse(target.MovePiece(move)); // Vertical move. move = new CheckersMove(new CheckersPiece(CheckersPlayer.PlayerOne) { CurrentSquare = new CheckersSquare(1, 0) }, new CheckersSquare(1, 2)); Assert.IsFalse(target.MovePiece(move)); // Back move. move = new CheckersMove(new CheckersPiece(CheckersPlayer.PlayerOne) { CurrentSquare = new CheckersSquare(2, 3) }, new CheckersSquare(1, 2)); Assert.IsFalse(target.MovePiece(move)); // Move to occupied square to right side. move = new CheckersMove(new CheckersPiece(CheckersPlayer.PlayerOne) { CurrentSquare = new CheckersSquare(1, 2) }, new CheckersSquare(2, 3)); Assert.IsTrue(target.MovePiece(move)); move = new CheckersMove(new CheckersPiece(CheckersPlayer.PlayerOne) { CurrentSquare = new CheckersSquare(2, 3) }, new CheckersSquare(3, 4)); Assert.IsTrue(target.MovePiece(move)); move = new CheckersMove(new CheckersPiece(CheckersPlayer.PlayerOne) { CurrentSquare = new CheckersSquare(3, 4) }, new CheckersSquare(4, 5)); // Occupied. Assert.IsFalse(target.MovePiece(move)); // Move to occupied square to left side. move = new CheckersMove(new CheckersPiece(CheckersPlayer.PlayerOne) { CurrentSquare = new CheckersSquare(7, 2) }, new CheckersSquare(6, 3)); Assert.IsTrue(target.MovePiece(move)); move = new CheckersMove(new CheckersPiece(CheckersPlayer.PlayerOne) { CurrentSquare = new CheckersSquare(6, 3) }, new CheckersSquare(5, 4)); Assert.IsTrue(target.MovePiece(move)); move = new CheckersMove(new CheckersPiece(CheckersPlayer.PlayerOne) { CurrentSquare = new CheckersSquare(5, 4) }, new CheckersSquare(6, 5)); // Occupied. Assert.IsFalse(target.MovePiece(move)); // Move more than 1 square not capturing. move = new CheckersMove(new CheckersPiece(CheckersPlayer.PlayerOne) { CurrentSquare = new CheckersSquare(1, 2) }, new CheckersSquare(3, 4)); Assert.IsFalse(target.MovePiece(move)); }
/// <summary>Stops a decided game or forces a game-in-progress to stop prematurely with no winner.</summary> public void Stop() { if(isReadOnly) throw new InvalidOperationException("Game is read only."); isPlaying = false; pieces.Clear(); for(int y = 0; y < BoardSize.Height; y++) for(int x = 0; x < BoardSize.Width; x++) board[x, y] = null; lastMove = null; winner = 0; turn = 0; if(GameStopped != null) GameStopped(this, EventArgs.Empty); }
/// <summary>Begins the checkers game.</summary> public void Play() { if(isReadOnly) throw new InvalidOperationException("Game is read only."); if(isPlaying) throw new InvalidOperationException("Game has already started."); Stop(); isPlaying = true; for(int y = BoardSize.Height - 1; y >= 5; y--) { for(int x = 0; x < BoardSize.Width; x++) { if((x % 2) == (y % 2)) continue; CheckersPiece piece = new CheckersPiece(this, 1, CheckersRank.Pawn, new Point(x, y), true); board[x, y] = piece; pieces.Add(piece); } } for(int y = 0; y < 3; y++) { for(int x = 0; x < BoardSize.Width; x++) { if((x % 2) == (y % 2)) continue; CheckersPiece piece = new CheckersPiece(this, 2, CheckersRank.Pawn, new Point(x, y), true); board[x, y] = piece; pieces.Add(piece); } } // Set player's turn turn = firstMove; lastMove = null; if(GameStarted != null) GameStarted(this, EventArgs.Empty); }
/// <summary>Moves a Checkers piece on the board.</summary> /// <param name="piece">The checkers piece to move.</param> /// <param name="path">The the location for the piece to be moved to, and the path taken to get there.</param> /// <returns>True if the piece was moved successfully.</returns> public bool MovePiece(CheckersPiece piece, Point[] path) { if(isReadOnly) throw new InvalidOperationException("Game is read only."); if(!isPlaying) throw new InvalidOperationException("Operation requires game to be playing."); // Check for valid move CheckersMove move = IsMoveValidCore(piece, path); // Remove jumped pieces foreach(CheckersPiece jumped in move.Jumped) { if(board[jumped.Location.X, jumped.Location.Y] == jumped) board[jumped.Location.X, jumped.Location.Y] = null; pieces.Remove(jumped); jumped.RemovedFromPlay(); } // Move the piece on board board[piece.Location.X, piece.Location.Y] = null; board[move.CurrentLocation.X, move.CurrentLocation.Y] = piece; piece.Moved(move.CurrentLocation); // King a pawn if reached other end of board if(move.Kinged) piece.Promoted(); // Remember last move lastMove = move; // Update player's turn int prevTurn = turn; if(++turn > PlayerCount) turn = 1; // Check for win by removal of opponent's pieces or by no turns available this turn if((EnumPlayerPieces(prevTurn).Length == 0) || (EnumMovablePieces().Length == 0)) DeclareWinner(prevTurn); else if(TurnChanged != null) TurnChanged(this, EventArgs.Empty); return true; }
/// <summary>Moves a Checkers piece on the board.</summary> /// <param name="move">The movement object to which the piece will move to.</param> /// <returns>True if the piece was moved successfully.</returns> public bool MovePiece(CheckersMove move) { if(isReadOnly) throw new InvalidOperationException("Game is read only."); if(move == null) return false; return MovePiece(move.Piece, move.Path); }
/// <summary>Returns whether or not a move is valid.</summary> /// <param name="move">The CheckersMove object to check.</param> /// <returns>True if the move is valid.</returns> public bool IsValidMove(CheckersMove move) { if(move == null) return false; return IsValidMove(move.Piece, move.Path); }
/// <summary>Returns a list of movable pieces this turn.</summary> /// <param name="optionalJumping">Overrides the game's OptionalJumping parameter for the enumeration.</param> /// <returns>A list of pieces that can be moved this turn.</returns> public CheckersPiece[] EnumMovablePieces(bool optionalJumping) { if((!isPlaying) && (winner == 0)) throw new InvalidOperationException("Operation requires game to be playing."); ArrayList movable = new ArrayList(); foreach(CheckersPiece piece in EnumPlayerPieces(turn)) { CheckersMove move = new CheckersMove(this, piece, false); if(move.EnumMoves(optionalJumping).Length != 0) movable.Add(piece); } return (CheckersPiece[])movable.ToArray(typeof(CheckersPiece)); }
/// <summary> /// Runs the minimax algoritm with alpha beta pruning /// </summary> /// <param name="board">The board.</param> /// <param name="depth">The depth.</param> /// <param name="alpha">The alpha.</param> /// <param name="beta">The beta.</param> /// <param name="isMax">if set to <c>true</c> [is maximum].</param> /// <param name="rootPlayer">The root player.</param> /// <returns>Minimax value for this board state</returns> private static int Minimax(CheckerBoard board, int depth, int alpha, int beta, bool isMax, PlayerColor rootPlayer) { List <CheckersMove> possibleMoves = board.GetMovesForPlayer(); if (depth == 0 || possibleMoves.Count == 0) { return(Score(board, rootPlayer)); } int value = 0; if (isMax) { value = int.MinValue; foreach (CheckersMove move in possibleMoves) { CheckersMove moveToMake = move; CheckerBoard boardToMakeMoveOn = board; do { boardToMakeMoveOn = (CheckerBoard)boardToMakeMoveOn.GetMinimaxClone(); boardToMakeMoveOn.MakeMoveOnBoard((CheckersMove)moveToMake.GetMinimaxClone()); moveToMake = moveToMake.NextMove; }while (moveToMake != null); int result = Minimax(boardToMakeMoveOn, depth - 1, alpha, beta, false, rootPlayer); value = Math.Max(result, value); alpha = Math.Max(alpha, value); if (alpha >= beta) { Logger.Debug("Branch was pruned"); break; } } } else { value = int.MaxValue; foreach (CheckersMove move in possibleMoves) { CheckersMove moveToMake = move; CheckerBoard boardToMakeMoveOn = board; do { boardToMakeMoveOn = (CheckerBoard)boardToMakeMoveOn.GetMinimaxClone(); boardToMakeMoveOn.MakeMoveOnBoard((CheckersMove)moveToMake.GetMinimaxClone()); moveToMake = moveToMake.NextMove; }while (moveToMake != null); int result = Minimax(boardToMakeMoveOn, depth - 1, alpha, beta, true, rootPlayer); value = Math.Min(result, value); beta = Math.Min(alpha, value); if (alpha >= beta) { Logger.Debug("Branch was pruned"); break; } } } return(value); }
/// <summary> /// Initial minimax starting method. This method kicks off the algoritm and finds the best move for the current player. /// If two or more moves have the same value, the best move is choosen randomly from the moves /// </summary> /// <param name="board">The board.</param> /// <returns>Best move for the current player</returns> public static CheckersMove MinimaxStart(CheckerBoard board) { int alpha = int.MinValue; int beta = int.MaxValue; thinking = true; List <CheckersMove> possibleMoves = board.GetMovesForPlayer(); List <int> values = new List <int>(); Logger.Info(string.Format("Max is {0}", board.CurrentPlayerTurn)); if (possibleMoves.IsNullOrEmpty()) { return(null); } foreach (CheckersMove move in possibleMoves) { CheckersMove moveToMake = move; CheckerBoard boardToMakeMoveOn = board; do { Logger.Debug("Board Before"); Logger.Debug(boardToMakeMoveOn.ToString()); boardToMakeMoveOn = (CheckerBoard)boardToMakeMoveOn.GetMinimaxClone(); boardToMakeMoveOn.MakeMoveOnBoard((CheckersMove)moveToMake.GetMinimaxClone()); moveToMake = moveToMake.NextMove; Logger.Debug("Board After"); Logger.Debug(boardToMakeMoveOn.ToString()); }while (moveToMake != null); values.Add(Minimax(boardToMakeMoveOn, Settings.AIDepth - 1, alpha, beta, false, board.CurrentPlayerTurn)); } int maxHeuristics = int.MinValue; foreach (int value in values) { if (value >= maxHeuristics) { maxHeuristics = value; } } //filter the list of moves based on max value List <CheckersMove> bestMoves = new List <CheckersMove>(); for (int i = 0; i < values.Count; i++) { if (values[i] == maxHeuristics) { bestMoves.Add(possibleMoves[i]); } } counter = 0; thinking = false; Logger.Info("Node Values: " + string.Join(",", values.Select(x => x.ToString()).ToArray())); return(bestMoves[Rng.Next(bestMoves.Count)]); }