Beispiel #1
0
        public void AISelect()
        {
            // wait for previous ai thread to stop
            while (AI.RUNNING)
            {
                Thread.Sleep(100);
            }

            // ai is dump
            this.m_UI.SetStatus(true, "Thinking...");

            // calculate move
            move_t move = AI.MiniMaxAB(this.Board, this.Turn);

            // if valid move, make the move
            if (move.to.letter >= 0 && move.to.number >= 0)
            {
                MakeMove(move);
            }
            else // if invalid move
            {
                if (!AI.STOP) // and not caused by AI interupt
                {
                    // fuuuuuu
                    this.m_UI.LogMove("Null Move\n");
                }
            }

            bool checkmate = false;

            // if the AI wasn't interupted finish our turn
            if (!AI.STOP)
            {
                switchPlayer();
                checkmate = detectCheckmate();
            }

            // we're done now
            AI.RUNNING = false;

            // if the AI wan't interupted
            // and we're in AI vs AI mode
            // and not in checkmate/stalemate
            // start the next AI's turn
            if (!AI.STOP && this.m_nPlayers == 0 && !checkmate)
            {
                new Thread(AISelect).Start();
            }
        }
Beispiel #2
0
        public static bool isEnPassant(ChessBoard b, move_t m)
        {
            // step = where opposite pawn is
            int step = ((b.Grid[m.from.number][m.from.letter].player == Player.WHITE) ? -1 : 1);

            // true if
            // move is pawn
            // space is blank
            // move is diagonal
            // opposite pawn exists at step
            // the last move for opposite player was the pawn
            // the last move for opposite pawn was the double jump
            return(
                b.Grid[m.from.number][m.from.letter].piece == Piece.PAWN &&
                b.Grid[m.to.number][m.to.letter].piece == Piece.NONE &&
                m.to.letter != m.from.letter &&
                b.Grid[m.to.number + step][m.to.letter].piece == Piece.PAWN &&
                b.LastMove[(b.Grid[m.from.number][m.from.letter].player == Player.WHITE) ? Player.BLACK : Player.WHITE].Equals(new position_t(m.to.letter, m.to.number + step)) &&
                Math.Abs(b.Grid[m.to.number + step][m.to.letter].lastPosition.number - (m.to.number + step)) == 2 //jumped from last position
                );
        }
Beispiel #3
0
        private void MakeMove(move_t m)
        {
            // start move log output
            string move = (this.Turn == Player.WHITE) ? "W" : "B";

            move += ":\t";

            // piece
            switch (this.Board.Grid[m.from.number][m.from.letter].piece)
            {
            case Piece.PAWN:
                move += "P";
                break;

            case Piece.ROOK:
                move += "R";
                break;

            case Piece.KNIGHT:
                move += "k";
                break;

            case Piece.BISHOP:
                move += "B";
                break;

            case Piece.QUEEN:
                move += "Q";
                break;

            case Piece.KING:
                move += "K";
                break;
            }

            // kill
            if (this.Board.Grid[m.to.number][m.to.letter].piece != Piece.NONE || LegalMoveSet.isEnPassant(this.Board, m))
            {
                move += "x";
            }

            // letter
            switch (m.to.letter)
            {
            case 0: move += "a"; break;

            case 1: move += "b"; break;

            case 2: move += "c"; break;

            case 3: move += "d"; break;

            case 4: move += "e"; break;

            case 5: move += "f"; break;

            case 6: move += "g"; break;

            case 7: move += "h"; break;
            }

            // number
            move += (m.to.number + 1).ToString();

            // update board / make actual move
            this.Board = LegalMoveSet.move(this.Board, m);

            // if that move put someone in check
            if (LegalMoveSet.isCheck(this.Board, (Turn == Player.WHITE) ? Player.BLACK : Player.WHITE))
            {
                move += "+";
            }

            // show log
            this.m_UI.LogMove(move + "\n");
        }
Beispiel #4
0
        public static move_t MiniMaxAB(ChessBoard board, Player turn)
        {
            RUNNING = true;  // we've started running
            STOP    = false; // no interupt command sent
            MAX     = turn;  // who is maximizing

            // gather all possible moves
            Dictionary <position_t, List <position_t> > moves = LegalMoveSet.getPlayerMoves(board, turn);

            // because we're threading safely store best result from each thread
            int[]    bestresults = new int[moves.Count];
            move_t[] bestmoves   = new move_t[moves.Count];

            // thread the generation of each move
            Parallel.ForEach(moves, (movelist, state, index) =>
            {
                if (STOP) // interupt
                {
                    state.Stop();
                    return;
                }

                // initialize thread best
                bestresults[index] = int.MinValue;
                bestmoves[index]   = new move_t(new position_t(-1, -1), new position_t(-1, -1));

                // for each move for the current piece(thread)
                foreach (position_t move in movelist.Value)
                {
                    if (STOP) // interupt
                    {
                        state.Stop();
                        return;
                    }

                    // make initial move and start recursion
                    ChessBoard b2 = LegalMoveSet.move(board, new move_t(movelist.Key, move));
                    int result    = mimaab(b2, (turn == Player.WHITE) ? Player.BLACK : Player.WHITE, 1, Int32.MinValue, Int32.MaxValue);

                    // if result is better or best hasn't been set yet
                    if (bestresults[index] < result || (bestmoves[index].to.Equals(new position_t(-1, -1)) && bestresults[index] == int.MinValue))
                    {
                        bestresults[index]    = result;
                        bestmoves[index].from = movelist.Key;
                        bestmoves[index].to   = move;
                    }
                }
            });

            // interupted
            if (STOP)
            {
                return(new move_t(new position_t(-1, -1), new position_t(-1, -1)));
            }

            // find the best of the thread results
            int    best = int.MinValue;
            move_t m    = new move_t(new position_t(-1, -1), new position_t(-1, -1));

            for (int i = 0; i < bestmoves.Length; i++)
            {
                if (best < bestresults[i] || (m.to.Equals(new position_t(-1, -1)) && !bestmoves[i].to.Equals(new position_t(-1, -1))))
                {
                    best = bestresults[i];
                    m    = bestmoves[i];
                }
            }
            return(m);
        }
Beispiel #5
0
        private void MakeMove(move_t m)
        {
            // start move log output
            string move = (this.Turn == Player.WHITE) ? "W" : "B";

            move += ":\t";

            // piece
            switch (this.Board.Grid[m.from.number][m.from.letter].piece)
            {
                case Piece.PAWN:
                    move += "P";
                    break;
                case Piece.ROOK:
                    move += "R";
                    break;
                case Piece.KNIGHT:
                    move += "k";
                    break;
                case Piece.BISHOP:
                    move += "B";
                    break;
                case Piece.QUEEN:
                    move += "Q";
                    break;
                case Piece.KING:
                    move += "K";
                    break;
            }

            // kill
            if (this.Board.Grid[m.to.number][m.to.letter].piece != Piece.NONE || LegalMoveSet.isEnPassant(this.Board, m))
            {
                move += "x";
            }

            // letter
            switch (m.to.letter)
            {
                case 0: move += "a"; break;
                case 1: move += "b"; break;
                case 2: move += "c"; break;
                case 3: move += "d"; break;
                case 4: move += "e"; break;
                case 5: move += "f"; break;
                case 6: move += "g"; break;
                case 7: move += "h"; break;
            }

            // number
            move += (m.to.number + 1).ToString();

            // update board / make actual move
            this.Board = LegalMoveSet.move(this.Board, m);

            // if that move put someone in check
            if (LegalMoveSet.isCheck(this.Board, (Turn == Player.WHITE) ? Player.BLACK : Player.WHITE))
            {
                move += "+";
            }

            // show log
            this.m_UI.LogMove(move + "\n");
        }
Beispiel #6
0
        /// <summary>
        /// Performs all necessary steps to update the game state and move the pieces.
        /// </summary>
        /// <param name="b">The state of the game.</param>
        /// <param name="m">The desired move.</param>
        /// <returns>The new state of the game.</returns>
        public static ChessBoard move(ChessBoard b, move_t m)
        {
            // create a copy of the board
            ChessBoard b2 = new ChessBoard(b);

            // determine if move is enpassant or castling
            bool enpassant = (b2.Grid[m.from.number][m.from.letter].piece == Piece.PAWN && isEnPassant(b2, m));
            bool castle    = (b2.Grid[m.from.number][m.from.letter].piece == Piece.KING && Math.Abs(m.to.letter - m.from.letter) == 2);

            // update piece list, remove old position from piece list for moving player
            b2.Pieces[b2.Grid[m.from.number][m.from.letter].player].Remove(m.from);

            // if move kills a piece directly, remove killed piece from killed player piece list
            if (b2.Grid[m.to.number][m.to.letter].piece != Piece.NONE && b2.Grid[m.from.number][m.from.letter].player != b2.Grid[m.to.number][m.to.letter].player)
            {
                b2.Pieces[b2.Grid[m.to.number][m.to.letter].player].Remove(m.to);
            }
            else if (enpassant)
            {
                // if kill was through enpassant determine which direction and remove the killed pawn
                int step = (b.Grid[m.from.number][m.from.letter].player == Player.WHITE) ? -1 : 1;
                b2.Pieces[b2.Grid[m.to.number + step][m.to.letter].player].Remove(new position_t(m.to.letter, m.to.number + step));
            }
            else if (castle)
            {
                // if no kill but enpassant, update the rook position
                if (m.to.letter == 6)
                {
                    b2.Pieces[b2.Grid[m.to.number][m.to.letter].player].Remove(new position_t(7, m.to.number));
                    b2.Pieces[b2.Grid[m.to.number][m.to.letter].player].Add(new position_t(5, m.to.number));
                }
                else
                {
                    b2.Pieces[b2.Grid[m.to.number][m.to.letter].player].Remove(new position_t(0, m.to.number));
                    b2.Pieces[b2.Grid[m.to.number][m.to.letter].player].Remove(new position_t(3, m.to.number));
                }
            }

            // add the new piece location to piece list
            b2.Pieces[b2.Grid[m.from.number][m.from.letter].player].Add(m.to);

            // update board grid
            b2.Grid[m.to.number][m.to.letter] = new piece_t(b2.Grid[m.from.number][m.from.letter]);
            b2.Grid[m.to.number][m.to.letter].lastPosition = m.from;
            b2.Grid[m.from.number][m.from.letter].piece    = Piece.NONE;
            if (enpassant)
            {
                // if kill was through enpassant determine which direction and remove the killed pawn
                int step = (b.Grid[m.from.number][m.from.letter].player == Player.WHITE) ? -1 : 1;
                b2.Grid[m.to.number + step][m.to.letter].piece = Piece.NONE;
            }
            else if (castle)
            {
                // if no kill but enpassant, update the rook position
                if (m.to.letter == 6)
                {
                    b2.Grid[m.to.number][5]       = new piece_t(b2.Grid[m.to.number][7]);
                    b2.Grid[m.to.number][7].piece = Piece.NONE;
                }
                else
                {
                    b2.Grid[m.to.number][3]       = new piece_t(b2.Grid[m.to.number][0]);
                    b2.Grid[m.to.number][0].piece = Piece.NONE;
                }
            }


            //promotion
            if (b2.Grid[m.to.number][m.to.letter].piece == Piece.PAWN)
            {
                for (int i = 0; i < 8; i++)
                {
                    if (b2.Grid[0][i].piece == Piece.PAWN)
                    {
                        b2.Grid[0][i].piece = Piece.QUEEN;
                    }
                    if (b2.Grid[7][i].piece == Piece.PAWN)
                    {
                        b2.Grid[7][i].piece = Piece.QUEEN;
                    }
                }
            }

            // update king position
            if (b2.Grid[m.to.number][m.to.letter].piece == Piece.KING)
            {
                b2.Kings[b2.Grid[m.to.number][m.to.letter].player] = m.to;
            }

            // update last move
            b2.LastMove[b2.Grid[m.to.number][m.to.letter].player] = m.to;

            return(b2);
        }
Beispiel #7
0
        public static move_t MiniMaxAB(ChessBoard board, Player turn)
        {
            RUNNING = true; // we've started running
            STOP = false; // no interupt command sent
            MAX = turn; // who is maximizing

            // gather all possible moves
            Dictionary<position_t, List<position_t>> moves = LegalMoveSet.getPlayerMoves(board, turn);

            // because we're threading safely store best result from each thread
            int[] bestresults = new int[moves.Count];
            move_t[] bestmoves = new move_t[moves.Count];

            // thread the generation of each move
            Parallel.ForEach(moves, (movelist,state,index) =>
            {
                if (STOP) // interupt
                {
                    state.Stop();
                    return;
                }

                // initialize thread best
                bestresults[index] = int.MinValue;
                bestmoves[index] = new move_t(new position_t(-1, -1), new position_t(-1, -1));

                // for each move for the current piece(thread)
                foreach (position_t move in movelist.Value)
                {
                    if (STOP) // interupt
                    {
                        state.Stop();
                        return;
                    }

                    // make initial move and start recursion
                    ChessBoard b2 = LegalMoveSet.move(board, new move_t(movelist.Key, move));
                    int result = mimaab(b2, (turn == Player.WHITE) ? Player.BLACK : Player.WHITE, 1, Int32.MinValue, Int32.MaxValue);

                    // if result is better or best hasn't been set yet
                    if (bestresults[index] < result || (bestmoves[index].to.Equals(new position_t(-1, -1)) && bestresults[index] == int.MinValue))
                    {
                        bestresults[index] = result;
                        bestmoves[index].from = movelist.Key;
                        bestmoves[index].to = move;
                    }
                }
            });

            // interupted
            if (STOP)
                return new move_t(new position_t(-1, -1), new position_t(-1, -1)); 

            // find the best of the thread results
            int best = int.MinValue;
            move_t m = new move_t(new position_t(-1, -1), new position_t(-1, -1));
            for(int i = 0; i < bestmoves.Length; i++)
            {
                if (best < bestresults[i] || (m.to.Equals(new position_t(-1,-1)) && !bestmoves[i].to.Equals(new position_t(-1,-1))))
                {
                    best = bestresults[i];
                    m = bestmoves[i];
                }
            }
            return m;
        }
Beispiel #8
0
        public static bool isEnPassant(ChessBoard b, move_t m)
        {
            // step = where opposite pawn is
            int step = ((b.Grid[m.from.number][m.from.letter].player == Player.WHITE) ? -1 : 1);

            // true if
            // move is pawn
            // space is blank
            // move is diagonal
            // opposite pawn exists at step
            // the last move for opposite player was the pawn
            // the last move for opposite pawn was the double jump
            return (
                b.Grid[m.from.number][m.from.letter].piece == Piece.PAWN &&
                b.Grid[m.to.number][m.to.letter].piece == Piece.NONE &&
                m.to.letter != m.from.letter &&
                b.Grid[m.to.number + step][m.to.letter].piece == Piece.PAWN &&
                b.LastMove[(b.Grid[m.from.number][m.from.letter].player == Player.WHITE) ? Player.BLACK : Player.WHITE].Equals(new position_t(m.to.letter, m.to.number + step)) &&
                Math.Abs(b.Grid[m.to.number + step][m.to.letter].lastPosition.number - (m.to.number + step)) == 2 //jumped from last position
                );
        }
Beispiel #9
0
        /// <summary>
        /// Performs all necessary steps to update the game state and move the pieces.
        /// </summary>
        /// <param name="b">The state of the game.</param>
        /// <param name="m">The desired move.</param>
        /// <returns>The new state of the game.</returns>
        public static ChessBoard move(ChessBoard b, move_t m)
        {
            // create a copy of the board
            ChessBoard b2 = new ChessBoard(b); 

            // determine if move is enpassant or castling
            bool enpassant = (b2.Grid[m.from.number][m.from.letter].piece == Piece.PAWN && isEnPassant(b2, m));
            bool castle = (b2.Grid[m.from.number][m.from.letter].piece == Piece.KING && Math.Abs(m.to.letter - m.from.letter) == 2);

            // update piece list, remove old position from piece list for moving player
            b2.Pieces[b2.Grid[m.from.number][m.from.letter].player].Remove(m.from);

            // if move kills a piece directly, remove killed piece from killed player piece list
            if (b2.Grid[m.to.number][m.to.letter].piece != Piece.NONE && b2.Grid[m.from.number][m.from.letter].player != b2.Grid[m.to.number][m.to.letter].player)
                b2.Pieces[b2.Grid[m.to.number][m.to.letter].player].Remove(m.to);
            else if(enpassant) 
            {
                // if kill was through enpassant determine which direction and remove the killed pawn
                int step = (b.Grid[m.from.number][m.from.letter].player == Player.WHITE) ? -1 : 1;
                b2.Pieces[b2.Grid[m.to.number + step][m.to.letter].player].Remove(new position_t(m.to.letter, m.to.number + step));
            }
            else if (castle)
            {
                // if no kill but enpassant, update the rook position
                if (m.to.letter == 6)
                {
                    b2.Pieces[b2.Grid[m.to.number][m.to.letter].player].Remove(new position_t(7, m.to.number));
                    b2.Pieces[b2.Grid[m.to.number][m.to.letter].player].Add(new position_t(5, m.to.number));
                }
                else
                {
                    b2.Pieces[b2.Grid[m.to.number][m.to.letter].player].Remove(new position_t(0, m.to.number));
                    b2.Pieces[b2.Grid[m.to.number][m.to.letter].player].Remove(new position_t(3, m.to.number));
                }
            }

            // add the new piece location to piece list
            b2.Pieces[b2.Grid[m.from.number][m.from.letter].player].Add(m.to);

            // update board grid
            b2.Grid[m.to.number][m.to.letter] = new piece_t(b2.Grid[m.from.number][m.from.letter]);
            b2.Grid[m.to.number][m.to.letter].lastPosition = m.from;
            b2.Grid[m.from.number][m.from.letter].piece = Piece.NONE;
            if (enpassant)
            {
                // if kill was through enpassant determine which direction and remove the killed pawn
                int step = (b.Grid[m.from.number][m.from.letter].player == Player.WHITE) ? -1 : 1;
                b2.Grid[m.to.number + step][m.to.letter].piece = Piece.NONE;
            }
            else if (castle)
            {
                // if no kill but enpassant, update the rook position
                if (m.to.letter == 6)
                {
                    b2.Grid[m.to.number][5] = new piece_t(b2.Grid[m.to.number][7]);
                    b2.Grid[m.to.number][7].piece = Piece.NONE;
                }
                else
                {
                    b2.Grid[m.to.number][3] = new piece_t(b2.Grid[m.to.number][0]);
                    b2.Grid[m.to.number][0].piece = Piece.NONE;
                }
            }


            //promotion
            if (b2.Grid[m.to.number][m.to.letter].piece == Piece.PAWN)
            {
                for (int i = 0; i < 8; i++)
                {
                    if (b2.Grid[0][i].piece == Piece.PAWN)
                        b2.Grid[0][i].piece = Piece.QUEEN;
                    if (b2.Grid[7][i].piece == Piece.PAWN)
                        b2.Grid[7][i].piece = Piece.QUEEN;
                }
            }

            // update king position
            if (b2.Grid[m.to.number][m.to.letter].piece == Piece.KING)
            {
                b2.Kings[b2.Grid[m.to.number][m.to.letter].player] = m.to;
            }

            // update last move 
            b2.LastMove[b2.Grid[m.to.number][m.to.letter].player] = m.to;

            return b2;
        }