Example #1
0
        /// <summary>
        /// Function to evaluate the value of the state (Evaluation function)
        /// </summary>
        /// <param name="state">The state to be evaluated</param>
        /// <returns>The value of the state</returns>
        public int Evaluate(CheckersGameState state)
        {
            PieceColor winner = state.winner;

            //white is winner, if ai is white, then return max_int else return min_int
            if (winner == PieceColor.White)
            {
                return((state.aiColor == PieceColor.White) ? MAX_INT : MIN_INT);
            }
            //Find out that white is winner, if ai is white, then return max_int else return min_int
            else if (winner == PieceColor.Black)
            {
                return((state.aiColor == PieceColor.White) ? MIN_INT : MAX_INT);
            }
            //return the custom designed evaluation function
            //The states are evaluated by the difference in pieces left weighted by the number of turns that has occured
            //Every 4 turns the weight of difference in pieces goes up
            else
            {
                if (state.aiColor == PieceColor.White)
                {
                    return((int)(state.whiteGamePieces.Count - state.blackGamePieces.Count) * (int)(1 + state.numTurnsPassed * 0.25));
                }
                else
                {
                    return((int)(state.blackGamePieces.Count - state.whiteGamePieces.Count) * (int)(1 + state.numTurnsPassed * 0.25));
                }
            }
        }
Example #2
0
 /// <summary>
 /// Function called to initialize a new checkers game
 /// </summary>
 public void initComponent()
 {
     isMousePressed = false;
     didAiMove      = false;
     currentState   = new CheckersGameState(PieceColor.None);
     blackButton    = new Rectangle(25, 640, 150, 40);
     whiteButton    = new Rectangle(200, 640, 150, 40);
 }
Example #3
0
 /// <summary>
 /// Function that starts a new game for the player given the player color
 /// </summary>
 /// <param name="playerColor">Color of the player</param>
 public void newGame(PieceColor playerColor)
 {
     Console.WriteLine("========================================================"
                       + "\n                         NEW GAME                       "
                       + "\n========================================================");
     iterativeDepth = 0;
     currentState   = new CheckersGameState(playerColor);
 }
Example #4
0
        /// <summary>
        /// Max value search function
        /// </summary>
        /// <param name="state">The current state of the game</param>
        /// <param name="alpha">highest alpha found</param>
        /// <param name="beta">lowest beta found</param>
        /// <param name="depth">depth current state is at</param>
        /// <returns>The best max value</returns>
        public int MaxValue(CheckersGameState state, int alpha, int beta, int depth)
        {
            //increase depth
            depth++;
            maxDepth = (depth > maxDepth) ? depth : maxDepth;
            //Evaluate the state
            int utilityValue = Evaluate(state);

            //If the state is terminal or if the cuttoff is reached, return the value
            if (utilityValue == MAX_INT || utilityValue == MIN_INT ||
                depth == cutoff + iterativeDepth || (DateTime.Now - startTime).TotalSeconds > 55)
            {
                return(utilityValue);
            }
            //integer value used to determine alpha
            int value = MIN_INT;
            //A temporary gamestate to prevent anything in the actual game from changing
            CheckersGameState tempState;

            //The loop below finds every possible action from this state,
            //then using the temporary state, it will do the action,
            //and pass that state into the minValue function to find the largest possible value for alpha
            foreach (CheckersPiece piece in state.moveablePieces)
            {
                state.doGamePieceAction(piece);
                foreach (GameMove action in state.activeGamePiece.getPossibleMoves())
                {
                    tempState = new CheckersGameState(state);
                    nodes++;
                    if (tempState.doTileAction(tempState.gameBoard.getTileAt(action.destinationPosition)) == true)
                    {
                        tempState.activeGamePiece.Update(tempState);
                    }
                    value = Math.Max(value, MinValue(tempState, alpha, beta, depth));

                    //if alpha becomes greater than or equal to beta prune the tree
                    if (value >= beta)
                    {
                        maxPruned++;
                        return(value);
                    }

                    if (alpha < value)
                    {
                        alpha = value;
                        //if we are in the actual state of the game, that means we found a new best move
                        if (depth == 1)
                        {
                            bestMove = action;
                        }
                    }
                }
            }

            return(value);
        }
Example #5
0
        /// <summary>
        /// Function that will determine all possible moves for the piece
        /// </summary>
        /// <param name="gameBoard">The gameboard</param>
        /// <param name="gameState">The current state of the game</param>
        /// <param name="noShow">Whether or not to mark the board</param>
        /// <returns>Type of move the piece has (NONE, MOVE, JUMP)</returns>
        public TileStatus determineMoves(CheckersBoard gameBoard, CheckersGameState gameState, bool noShow = false)
        {
            TileStatus foundMove = TileStatus.NONE;

            possibleMoves.Clear();

            Vector2 tilePosition = new Vector2(position.X, position.Y);

            List <GameMove> jumps = getJumps(tilePosition, gameBoard, gameState);

            //Look for any jumps by the piece
            if (jumps.Count != 0)
            {
                foundMove            = TileStatus.JUMP;
                possibleMoves        = jumps;
                gameState.jumpExists = true;
                //Reset that the piece was just jumped over
                //Necessary for multi-jumps
                if (color == PieceColor.Black)
                {
                    foreach (CheckersPiece piece in gameState.whiteGamePieces)
                    {
                        piece.justJumpedOver = false;
                    }
                }
                else if (color == PieceColor.White)
                {
                    foreach (CheckersPiece piece in gameState.blackGamePieces)
                    {
                        piece.justJumpedOver = false;
                    }
                }
            }
            //If no jump was found in the context of the turn find possible regular moves for the piece
            else if (gameState.jumpExists == false)
            {
                List <GameMove> regularMoves = getRegularMoves(tilePosition, gameBoard, gameState);
                if (regularMoves.Count != 0)
                {
                    foundMove     = TileStatus.MOVE;
                    possibleMoves = regularMoves;
                }
            }
            if (noShow == false)
            {
                gameBoard.clearMarkings();
                if (foundMove != TileStatus.NONE)
                {
                    foreach (GameMove move in possibleMoves)
                    {
                        gameBoard.getTileAt(move.destinationPosition).setStatus(foundMove);
                    }
                }
            }
            return(foundMove);
        }
Example #6
0
        /// <summary>
        /// Main alpha-beta search algorithm
        /// </summary>
        /// <param name="state">The current state of the game</param>
        /// <returns>The value for the best next move</returns>
        public int AlphaBetaSearch(CheckersGameState state)
        {
            //Initialize all the variables to be used in the algorithm
            int alpha = MIN_INT;
            int beta  = MAX_INT;

            nodes     = 0;
            maxDepth  = 0;
            maxPruned = 0;
            minPruned = 0;
            startTime = DateTime.Now;

            int value = MaxValue(state, alpha, beta, 0);

            endTime = DateTime.Now;
            return(value);
        }
Example #7
0
        /// <summary>
        /// Function handles the updating of checkers piece.
        /// This function is called whenever a successful move is done.
        /// This function will update the piece's position on the board, and change who's turn it is.
        /// </summary>
        /// <param name="gameState">The gamestate to update</param>
        public void Update(CheckersGameState gameState)
        {
            if (destination != Vector2.Zero)
            {
                position    = destination;
                destination = Vector2.Zero;

                if (gameState.turnColor == PieceColor.Black)
                {
                    gameState.changePlayerTurn(PieceColor.White);
                }
                else
                {
                    gameState.changePlayerTurn(PieceColor.Black);
                }
            }
        }
Example #8
0
 /// <summary>
 /// Copy constructor to make a new copy of this current state
 /// This constructor is used to create temporary states in the ai.
 /// </summary>
 /// <param name="gameState">The state to be copied</param>
 public CheckersGameState(CheckersGameState gameState)
 {
     whiteGamePieces = new List <CheckersPiece>();
     blackGamePieces = new List <CheckersPiece>();
     moveablePieces  = new List <CheckersPiece>();
     gameBoard       = new CheckersBoard(gameState.gameBoard);
     foreach (CheckersPiece piece in gameState.blackGamePieces)
     {
         CheckersPiece newPiece = new CheckersPiece(piece);
         //find the active game piece
         if (gameState.activeGamePiece != null && newPiece.position == gameState.activeGamePiece.position)
         {
             activeGamePiece = newPiece;
         }
         blackGamePieces.Add(newPiece);
     }
     foreach (CheckersPiece piece in gameState.whiteGamePieces)
     {
         CheckersPiece newPiece = new CheckersPiece(piece);
         //find the active game piece
         if (gameState.activeGamePiece != null && newPiece.position == gameState.activeGamePiece.position)
         {
             activeGamePiece = newPiece;
         }
         whiteGamePieces.Add(newPiece);
     }
     foreach (CheckersPiece piece in gameState.moveablePieces)
     {
         CheckersPiece newPiece = new CheckersPiece(piece);
         moveablePieces.Add(newPiece);
     }
     playerColor    = gameState.playerColor;
     aiColor        = gameState.aiColor;
     turnColor      = gameState.turnColor;
     jumpExists     = gameState.jumpExists;
     winner         = gameState.winner;
     numTurnsPassed = gameState.numTurnsPassed;
 }
Example #9
0
        /// <summary>
        /// Function that will find all regular moves for this piece
        /// A regular move is a non-jump move
        /// </summary>
        /// <param name="tilePosition">The position of the tile to check jumps from</param>
        /// <param name="gameBoard">The gameboard</param>
        /// <param name="gameState">The current gamestate</param>
        /// <returns>A list of possible regular moves</returns>
        public List <GameMove> getRegularMoves(Vector2 tilePosition, CheckersBoard gameBoard, CheckersGameState gameState)
        {
            List <GameMove> regularMoves = new List <GameMove>();

            //Below is the logic for if the checkers piece is black
            if (color == PieceColor.Black)
            {
                //Get the two possible tiles a black piece could move to
                BoardTile topLeftTile  = gameBoard.getTileAt((int)tilePosition.X - 1, (int)tilePosition.Y - 1);
                BoardTile topRightTile = gameBoard.getTileAt((int)tilePosition.X + 1, (int)tilePosition.Y - 1);

                //If the tile exists on the board, add that tile as a possible move
                if (topLeftTile != null && topLeftTile.getOccupiedStatus() == PieceColor.None)
                {
                    regularMoves.Add(new GameMove(this, topLeftTile.position));
                }
                if (topRightTile != null && topRightTile.getOccupiedStatus() == PieceColor.None)
                {
                    regularMoves.Add(new GameMove(this, topRightTile.position));
                }
            }

            //Below is the logic for if the checkers piece is white
            if (color == PieceColor.White)
            {
                //Get the two possible tiles a black piece could move to
                BoardTile bottomLeftTile  = gameBoard.getTileAt((int)tilePosition.X - 1, (int)tilePosition.Y + 1);
                BoardTile bottomRightTile = gameBoard.getTileAt((int)tilePosition.X + 1, (int)tilePosition.Y + 1);

                //If the tile exists on the board, add that tile as a possible move
                if (bottomLeftTile != null && bottomLeftTile.getOccupiedStatus() == PieceColor.None)
                {
                    regularMoves.Add(new GameMove(this, bottomLeftTile.position));
                }
                if (bottomRightTile != null && bottomRightTile.getOccupiedStatus() == PieceColor.None)
                {
                    regularMoves.Add(new GameMove(this, bottomRightTile.position));
                }
            }
            return(regularMoves);
        }
Example #10
0
        /// <summary>
        /// Function that will recursively find all the jump sequences possible by this piece
        /// </summary>
        /// <param name="tilePosition">The position of the tile to check jumps from</param>
        /// <param name="gameBoard">The gameboard</param>
        /// <param name="gameState">The current gamestate</param>
        /// <returns>A list of possible jumps</returns>
        public List <GameMove> getJumps(Vector2 tilePosition, CheckersBoard gameBoard, CheckersGameState gameState)
        {
            List <GameMove> jumps = new List <GameMove>();
            //Get all the possible tiles that could result with a jump
            BoardTile topLeftTile         = gameBoard.getTileAt((int)tilePosition.X - 1, (int)tilePosition.Y - 1);
            BoardTile topRightTile        = gameBoard.getTileAt((int)tilePosition.X + 1, (int)tilePosition.Y - 1);
            BoardTile bottomLeftTile      = gameBoard.getTileAt((int)tilePosition.X - 1, (int)tilePosition.Y + 1);
            BoardTile bottomRightTile     = gameBoard.getTileAt((int)tilePosition.X + 1, (int)tilePosition.Y + 1);
            BoardTile topLeftJumpTile     = gameBoard.getTileAt((int)tilePosition.X - 2, (int)tilePosition.Y - 2);
            BoardTile topRightJumpTile    = gameBoard.getTileAt((int)tilePosition.X + 2, (int)tilePosition.Y - 2);
            BoardTile bottomLeftJumpTile  = gameBoard.getTileAt((int)tilePosition.X - 2, (int)tilePosition.Y + 2);
            BoardTile bottomRightJumpTile = gameBoard.getTileAt((int)tilePosition.X + 2, (int)tilePosition.Y + 2);

            //Set the enemy color
            PieceColor enemyColor;

            if (this.color == PieceColor.Black)
            {
                enemyColor = PieceColor.White;
            }
            else
            {
                enemyColor = PieceColor.Black;
            }

            //The below four if-elses will basically determine if there was a piece of the enemy color was jumped over
            //by moving to a tile 2 diagonal tiles away. If there was a jump, it will mark the piece that it just jumped over
            //and then recursively look for any other following jumps from that tile.
            if (topLeftTile != null && topLeftTile.getOccupiedStatus() == enemyColor)
            {
                //Get the piece that was jumped over
                CheckersPiece adjacentPiece = gameState.getPiece(enemyColor, topLeftTile.position);
                if (topLeftJumpTile != null && topLeftJumpTile.getOccupiedStatus() == PieceColor.None && adjacentPiece.justJumpedOver == false)
                {
                    //mark the piece as jumped over
                    adjacentPiece.justJumpedOver = true;
                    //Find any jumps from the new tile position
                    List <GameMove> sequenceJumps = getJumps(topLeftJumpTile.position, gameBoard, gameState);

                    //If there was no following jump then add the jump to the list of jump
                    if (sequenceJumps.Count == 0)
                    {
                        GameMove newJump = (new GameMove(this, topLeftJumpTile.position));
                        newJump.capturedPieces.Add(adjacentPiece);
                        jumps.Add(newJump);
                    }
                    //Else for each following jump, add the piece the first jump captured to the list of captured pieces
                    else
                    {
                        foreach (GameMove jump in sequenceJumps)
                        {
                            //GameMove newJump = (new GameMove(this, jump.destinationPosition));
                            //jump.capturedPieces = jump.capturedPieces;
                            jump.capturedPieces.Add(adjacentPiece);
                            jumps.Add(jump);
                        }
                    }
                }
            }
            if (topRightTile != null && topRightTile.getOccupiedStatus() == enemyColor)
            {
                CheckersPiece adjacentPiece = gameState.getPiece(enemyColor, topRightTile.position);
                if (topRightJumpTile != null && topRightJumpTile.getOccupiedStatus() == PieceColor.None && adjacentPiece.justJumpedOver == false)
                {
                    //get any jumps from that tile
                    adjacentPiece.justJumpedOver = true;
                    List <GameMove> sequenceJumps = getJumps(topRightJumpTile.position, gameBoard, gameState);

                    if (sequenceJumps.Count == 0)
                    {
                        GameMove newJump = (new GameMove(this, topRightJumpTile.position));
                        newJump.capturedPieces.Add(adjacentPiece);
                        jumps.Add(newJump);
                    }
                    else
                    {
                        foreach (GameMove jump in sequenceJumps)
                        {
                            GameMove newJump = (new GameMove(this, jump.destinationPosition));
                            newJump.capturedPieces = jump.capturedPieces;
                            newJump.capturedPieces.Add(adjacentPiece);
                            jumps.Add(newJump);
                        }
                    }
                }
            }
            if (bottomLeftTile != null && bottomLeftTile.getOccupiedStatus() == enemyColor)
            {
                CheckersPiece adjacentPiece = gameState.getPiece(enemyColor, bottomLeftTile.position);
                if (bottomLeftJumpTile != null && bottomLeftJumpTile.getOccupiedStatus() == PieceColor.None && adjacentPiece.justJumpedOver == false)
                {
                    //get any jumps from that tile
                    adjacentPiece.justJumpedOver = true;
                    List <GameMove> sequenceJumps = getJumps(bottomLeftJumpTile.position, gameBoard, gameState);

                    if (sequenceJumps.Count == 0)
                    {
                        GameMove newJump = (new GameMove(this, bottomLeftJumpTile.position));
                        newJump.capturedPieces.Add(adjacentPiece);
                        jumps.Add(newJump);
                    }
                    else
                    {
                        foreach (GameMove jump in sequenceJumps)
                        {
                            GameMove newJump = (new GameMove(this, jump.destinationPosition));
                            newJump.capturedPieces = jump.capturedPieces;
                            newJump.capturedPieces.Add(adjacentPiece);
                            jumps.Add(newJump);
                        }
                    }
                }
            }
            if (bottomRightTile != null && bottomRightTile.getOccupiedStatus() == enemyColor)
            {
                CheckersPiece adjacentPiece = gameState.getPiece(enemyColor, bottomRightTile.position);
                if (bottomRightJumpTile != null && bottomRightJumpTile.getOccupiedStatus() == PieceColor.None && adjacentPiece.justJumpedOver == false)
                {
                    //get any jumps from that tile
                    adjacentPiece.justJumpedOver = true;
                    List <GameMove> sequenceJumps = getJumps(bottomRightJumpTile.position, gameBoard, gameState);

                    if (sequenceJumps.Count == 0)
                    {
                        GameMove newJump = (new GameMove(this, bottomRightJumpTile.position));
                        newJump.capturedPieces.Add(adjacentPiece);
                        jumps.Add(newJump);
                    }
                    else
                    {
                        foreach (GameMove jump in sequenceJumps)
                        {
                            GameMove newJump = (new GameMove(this, jump.destinationPosition));
                            newJump.capturedPieces = jump.capturedPieces;
                            newJump.capturedPieces.Add(adjacentPiece);
                            jumps.Add(newJump);
                        }
                    }
                }
            }

            return(jumps);
        }