Esempio n. 1
0
        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));
        }
Esempio n. 3
0
        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));
        }
Esempio n. 4
0
        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)]);
        }
Esempio n. 5
0
        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);
        }
Esempio n. 6
0
        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;
            }
        }
Esempio n. 7
0
        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);
                }
            }
        }
Esempio n. 8
0
    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();
            }
        }
    }
Esempio n. 9
0
        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);
        }
Esempio n. 10
0
        /// <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);
        }
Esempio n. 11
0
 /// <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;
     }
 }
Esempio n. 12
0
        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));
        }
Esempio n. 13
0
 /// <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);
 }
Esempio n. 14
0
        /// <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);
        }
Esempio n. 15
0
 /// <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;
 }
Esempio n. 16
0
 /// <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);
 }
Esempio n. 17
0
 /// <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);
 }
Esempio n. 18
0
 /// <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));
 }
Esempio n. 19
0
        /// <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);
        }
Esempio n. 20
0
        /// <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)]);
        }