Beispiel #1
0
        internal void copy(Position pos)
        {
            // MEMCPY
            Array.Copy(pos.board, this.board, 64);
            Array.Copy(pos.byTypeBB, this.byTypeBB, 8);
            Array.Copy(pos.byColorBB, this.byColorBB, 2);
            this.occupied_squares = pos.occupied_squares;

            for (int i = 0; i < 2; i++)
            {
                Array.Copy(pos.castleRookSquare[i], this.castleRookSquare[i], 2);
                Array.Copy(pos.castlePath[i], this.castlePath[i], 2);
                Array.Copy(pos.pieceCount[i], this.pieceCount[i], 8);
                for (int j = 0; j < 8; j++)
                {
                    Array.Copy(pos.pieceList[i][j], this.pieceList[i][j], 16);
                }
            }

            Array.Copy(pos.index, this.index, 64);
            Array.Copy(pos.castleRightsMask, this.castleRightsMask, 64);

            this.startState = pos.startState;
            this.startPosPly = pos.startPosPly;
            this.sideToMove = pos.sideToMove;

            this.st = pos.st;
            this.chess960 = pos.chess960;
            this.thisThread = pos.thisThread;

            startState = st;
            st = startState;
            nodes = 0;

            Debug.Assert(pos_is_ok());
        }
Beispiel #2
0
        internal void Clear()
        {
            this.pawnKey = 0;
            this.materialKey = 0;
            this.npMaterialWHITE = 0;
            this.npMaterialBLACK = 0;
            this.castleRights = 0;
            this.rule50 = 0;
            this.pliesFromNull = 0;
            this.psqScore = 0;
            this.epSquare = 0;

            this.key = 0;
            this.checkersBB = 0;
            this.capturedType = 0;
            this.previous = null;
        }
Beispiel #3
0
 internal void do_move(int m, StateInfo newSt)
 {
     var ci = CheckInfoBroker.GetObject();
     ci.CreateCheckInfo(this);
     this.do_move(m, newSt, ci, this.move_gives_check(m, ci));
     CheckInfoBroker.Free();
 }
Beispiel #4
0
        /// clear() erases the position object to a pristine state, with an
        /// empty board, white to move, and no castling rights.
        internal void clear()
        {
            Array.Clear(byColorBB, 0, 2);
            Array.Clear(byTypeBB, 0, 8);
            Array.Clear(pieceCount[0], 0, 8);
            Array.Clear(pieceCount[1], 0, 8);
            Array.Clear(index, 0, 64);
            Array.Clear(castleRightsMask, 0, 64);
            Array.Clear(castleRookSquare[0], 0, 2);
            Array.Clear(castleRookSquare[1], 0, 2);
            Array.Clear(castlePath[0], 0, 2);
            Array.Clear(castlePath[1], 0, 2);

            startState.Clear();
            occupied_squares = 0;
            nodes = 0;
            startPosPly = 0;
            sideToMove = 0;
            thisThread = null;
            chess960 = false;

            startState.epSquare = SquareC.SQ_NONE;
            st = startState;

            for (int i = 0; i < 8; i++)
                for (int j = 0; j < 16; j++)
                    pieceList[0][i][j] = pieceList[1][i][j] = SquareC.SQ_NONE;

            for (Square sq = SquareC.SQ_A1; sq <= SquareC.SQ_H8; sq++)
                board[sq] = PieceC.NO_PIECE;
        }
Beispiel #5
0
        /// Wait for a command from the user, parse this text string as an UCI command,
        /// and call the appropriate functions. Also intercepts EOF from stdin to ensure
        /// that we exit gracefully if the GUI dies unexpectedly. In addition to the UCI
        /// commands, the function also supports a few debug commands.
        internal static void uci_loop(string args)
        {
            for (int i = 0; i < 102; i++)
            {
                StateRingBuf[i] = new StateInfo();
            }

            Position pos = new Position(StartFEN, false, Threads.main_thread()); // The root position
            string cmd, token = string.Empty;

            while (token != "quit")
            {
                if (args.Length > 0)
                {
                    cmd = args;
                }
                else if (String.IsNullOrEmpty(cmd = Plug.ReadLine())) // Block here waiting for input
                {
                    cmd = "quit";
                }
                Stack<string> stack = Utils.CreateStack(cmd);

                token = stack.Pop();

                if (token == "quit" || token == "stop")
                {
                    Search.SignalsStop = true;
                    Threads.wait_for_search_finished(); // Cannot quit while threads are running
                }
                else if (token == "ponderhit")
                {
                    // The opponent has played the expected move. GUI sends "ponderhit" if
                    // we were told to ponder on the same move the opponent has played. We
                    // should continue searching but switching from pondering to normal search.
                    Search.Limits.ponder = false;

                    if (Search.SignalsStopOnPonderhit)
                    {
                        Search.SignalsStop = true;
                        Threads.main_thread().wake_up(); // Could be sleeping
                    }
                }
                else if (token == "go")
                {
                    go(pos, stack);
                }
                else if (token == "ucinewgame")
                { /* Avoid returning "Unknown command" */ }
                else if (token == "isready")
                {
                    Plug.Write("readyok");
                    Plug.Write(Constants.endl);
                }
                else if (token == "position")
                {
                    set_position(pos, stack);
                }
                else if (token == "setoption")
                {
                    set_option(stack);
                }
                else if (token == "validmoves")
                {
                    Search.validmoves(pos, stack);
                }
                else if (token == "d")
                {
                    pos.print(0);
                }
                else if (token == "flip")
                {
                    pos.flip();
                }
                else if (token == "eval")
                {
                    Plug.Write(Evaluate.trace(pos));
                    Plug.Write(Constants.endl);
                }
                else if (token == "bench")
                {
                    Benchmark.benchmark(pos, stack);
                }
                else if (token == "key")
                {
                    Plug.Write("key: ");
                    Plug.Write(String.Format("{0:X}", pos.key()));
                    Plug.Write("\nmaterial key: ");
                    Plug.Write(pos.material_key().ToString());
                    Plug.Write("\npawn key: ");
                    Plug.Write(pos.pawn_key().ToString());
                    Plug.Write(Constants.endl);
                }
                else if (token == "uci")
                {
                    Plug.Write("id name "); Plug.Write(Utils.engine_info(true));
                    Plug.Write("\n"); Plug.Write(OptionMap.Instance.ToString());
                    Plug.Write("\nuciok"); Plug.Write(Constants.endl);
                }
                else if (token == "perft")
                {
                    token = stack.Pop();  // Read depth
                    Stack<string> ss = Utils.CreateStack(
                        string.Format("{0} {1} {2} current perft", OptionMap.Instance["Hash"].v, OptionMap.Instance["Threads"].v, token)
                        );
                    Benchmark.benchmark(pos, ss);
                }
                else
                {
                    Plug.Write("Unknown command: ");
                    Plug.Write(cmd);
                    Plug.Write(Constants.endl);
                }

                if (args.Length > 0) // Command line arguments have one-shot behaviour
                {
                    Threads.wait_for_search_finished();
                    break;
                }

            }
        }
Beispiel #6
0
 internal static StateInfo GetObject()
 {
     int slotID = System.Threading.Thread.CurrentThread.ManagedThreadId & Constants.BROKER_SLOT_MASK;
     if (_cnt[slotID] == _pool[slotID].Length)
     {
         int poolLength = _pool[slotID].Length;
         StateInfo[] temp = new StateInfo[poolLength + Constants.BrokerCapacity];
         Array.Copy(_pool[slotID], temp, poolLength);
         for (int i = 0; i < Constants.BrokerCapacity; i++)
         {
             temp[poolLength + i] = new StateInfo();
         }
         _pool[slotID] = temp;
     }
     return _pool[slotID][_cnt[slotID]++];
 }
Beispiel #7
0
 internal void do_move(Move m, StateInfo newSt)
 {
     CheckInfo ci = CheckInfoBroker.GetObject();
     ci.CreateCheckInfo(this);
     do_move(m, newSt, ci, move_gives_check(m, ci));
     CheckInfoBroker.Free();
 }
Beispiel #8
0
        /// Search::perft() is our utility to verify move generation. All the leaf nodes
        /// up to the given depth are generated and counted and the sum returned.
        internal static Int64 perft(Position pos, Depth depth)
        {
            StateInfo st = new StateInfo();
            Int64 cnt = 0;

            MList mlist = MListBroker.GetObject(); mlist.pos = 0;
            Movegen.generate_legal(pos, mlist.moves, ref mlist.pos);

            // At the last ply just return the number of moves (leaf nodes)
            if (depth == DepthC.ONE_PLY)
            {
                int retval = mlist.pos;
                MListBroker.Free();
                return retval;
            }

            CheckInfo ci = CheckInfoBroker.GetObject();
            ci.CreateCheckInfo(pos);
            for (int i = 0; i < mlist.pos; ++i)
            {
                MoveStack ms = mlist.moves[i];
                pos.do_move(ms.move, st, ci, pos.move_gives_check(ms.move, ci));
                cnt += perft(pos, depth - DepthC.ONE_PLY);
                pos.undo_move(ms.move);
            }
            CheckInfoBroker.Free();
            MListBroker.Free();
            return cnt;
        }
Beispiel #9
0
        // Position::do(undo)_null_move() is used to do(undo) a "null move": It flips
        // the side to move without executing any move on the board.
        internal void do_null_move(StateInfo newSt)
        {
            Debug.Assert(!this.in_check());

            newSt.capturedType = st.capturedType;
            newSt.castleRights = st.castleRights;
            newSt.rule50 = st.rule50;
            newSt.pliesFromNull = st.pliesFromNull;
            newSt.checkersBB = st.checkersBB;
            newSt.epSquare = st.epSquare;
            newSt.key = st.key;
            newSt.npMaterialWHITE = st.npMaterialWHITE;
            newSt.npMaterialBLACK = st.npMaterialBLACK;
            newSt.pawnKey = st.pawnKey;
            newSt.materialKey = st.materialKey;
            newSt.psqScore = st.psqScore;
            
            newSt.previous = st;
            st = newSt;

            if (this.st.epSquare != SquareC.SQ_NONE)
            {
                this.st.key ^= Zobrist.enpassant[Utils.file_of(this.st.epSquare)];
                this.st.epSquare = SquareC.SQ_NONE;
            }

            st.key ^= Zobrist.side;
            st.rule50++;
            st.pliesFromNull = 0;

            this.sideToMove = Utils.flip_C(this.sideToMove);

            Debug.Assert(this.pos_is_ok());
        }
Beispiel #10
0
        /// clear() erases the position object to a pristine state, with an
        /// empty board, white to move, and no castling rights.
        internal void clear()
        {
            Array.Clear(this.byColorBB, 0, 2);
            Array.Clear(this.byTypeBB, 0, 8);
            Array.Clear(this.pieceCount[0], 0, 8);
            Array.Clear(this.pieceCount[1], 0, 8);
            Array.Clear(this.index, 0, 64);
            Array.Clear(this.castleRightsMask, 0, 64);
            Array.Clear(this.castleRookSquare[0], 0, 2);
            Array.Clear(this.castleRookSquare[1], 0, 2);
            Array.Clear(this.castlePath[0], 0, 2);
            Array.Clear(this.castlePath[1], 0, 2);

            this.startState.Clear();
            this.occupied_squares = 0;
            this.nodes = 0;
            this.startPosPly = 0;
            this.sideToMove = 0;
            this.thisThread = null;
            this.chess960 = false;

            this.startState.epSquare = SquareC.SQ_NONE;
            this.st = this.startState;

            for (var i = 0; i < 8; i++)
            {
                for (var j = 0; j < 16; j++)
                {
                    this.pieceList[0][i][j] = this.pieceList[1][i][j] = SquareC.SQ_NONE;
                }
            }

            for (var sq = SquareC.SQ_A1; sq <= SquareC.SQ_H8; sq++)
            {
                this.board[sq] = PieceC.NO_PIECE;
            }
        }
Beispiel #11
0
 internal void undo_null_move(StateInfo backupSt)
 {
     Debug.Assert(!this.in_check());
     
     st = st.previous;
     this.sideToMove = Utils.flip_C(this.sideToMove);
 }
Beispiel #12
0
        /// undo_move() unmakes a move. When it returns, the position should
        /// be restored to exactly the same state as before the move was made.
        internal void undo_move(int m)
        {
            Debug.Assert(Utils.is_ok_M(m));

            this.sideToMove = this.sideToMove ^ 1;

            var us = this.sideToMove;
            var them = us ^ 1;
            var from = ((m >> 6) & 0x3F);
            var to = (m & 0x3F);
            var pt = Utils.type_of(piece_on(to));
            var capture = this.st.capturedType;

            Debug.Assert(this.is_empty(from) || Utils.type_of_move(m) == MoveTypeC.CASTLING);
            Debug.Assert(capture != PieceTypeC.KING);

            if (Utils.type_of_move(m) == MoveTypeC.PROMOTION)
            {
                var promotion = (((m >> 12) & 3) + 2);

                Debug.Assert(promotion == pt);
                Debug.Assert(Utils.relative_rank_CS(us, to) == RankC.RANK_8);
                Debug.Assert(promotion >= PieceTypeC.KNIGHT && promotion <= PieceTypeC.QUEEN);

                // Replace the promoted piece with the pawn
                this.byTypeBB[promotion] ^= Utils.SquareBB[to];
                this.byTypeBB[PieceTypeC.PAWN] |= Utils.SquareBB[to];
                this.board[to] = ((us << 3) | PieceTypeC.PAWN);

                // Update piece lists, move the last promoted piece at index[to] position
                // and shrink the list. Add a new pawn to the list.
                var lastSquare = this.pieceList[us][promotion][--this.pieceCount[us][promotion]];
                this.index[lastSquare] = this.index[to];
                var plUsPromotion = this.pieceList[us][promotion];
                plUsPromotion[this.index[lastSquare]] = lastSquare;
                plUsPromotion[this.pieceCount[us][promotion]] = SquareC.SQ_NONE;
                this.index[to] = this.pieceCount[us][PieceTypeC.PAWN]++;
                this.pieceList[us][PieceTypeC.PAWN][this.index[to]] = to;

                pt = PieceTypeC.PAWN;
            }

            if (Utils.type_of_move(m) == MoveTypeC.CASTLING)
            {
                bool kingSide = to > from;
                Square rfrom = to; // Castle is encoded as "king captures friendly rook"
                Square rto = Utils.relative_square(us, kingSide ? SquareC.SQ_F1 : SquareC.SQ_D1);
                to = Utils.relative_square(us, kingSide ? SquareC.SQ_G1 : SquareC.SQ_C1);
                capture = PieceTypeC.NO_PIECE_TYPE;
                pt = PieceTypeC.KING;
                do_castle(to, from, rto, rfrom);
            }
            else
            {
                // Put the piece back at the source square
                Bitboard from_to_bb = Utils.SquareBB[from] ^ Utils.SquareBB[to];
                occupied_squares ^= from_to_bb;
                byTypeBB[pt] ^= from_to_bb;
                byColorBB[us] ^= from_to_bb;
                
                board[to] = PieceC.NO_PIECE;
                board[from] = Utils.make_piece(us, pt);
                
                // Update piece lists, index[to] is not updated and becomes stale. This
                // works as long as index[] is accessed just by known occupied squares.
                index[from] = index[to];
                pieceList[us][pt][index[from]] = from;
            }

            if (capture != 0)
            {
                var capsq = to;

                if (Utils.type_of_move(m) == MoveTypeC.ENPASSANT)
                {
                    capsq -= (us == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S);

                    Debug.Assert(pt == PieceTypeC.PAWN);
                    Debug.Assert(to == this.st.previous.epSquare);
                    Debug.Assert(Utils.relative_rank_CS(us, to) == RankC.RANK_6);
                    Debug.Assert(this.piece_on(capsq) == PieceC.NO_PIECE);
                }

                // Restore the captured piece
                var capSqMask = Utils.SquareBB[capsq];
                this.occupied_squares |= capSqMask;
                this.byTypeBB[capture] |= capSqMask;
                this.byColorBB[them] |= capSqMask;
                this.board[capsq] = ((them << 3) | capture);

                // Update piece list, add a new captured piece in capsq square
                this.index[capsq] = this.pieceCount[them][capture]++;
                this.pieceList[them][capture][this.index[capsq]] = capsq;
            }

            // Finally point our state pointer back to the previous state
            this.st = this.st.previous;

            Debug.Assert(this.pos_is_ok());
        }
Beispiel #13
0
        internal void do_move(int m, StateInfo newSt, CheckInfo ci, bool moveIsCheck)
        {
            Debug.Assert(Utils.is_ok_M(m));
            Debug.Assert(newSt != this.st);

            this.nodes++;
            var k = this.st.key;

            newSt.pawnKey = this.st.pawnKey;
            newSt.materialKey = this.st.materialKey;
            newSt.npMaterialWHITE = this.st.npMaterialWHITE;
            newSt.npMaterialBLACK = this.st.npMaterialBLACK;
            newSt.castleRights = this.st.castleRights;
            newSt.rule50 = this.st.rule50;
            newSt.pliesFromNull = this.st.pliesFromNull;
            newSt.psqScore = this.st.psqScore;
            newSt.epSquare = this.st.epSquare;

            newSt.previous = this.st;
            this.st = newSt;

            // Update side to move
            k ^= Zobrist.side;

            // Increment the 50 moves rule draw counter. Resetting it to zero in the
            // case of a capture or a pawn move is taken care of later.
            this.st.rule50++;
            this.st.pliesFromNull++;

            var us = this.sideToMove;
            var them = us ^ 1;
            Square from = Utils.from_sq(m);
            Square to = Utils.to_sq(m);
            Piece piece = piece_on(from);
            PieceType pt = Utils.type_of(piece);
            PieceType capture = Utils.type_of_move(m) == MoveTypeC.ENPASSANT ? PieceTypeC.PAWN : Utils.type_of(piece_on(to));

            Debug.Assert(Utils.color_of(piece) == us);
            Debug.Assert(piece_on(to) == PieceC.NO_PIECE || Utils.color_of(piece_on(to)) == them || Utils.type_of_move(m) == MoveTypeC.CASTLING);
            Debug.Assert(capture != PieceTypeC.KING);

            if (Utils.type_of_move(m) == MoveTypeC.CASTLING)
            {
                Debug.Assert(piece == Utils.make_piece(us, PieceTypeC.KING));
                
                bool kingSide = to > from;
                Square rfrom = to; // Castle is encoded as "king captures friendly rook"
                Square rto = Utils.relative_square(us, kingSide ? SquareC.SQ_F1 : SquareC.SQ_D1);
                to = Utils.relative_square(us, kingSide ? SquareC.SQ_G1 : SquareC.SQ_C1);
                capture = PieceTypeC.NO_PIECE_TYPE;
                
                do_castle(from, to, rfrom, rto);
                
                st.psqScore += psq_delta(Utils.make_piece(us, PieceTypeC.ROOK), rfrom, rto);
                k ^= Zobrist.psq[us][PieceTypeC.ROOK][rfrom] ^ Zobrist.psq[us][PieceTypeC.ROOK][rto];
            }

            if (capture != 0)
            {
                var capsq = to;

                // If the captured piece is a pawn, update pawn hash key, otherwise
                // update non-pawn material.
                if (capture == PieceTypeC.PAWN)
                {
                    if (Utils.type_of_move(m) == MoveTypeC.ENPASSANT)
                    {
                        capsq += (them == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S);

                        Debug.Assert(pt == PieceTypeC.PAWN);
                        Debug.Assert(to == this.st.epSquare);
                        Debug.Assert(Utils.relative_rank_CS(us, to) == RankC.RANK_6);
                        Debug.Assert(this.piece_on(to) == PieceC.NO_PIECE);
                        Debug.Assert(this.piece_on(capsq) == Utils.make_piece(them, PieceTypeC.PAWN));

                        this.board[capsq] = PieceC.NO_PIECE;
                    }

                    this.st.pawnKey ^= Zobrist.psq[them][PieceTypeC.PAWN][capsq];
                }
                else
                {
                    if (them == 0)
                    {
                        this.st.npMaterialWHITE -= PieceValue[PhaseC.MG][capture];
                    }
                    else
                    {
                        this.st.npMaterialBLACK -= PieceValue[PhaseC.MG][capture];
                    }
                }

                // Remove the captured piece
                var capPieceMask = Utils.SquareBB[capsq];
                this.occupied_squares ^= capPieceMask;
                this.byTypeBB[capture] ^= capPieceMask;
                this.byColorBB[them] ^= capPieceMask;

                // Update piece list, move the last piece at index[capsq] position and
                // shrink the list.
                //
                // WARNING: This is a not revresible operation. When we will reinsert the
                // captured piece in undo_move() we will put it at the end of the list and
                // not in its original place, it means index[] and pieceList[] are not
                // guaranteed to be invariant to a do_move() + undo_move() sequence.
                var plThemCapture = this.pieceList[them][capture];
                var pcThemCapture = --this.pieceCount[them][capture];
                var lastSquare = plThemCapture[pcThemCapture];
                this.index[lastSquare] = this.index[capsq];
                plThemCapture[this.index[lastSquare]] = lastSquare;
                plThemCapture[pcThemCapture] = SquareC.SQ_NONE;

                // Update hash keys
                k ^= Zobrist.psq[them][capture][capsq];
                this.st.materialKey ^= Zobrist.psq[them][capture][pcThemCapture];

                // Update incremental scores
                this.st.psqScore -= Zobrist.PieceSquareTable[((them << 3) | capture)][capsq];

                // Reset rule 50 counter
                this.st.rule50 = 0;
            }

            // Update hash key
            k ^= Zobrist.psq[us][pt][from] ^ Zobrist.psq[us][pt][to];

            // Reset en passant square
            if (this.st.epSquare != SquareC.SQ_NONE)
            {
                k ^= Zobrist.enpassant[this.st.epSquare & 7];
                this.st.epSquare = SquareC.SQ_NONE;
            }

            // Update castle rights if needed
            if ((this.st.castleRights != 0) && ((this.castleRightsMask[from] | this.castleRightsMask[to]) != 0))
            {
                var cr = this.castleRightsMask[from] | this.castleRightsMask[to];
                k ^= Zobrist.castle[this.st.castleRights & cr];
                this.st.castleRights &= ~cr;
            }

            // Move the piece. The tricky Chess960 castle is handled earlier
            if (Utils.type_of_move(m) != MoveTypeC.CASTLING)
            {
                Bitboard from_to_bb = Utils.SquareBB[from] ^ Utils.SquareBB[to];
                occupied_squares ^= from_to_bb;
                byTypeBB[pt] ^= from_to_bb;
                byColorBB[us] ^= from_to_bb;
                
                board[from] = PieceC.NO_PIECE;
                board[to] = piece;
                
                      // Update piece lists, index[from] is not updated and becomes stale. This
                      // works as long as index[] is accessed just by known occupied squares.
                index[to] = index[from];
                pieceList[us][pt][index[to]] = to;
            }

            // If the moving piece is a pawn do some special extra work
            if (pt == PieceTypeC.PAWN)
            {
                // Set en-passant square, only if moved pawn can be captured
                if ((to ^ from) == 16
                    && ((((Utils.StepAttacksBB[((us << 3) | PieceTypeC.PAWN)][
                        from + (us == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S)])
                          & (this.byTypeBB[PieceTypeC.PAWN] & this.byColorBB[them]))) != 0))
                {
                    this.st.epSquare = ((from + to) / 2);
                    k ^= Zobrist.enpassant[this.st.epSquare & 7];
                }

                if (Utils.type_of_move(m) == MoveTypeC.PROMOTION)
                {
                    var promotion = (((m >> 12) & 3) + 2);

                    Debug.Assert(Utils.relative_rank_CS(us, to) == RankC.RANK_8);
                    Debug.Assert(promotion >= PieceTypeC.KNIGHT && promotion <= PieceTypeC.QUEEN);

                    // Replace the pawn with the promoted piece
                    this.byTypeBB[PieceTypeC.PAWN] ^= Utils.SquareBB[to];
                    this.byTypeBB[promotion] |= Utils.SquareBB[to];
                    this.board[to] = ((us << 3) | promotion);

                    // Update piece lists, move the last pawn at index[to] position
                    // and shrink the list. Add a new promotion piece to the list.
                    var plUsPawn = this.pieceList[us][PieceTypeC.PAWN];
                    var lastSquare = plUsPawn[--this.pieceCount[us][PieceTypeC.PAWN]];
                    this.index[lastSquare] = this.index[to];
                    plUsPawn[this.index[lastSquare]] = lastSquare;
                    plUsPawn[this.pieceCount[us][PieceTypeC.PAWN]] = SquareC.SQ_NONE;
                    this.index[to] = this.pieceCount[us][promotion];
                    this.pieceList[us][promotion][this.index[to]] = to;

                    // Update hash keys
                    k ^= Zobrist.psq[us][PieceTypeC.PAWN][to] ^ Zobrist.psq[us][promotion][to];
                    this.st.pawnKey ^= Zobrist.psq[us][PieceTypeC.PAWN][to];
                    this.st.materialKey ^= Zobrist.psq[us][promotion][this.pieceCount[us][promotion]++]
                                           ^ Zobrist.psq[us][PieceTypeC.PAWN][this.pieceCount[us][PieceTypeC.PAWN]];

                    // Update incremental score
                    this.st.psqScore += Zobrist.PieceSquareTable[((us << 3) | promotion)][to]
                                        - Zobrist.PieceSquareTable[((us << 3) | PieceTypeC.PAWN)][to];

                    // Update material
                    if (us == 0)
                    {
                        this.st.npMaterialWHITE += PieceValue[PhaseC.MG][promotion];
                    }
                    else
                    {
                        this.st.npMaterialBLACK += PieceValue[PhaseC.MG][promotion];
                    }
                }

                // Update pawn hash key
                this.st.pawnKey ^= Zobrist.psq[us][PieceTypeC.PAWN][from] ^ Zobrist.psq[us][PieceTypeC.PAWN][to];

                // Reset rule 50 draw counter
                this.st.rule50 = 0;
            }

            // Update incremental scores
            this.st.psqScore += (Zobrist.PieceSquareTable[piece][to] - Zobrist.PieceSquareTable[piece][from]);

            // Set capture piece
            this.st.capturedType = capture;

            // Update the key with the final value
            this.st.key = k;

            // Update checkers bitboard, piece must be already moved
            this.st.checkersBB = 0;

            if (moveIsCheck)
            {
                if (Utils.type_of_move(m) != MoveTypeC.NORMAL)
                {
                    this.st.checkersBB = this.attackers_to(this.pieceList[them][PieceTypeC.KING][0])
                                         & this.byColorBB[us];
                }
                else
                {
                    // Direct checks
                    if ((ci.checkSq[pt] & Utils.SquareBB[to]) != 0)
                    {
                        this.st.checkersBB |= Utils.SquareBB[to];
                    }

                    // Discovery checks
                    if ((ci.dcCandidates != 0) && ((ci.dcCandidates & Utils.SquareBB[from]) != 0))
                    {
                        if (pt != PieceTypeC.ROOK)
                        {
                            this.st.checkersBB |= this.attacks_from_ROOK(this.pieceList[them][PieceTypeC.KING][0])
                                                  & ((this.byTypeBB[PieceTypeC.ROOK] | this.byTypeBB[PieceTypeC.QUEEN])
                                                     & this.byColorBB[us]);
                        }

                        if (pt != PieceTypeC.BISHOP)
                        {
                            this.st.checkersBB |= this.attacks_from_BISHOP(this.pieceList[them][PieceTypeC.KING][0])
                                                  & ((this.byTypeBB[PieceTypeC.BISHOP] | this.byTypeBB[PieceTypeC.QUEEN])
                                                     & this.byColorBB[us]);
                        }
                    }
                }
            }

            // Finish
            this.sideToMove = this.sideToMove ^ 1;

            Debug.Assert(this.pos_is_ok());
        }
Beispiel #14
0
        /// Wait for a command from the user, parse this text string as an UCI command,
        /// and call the appropriate functions. Also intercepts EOF from stdin to ensure
        /// that we exit gracefully if the GUI dies unexpectedly. In addition to the UCI
        /// commands, the function also supports a few debug commands.
        internal static void loop(string args)
        {
            for (var i = 0; i < 102; i++)
            {
                StateRingBuf[i] = new StateInfo();
            }

            var pos = new Position(StartFEN, false, Threads.main_thread()); // The root position
            string cmd, token = string.Empty;

            while (token != "quit")
            {
                if (args.Length > 0)
                {
                    cmd = args;
                }
                else if (string.IsNullOrEmpty(cmd = Plug.ReadLine())) // Block here waiting for input
                {
                    cmd = "quit";
                }
                var stack = Utils.CreateStack(cmd);

                token = stack.Pop();

                if (token == "quit" || token == "stop" || token == "ponderhit")
                {
                    // GUI sends 'ponderhit' to tell us to ponder on the same move the
                    // opponent has played. In case Signals.stopOnPonderhit is set we are
                    // waiting for 'ponderhit' to stop the search (for instance because we
                    // already ran out of time), otherwise we should continue searching but
                    // switching from pondering to normal search.

                    if (token != "ponderhit" || Search.SignalsStopOnPonderhit)
                    {
                        Search.SignalsStop = true;
                        Threads.main_thread().notify_one(); // Could be sleeping
                    }
                    else
                    {
                        Search.Limits.ponder = false;
                    }
                }
                else if (token == "go")
                {
                    go(pos, stack);
                }
                else if (token == "ucinewgame")
                {
                    TT.clear();
                }
                else if (token == "isready")
                {
                    Plug.Write("readyok");
                    Plug.Write(Constants.endl);
                }
                else if (token == "position")
                {
                    set_position(pos, stack);
                }
                else if (token == "setoption")
                {
                    set_option(stack);
                }
                else if (token == "validmoves")
                {
                    Search.validmoves(pos, stack);
                }
                else if (token == "d")
                {
                    pos.print(0);
                }
                else if (token == "flip")
                {
                    pos.flip();
                }
                else if (token == "eval")
                {
                    Plug.Write(Evaluate.trace(pos));
                    Plug.Write(Constants.endl);
                }
                else if (token == "bench")
                {
                    Benchmark.benchmark(pos, stack);
                }
                else if (token == "key")
                {
                    Plug.Write("key: ");
                    Plug.Write(string.Format("{0:X}", pos.key()));
                    Plug.Write("\nmaterial key: ");
                    Plug.Write(pos.material_key().ToString());
                    Plug.Write("\npawn key: ");
                    Plug.Write(pos.pawn_key().ToString());
                    Plug.Write(Constants.endl);
                }
                else if (token == "uci")
                {
                    Plug.Write("id name ");
                    Plug.Write(Utils.engine_info(true));
                    Plug.Write("\n");
                    Plug.Write(OptionMap.Instance.ToString());
                    Plug.Write("\nuciok");
                    Plug.Write(Constants.endl);
                }
                else if (token == "perft")
                {
                    token = stack.Pop(); // Read depth
                    var ss =
                        Utils.CreateStack(
                            string.Format(
                                "{0} {1} {2} current perft",
                                OptionMap.Instance["Hash"].v,
                                OptionMap.Instance["Threads"].v,
                                token));
                    Benchmark.benchmark(pos, ss);
                }
                else
                {
                    Plug.Write("Unknown command: ");
                    Plug.Write(cmd);
                    Plug.Write(Constants.endl);
                }

                if (args.Length > 0) // Command line arguments have one-shot behaviour
                {
                    Threads.wait_for_think_finished();
                    break;
                }
            }
        }
Beispiel #15
0
        internal void do_move(Move m, StateInfo newSt, CheckInfo ci, bool moveIsCheck)
        {
            Debug.Assert(Utils.is_ok_M(m));
            Debug.Assert(newSt != st);

            nodes++;
            Key k = st.key;

            newSt.pawnKey = st.pawnKey;
            newSt.materialKey = st.materialKey;
            newSt.npMaterialWHITE = st.npMaterialWHITE;
            newSt.npMaterialBLACK = st.npMaterialBLACK;
            newSt.castleRights = st.castleRights;
            newSt.rule50 = st.rule50;
            newSt.pliesFromNull = st.pliesFromNull;
            newSt.psqScore = st.psqScore;
            newSt.epSquare = st.epSquare;

            newSt.previous = st;
            st = newSt;

            // Update side to move
            k ^= zobSideToMove;

            // Increment the 50 moves rule draw counter. Resetting it to zero in the
            // case of a capture or a pawn move is taken care of later.
            st.rule50++;
            st.pliesFromNull++;

            if ((m & (3 << 14)) == (3 << 14))
            {
                st.key = k;
                do_castle_move(true, m);
                return;
            }

            Color us = sideToMove;
            Color them = us ^ 1;
            Square from = ((m >> 6) & 0x3F);
            Square to = (m & 0x3F);
            Piece piece = board[from];
            PieceType pt = (piece & 7);
            PieceType capture = ((m & (3 << 14)) == (2 << 14)) ? PieceTypeC.PAWN : (board[to] & 7);

            Debug.Assert(Utils.color_of(piece) == us);
            Debug.Assert(Utils.color_of(piece_on(to)) != us);
            Debug.Assert(capture != PieceTypeC.KING);

            if (capture != 0)
            {
                Square capsq = to;

                // If the captured piece is a pawn, update pawn hash key, otherwise
                // update non-pawn material.
                if (capture == PieceTypeC.PAWN)
                {
                    if ((m & (3 << 14)) == (2 << 14))
                    {
                        capsq += (them == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S);

                        Debug.Assert(pt == PieceTypeC.PAWN);
                        Debug.Assert(to == st.epSquare);
                        Debug.Assert(Utils.relative_rank_CS(us, to) == RankC.RANK_6);
                        Debug.Assert(piece_on(to) == PieceC.NO_PIECE);
                        Debug.Assert(piece_on(capsq) == Utils.make_piece(them, PieceTypeC.PAWN));

                        board[capsq] = PieceC.NO_PIECE;
                    }

                    st.pawnKey ^= zobrist[them][PieceTypeC.PAWN][capsq];
                }
                else
                {
                    if (them == 0) { st.npMaterialWHITE -= PieceValueMidgame[capture]; } else { st.npMaterialBLACK -= PieceValueMidgame[capture]; }
                }

                // Remove the captured piece
                Bitboard capPieceMask = Utils.SquareBB[capsq];
                occupied_squares ^= capPieceMask;
                byTypeBB[capture] ^= capPieceMask;
                byColorBB[them] ^= capPieceMask;

                // Update piece list, move the last piece at index[capsq] position and
                // shrink the list.
                //
                // WARNING: This is a not revresible operation. When we will reinsert the
                // captured piece in undo_move() we will put it at the end of the list and
                // not in its original place, it means index[] and pieceList[] are not
                // guaranteed to be invariant to a do_move() + undo_move() sequence.
                int[] plThemCapture = pieceList[them][capture];
                int pcThemCapture = --pieceCount[them][capture];
                Square lastSquare = plThemCapture[pcThemCapture];
                index[lastSquare] = index[capsq];
                plThemCapture[index[lastSquare]] = lastSquare;
                plThemCapture[pcThemCapture] = SquareC.SQ_NONE;

                // Update hash keys
                k ^= zobrist[them][capture][capsq];
                st.materialKey ^= zobrist[them][capture][pcThemCapture];

                // Update incremental scores
                st.psqScore -= pieceSquareTable[((them << 3) | capture)][capsq];

                // Reset rule 50 counter
                st.rule50 = 0;
            }

            // Update hash key
            k ^= zobrist[us][pt][from] ^ zobrist[us][pt][to];

            // Reset en passant square
            if (st.epSquare != SquareC.SQ_NONE)
            {
                k ^= zobEp[st.epSquare & 7];
                st.epSquare = SquareC.SQ_NONE;
            }

            // Update castle rights if needed
            if ((st.castleRights != 0) && ((castleRightsMask[from] | castleRightsMask[to]) != 0))
            {
                int cr = castleRightsMask[from] | castleRightsMask[to];
                k ^= zobCastle[st.castleRights & cr];
                st.castleRights &= ~cr;
            }

            // Move the piece
            Bitboard from_to_bb = Utils.SquareBB[from] ^ Utils.SquareBB[to];
            occupied_squares ^= from_to_bb;
            byTypeBB[pt] ^= from_to_bb;
            byColorBB[us] ^= from_to_bb;

            board[to] = board[from];
            board[from] = PieceC.NO_PIECE;

            // Update piece lists, index[from] is not updated and becomes stale. This
            // works as long as index[] is accessed just by known occupied squares.
            index[to] = index[from];
            pieceList[us][pt][index[to]] = to;

            // If the moving piece is a pawn do some special extra work
            if (pt == PieceTypeC.PAWN)
            {
                // Set en-passant square, only if moved pawn can be captured
                if ((to ^ from) == 16
                    && ((((Utils.StepAttacksBB[((us << 3) | PieceTypeC.PAWN)][from + (us == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S)]) & (byTypeBB[PieceTypeC.PAWN] & byColorBB[them]))) != 0))
                {
                    st.epSquare = ((from + to) / 2);
                    k ^= zobEp[st.epSquare & 7];
                }

                if ((m & (3 << 14)) == (1 << 14))
                {
                    PieceType promotion = (((m >> 12) & 3) + 2);

                    Debug.Assert(Utils.relative_rank_CS(us, to) == RankC.RANK_8);
                    Debug.Assert(promotion >= PieceTypeC.KNIGHT && promotion <= PieceTypeC.QUEEN);

                    // Replace the pawn with the promoted piece
                    byTypeBB[PieceTypeC.PAWN] ^= Utils.SquareBB[to];
                    byTypeBB[promotion] |= Utils.SquareBB[to];
                    board[to] = ((us << 3) | promotion);

                    // Update piece lists, move the last pawn at index[to] position
                    // and shrink the list. Add a new promotion piece to the list.
                    int[] plUsPawn = pieceList[us][PieceTypeC.PAWN];
                    Square lastSquare = plUsPawn[--pieceCount[us][PieceTypeC.PAWN]];
                    index[lastSquare] = index[to];
                    plUsPawn[index[lastSquare]] = lastSquare;
                    plUsPawn[pieceCount[us][PieceTypeC.PAWN]] = SquareC.SQ_NONE;
                    index[to] = pieceCount[us][promotion];
                    pieceList[us][promotion][index[to]] = to;

                    // Update hash keys
                    k ^= zobrist[us][PieceTypeC.PAWN][to] ^ zobrist[us][promotion][to];
                    st.pawnKey ^= zobrist[us][PieceTypeC.PAWN][to];
                    st.materialKey ^= zobrist[us][promotion][pieceCount[us][promotion]++]
                                      ^ zobrist[us][PieceTypeC.PAWN][pieceCount[us][PieceTypeC.PAWN]];

                    // Update incremental score
                    st.psqScore += pieceSquareTable[((us << 3) | promotion)][to] - pieceSquareTable[((us << 3) | PieceTypeC.PAWN)][to];

                    // Update material
                    if (us == 0) { st.npMaterialWHITE += PieceValueMidgame[promotion]; }
                    else { st.npMaterialBLACK += PieceValueMidgame[promotion]; }
                }

                // Update pawn hash key
                st.pawnKey ^= zobrist[us][PieceTypeC.PAWN][from] ^ zobrist[us][PieceTypeC.PAWN][to];

                // Reset rule 50 draw counter
                st.rule50 = 0;
            }

            // Update incremental scores
            st.psqScore += (pieceSquareTable[piece][to] - pieceSquareTable[piece][from]);

            // Set capture piece
            st.capturedType = capture;

            // Update the key with the final value
            st.key = k;

            // Update checkers bitboard, piece must be already moved
            st.checkersBB = 0;

            if (moveIsCheck)
            {
                if ((m & (3 << 14)) != 0)
                    st.checkersBB = attackers_to(pieceList[them][PieceTypeC.KING][0]) & byColorBB[us];
                else
                {
                    // Direct checks
                    if ((ci.checkSq[pt] & Utils.SquareBB[to]) != 0)
                    {
                        st.checkersBB |= Utils.SquareBB[to];
                    }

                    // Discovery checks
                    if ((ci.dcCandidates != 0) && ((ci.dcCandidates & Utils.SquareBB[from]) != 0))
                    {
                        if (pt != PieceTypeC.ROOK)
                            st.checkersBB |= attacks_from_ROOK(pieceList[them][PieceTypeC.KING][0]) & ((byTypeBB[PieceTypeC.ROOK] | byTypeBB[PieceTypeC.QUEEN]) & byColorBB[us]);

                        if (pt != PieceTypeC.BISHOP)
                            st.checkersBB |= attacks_from_BISHOP(pieceList[them][PieceTypeC.KING][0]) & ((byTypeBB[PieceTypeC.BISHOP] | byTypeBB[PieceTypeC.QUEEN]) & byColorBB[us]);
                    }
                }
            }

            // Finish
            sideToMove = sideToMove ^ 1;

            Debug.Assert(pos_is_ok());
        }
Beispiel #16
0
        // Search::validmoves() will return the list of all valid moves for a 'square' in UCI notation - all valid moves for the piece occupying that square
        // The list will be empty if no square is given or there is no piece on that square or the piece have no possible moves
        internal static void validmoves(Position pos, Stack<string> stack)
        {
            if (stack.Count > 0)
            {
                var squareFromString = stack.Pop();

                var st = new StateInfo();
                var mlist = MListBroker.GetObject();
                mlist.pos = 0;
                Movegen.generate_legal(pos, mlist.moves, ref mlist.pos);

                var firstOne = true;
                for (var i = 0; i < mlist.pos; ++i)
                {
                    var ms = mlist.moves[i];
                    var m = ms.move;
                    var from = ((m >> 6) & 0x3F);
                    if (Utils.square_to_string(from) == squareFromString)
                    {
                        if (!firstOne)
                        {
                            Plug.Write(" ");
                        }
                        Plug.Write(Utils.move_to_uci(m, false));
                        firstOne = false;
                    }
                }
                MListBroker.Free();
            }
            Plug.Write(Constants.endl);
        }
Beispiel #17
0
        /// undo_move() unmakes a move. When it returns, the position should
        /// be restored to exactly the same state as before the move was made.
        internal void undo_move(Move m)
        {
            Debug.Assert(Utils.is_ok_M(m));

            sideToMove = sideToMove ^ 1;

            if ((m & (3 << 14)) == (3 << 14))
            {
                do_castle_move(false, m);
                return;
            }

            Color us = sideToMove;
            Color them = us ^ 1;
            Square from = ((m >> 6) & 0x3F);
            Square to = (m & 0x3F);
            Piece piece = board[to];
            PieceType pt = piece & 7;
            PieceType capture = st.capturedType;

            Debug.Assert(is_empty(from));
            Debug.Assert(Utils.color_of(piece) == us);
            Debug.Assert(capture != PieceTypeC.KING);

            if ((m & (3 << 14)) == (1 << 14))
            {
                PieceType promotion = (((m >> 12) & 3) + 2);

                Debug.Assert(promotion == pt);
                Debug.Assert(Utils.relative_rank_CS(us, to) == RankC.RANK_8);
                Debug.Assert(promotion >= PieceTypeC.KNIGHT && promotion <= PieceTypeC.QUEEN);

                // Replace the promoted piece with the pawn
                byTypeBB[promotion] ^= Utils.SquareBB[to];
                byTypeBB[PieceTypeC.PAWN] |= Utils.SquareBB[to];
                board[to] = ((us << 3) | PieceTypeC.PAWN);

                // Update piece lists, move the last promoted piece at index[to] position
                // and shrink the list. Add a new pawn to the list.
                Square lastSquare = pieceList[us][promotion][--pieceCount[us][promotion]];
                index[lastSquare] = index[to];
                int[] plUsPromotion = pieceList[us][promotion];
                plUsPromotion[index[lastSquare]] = lastSquare;
                plUsPromotion[pieceCount[us][promotion]] = SquareC.SQ_NONE;
                index[to] = pieceCount[us][PieceTypeC.PAWN]++;
                pieceList[us][PieceTypeC.PAWN][index[to]] = to;

                pt = PieceTypeC.PAWN;
            }

            // Put the piece back at the source square
            Bitboard from_to_bb = Utils.SquareBB[from] ^ Utils.SquareBB[to];
            occupied_squares ^= from_to_bb;
            byTypeBB[pt] ^= from_to_bb;
            byColorBB[us] ^= from_to_bb;

            board[from] = board[to];
            board[to] = PieceC.NO_PIECE;

            // Update piece lists, index[to] is not updated and becomes stale. This
            // works as long as index[] is accessed just by known occupied squares.
            index[from] = index[to];
            pieceList[us][pt][index[from]] = from;

            if (capture != 0)
            {
                Square capsq = to;

                if ((m & (3 << 14)) == (2 << 14))
                {
                    capsq -= (us == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S);

                    Debug.Assert(pt == PieceTypeC.PAWN);
                    Debug.Assert(to == st.previous.epSquare);
                    Debug.Assert(Utils.relative_rank_CS(us, to) == RankC.RANK_6);
                    Debug.Assert(piece_on(capsq) == PieceC.NO_PIECE);
                }

                // Restore the captured piece
                Bitboard capSqMask = Utils.SquareBB[capsq];
                occupied_squares |= capSqMask;
                byTypeBB[capture] |= capSqMask;
                byColorBB[them] |= capSqMask;
                board[capsq] = ((them << 3) | capture);

                // Update piece list, add a new captured piece in capsq square
                index[capsq] = pieceCount[them][capture]++;
                pieceList[them][capture][index[capsq]] = capsq;
            }

            // Finally point our state pointer back to the previous state
            st = st.previous;

            Debug.Assert(pos_is_ok());
        }
Beispiel #18
0
        /// move_to_san() takes a position and a move as input, where it is assumed
        /// that the move is a legal move for the position. The return value is
        /// a string containing the move in short algebraic notation.
        internal static string move_to_san(Position pos, Move m)
        {
            if (m == MoveC.MOVE_NONE)
                return "(none)";

            if (m == MoveC.MOVE_NULL)
                return "(null)";

            Debug.Assert(is_ok_M(m));

            Bitboard attackers;
            bool ambiguousMove, ambiguousFile, ambiguousRank;
            Square sq, from = from_sq(m);
            Square to = to_sq(m);
            PieceType pt = type_of(pos.piece_moved(m));

            StringBuilder san = new StringBuilder();

            if (is_castle(m))
                san.Append((to_sq(m) < from_sq(m) ? "O-O-O" : "O-O"));
            else
            {
                if (pt != PieceTypeC.PAWN)
                {
                    san.Append(piece_type_to_char(pt).ToString());

                    // Disambiguation if we have more then one piece with destination 'to'
                    // note that for pawns is not needed because starting file is explicit.
                    attackers = pos.attackers_to(to) & pos.pieces_PTC(pt, pos.sideToMove);
                    xor_bit(ref attackers, from);
                    ambiguousMove = ambiguousFile = ambiguousRank = false;

                    while (attackers != 0)
                    {
                        sq = pop_1st_bit(ref attackers);

                        // Pinned pieces are not included in the possible sub-set
                        if (!pos.pl_move_is_legal(make_move(sq, to), pos.pinned_pieces()))
                            continue;

                        if (file_of(sq) == file_of(from))
                            ambiguousFile = true;

                        if (rank_of(sq) == rank_of(from))
                            ambiguousRank = true;

                        ambiguousMove = true;
                    }

                    if (ambiguousMove)
                    {
                        if (!ambiguousFile)
                            san.Append(file_to_char(file_of(from)));
                        else if (!ambiguousRank)
                            san.Append(rank_to_char(rank_of(from)));
                        else
                            san.Append(square_to_string(from));
                    }
                }

                if (pos.is_capture(m))
                {
                    if (pt == PieceTypeC.PAWN)
                        san.Append(file_to_char(file_of(from)));

                    san.Append('x');
                }

                san.Append(square_to_string(to));

                if (is_promotion(m))
                {
                    san.Append('=');
                    san.Append(piece_type_to_char(promotion_type(m)));
                }
            }

            CheckInfo ci = CheckInfoBroker.GetObject();
            ci.CreateCheckInfo(pos);
            if (pos.move_gives_check(m, ci))
            {
                StateInfo st = new StateInfo();
                pos.do_move(m, st);
                MList mlist = MListBroker.GetObject(); mlist.pos = 0;
                Movegen.generate_legal(pos, mlist.moves, ref mlist.pos);
                san.Append(mlist.pos > 0 ? "+" : "#");
                MListBroker.Free();
                pos.undo_move(m);
            }
            CheckInfoBroker.Free();

            return san.ToString();
        }
Beispiel #19
0
        /// do_castle_move() is a private method used to do/undo a castling
        /// move. Note that castling moves are encoded as "king captures friendly rook"
        /// moves, for instance white short castling in a non-Chess960 game is encoded
        /// as e1h1.
        internal void do_castle_move(bool Do, Move m)
        {
            Debug.Assert(Utils.is_ok_M(m));
            Debug.Assert(Utils.is_castle(m));

            Square kto, kfrom, rfrom, rto, kAfter, rAfter;

            Color us = sideToMove;
            Square kBefore = Utils.from_sq(m);
            Square rBefore = Utils.to_sq(m);

            // Find after-castle squares for king and rook
            if (rBefore > kBefore) // O-O
            {
                kAfter = Utils.relative_square(us, SquareC.SQ_G1);
                rAfter = Utils.relative_square(us, SquareC.SQ_F1);
            }
            else // O-O-O
            {
                kAfter = Utils.relative_square(us, SquareC.SQ_C1);
                rAfter = Utils.relative_square(us, SquareC.SQ_D1);
            }

            kfrom = Do ? kBefore : kAfter;
            rfrom = Do ? rBefore : rAfter;

            kto = Do ? kAfter : kBefore;
            rto = Do ? rAfter : rBefore;

            Debug.Assert(piece_on(kfrom) == Utils.make_piece(us, PieceTypeC.KING));
            Debug.Assert(piece_on(rfrom) == Utils.make_piece(us, PieceTypeC.ROOK));

            // Move the pieces, with some care; in chess960 could be kto == rfrom
            Bitboard k_from_to_bb = Utils.SquareBB[kfrom] ^ Utils.SquareBB[kto];
            Bitboard r_from_to_bb = Utils.SquareBB[rfrom] ^ Utils.SquareBB[rto];
            byTypeBB[PieceTypeC.KING] ^= k_from_to_bb;
            byTypeBB[PieceTypeC.ROOK] ^= r_from_to_bb;
            occupied_squares ^= k_from_to_bb ^ r_from_to_bb;
            byColorBB[us] ^= k_from_to_bb ^ r_from_to_bb;

            // Update board
            Piece king = Utils.make_piece(us, PieceTypeC.KING);
            Piece rook = Utils.make_piece(us, PieceTypeC.ROOK);
            board[kfrom] = board[rfrom] = PieceC.NO_PIECE;
            board[kto] = king;
            board[rto] = rook;

            // Update piece lists
            pieceList[us][PieceTypeC.KING][index[kfrom]] = kto;
            pieceList[us][PieceTypeC.ROOK][index[rfrom]] = rto;
            int tmp = index[rfrom]; // In Chess960 could be kto == rfrom
            index[kto] = index[kfrom];
            index[rto] = tmp;

            if (Do)
            {
                // Reset capture field
                st.capturedType = PieceTypeC.NO_PIECE_TYPE;

                // Update incremental scores
                st.psqScore += psq_delta(king, kfrom, kto);
                st.psqScore += psq_delta(rook, rfrom, rto);

                // Update hash key
                st.key ^= zobrist[us][PieceTypeC.KING][kfrom] ^ zobrist[us][PieceTypeC.KING][kto];
                st.key ^= zobrist[us][PieceTypeC.ROOK][rfrom] ^ zobrist[us][PieceTypeC.ROOK][rto];

                // Clear en passant square
                if (st.epSquare != SquareC.SQ_NONE)
                {
                    st.key ^= zobEp[Utils.file_of(st.epSquare)];
                    st.epSquare = SquareC.SQ_NONE;
                }

                // Update castling rights
                st.key ^= zobCastle[st.castleRights & castleRightsMask[kfrom]];
                st.castleRights &= ~castleRightsMask[kfrom];

                // Update checkers BB
                st.checkersBB = attackers_to(king_square(Utils.flip_C(us))) & pieces_C(us);

                // Finish
                sideToMove = Utils.flip_C(sideToMove);
            }
            else
                // Undo: point our state pointer back to the previous state
                st = st.previous;

            Debug.Assert(pos_is_ok());
        }
Beispiel #20
0
        /// move_to_san() takes a position and a legal Move as input and returns its
        /// short algebraic notation representation.
        internal static string move_to_san(Position pos, int m)
        {
            if (m == MoveC.MOVE_NONE)
            {
                return "(none)";
            }

            if (m == MoveC.MOVE_NULL)
            {
                return "(null)";
            }

            Debug.Assert(pos.move_is_legal(m));

            Bitboard others, b;
            Color us = pos.sideToMove;
            var san = new StringBuilder();

            Square from = from_sq(m);
            Square to = to_sq(m);
            Piece pc = pos.piece_on(from);
            PieceType pt = type_of(pc);

            if (type_of_move(m) == MoveTypeC.CASTLING)
            {
                san.Append(to > from ? "O-O" : "O-O-O");
            }
            else
            {
                if (pt != PieceTypeC.PAWN)
                {
                    san.Append(PieceToChar[ColorC.WHITE][pt]); // Upper case

                    // Disambiguation if we have more then one piece of type 'pt' that can
                    // reach 'to' with a legal move.
                    others = b = (pos.attacks_from_PS(pc, to) & pos.pieces_PTC(pt, us)) ^ (ulong)from;
                    while (others != 0)
                    {
                        Move move = make_move(pop_lsb(ref b), to);
                        if (!pos.pl_move_is_legal(move, pos.pinned_pieces()))
                        {
                            others ^= (ulong)from_sq(move);
                        }
                    }

                    if (others != 0)
                    {
                        if ((others & file_bb_S(from)) == 0)
                        {
                            san.Append(file_to_char(file_of(from)));
                        }
                        else if ((others & rank_bb_S(from)) == 0)
                        {
                            san.Append(rank_to_char(rank_of(from)));
                        }
                        else
                        {
                            san.Append(square_to_string(from));
                        }
                    }
                }
                else if (pos.is_capture(m))
                {
                    san.Append(file_to_char(file_of(from)));
                }

                if (pos.is_capture(m))
                {
                    san.Append('x');
                }

                san.Append(square_to_string(to));

                if (type_of_move(m) == MoveTypeC.PROMOTION)
                {
                    san.Append('=');
                    san.Append(PieceToChar[ColorC.WHITE][promotion_type(m)]);
                }
            }

            var ci = CheckInfoBroker.GetObject();
            ci.CreateCheckInfo(pos);
            if (pos.move_gives_check(m, ci))
            {
                var st = new StateInfo();
                pos.do_move(m, st);
                var mlist = MListBroker.GetObject();
                mlist.pos = 0;
                Movegen.generate_legal(pos, mlist.moves, ref mlist.pos);
                san.Append(mlist.pos > 0 ? "+" : "#");
                MListBroker.Free();
                pos.undo_move(m);
            }
            CheckInfoBroker.Free();

            return san.ToString();
        }
Beispiel #21
0
        /// do_null_move() is used to do/undo a "null move": It flips the side
        /// to move and updates the hash key without executing any move on the board.
        internal void do_null_move(bool Do, StateInfo backupSt)
        {
            Debug.Assert(!in_check());

            // Back up the information necessary to undo the null move to the supplied
            // StateInfo object. Note that differently from normal case here backupSt
            // is actually used as a backup storage not as the new state. This reduces
            // the number of fields to be copied.
            StateInfo src = Do ? st : backupSt;
            StateInfo dst = Do ? backupSt : st;

            dst.key = src.key;
            dst.epSquare = src.epSquare;
            dst.psqScore = src.psqScore;
            dst.rule50 = src.rule50;
            dst.pliesFromNull = src.pliesFromNull;

            sideToMove = Utils.flip_C(sideToMove);

            if (Do)
            {
                if (st.epSquare != SquareC.SQ_NONE)
                    st.key ^= zobEp[Utils.file_of(st.epSquare)];

                st.key ^= zobSideToMove;
                st.epSquare = SquareC.SQ_NONE;
                st.rule50++;
                st.pliesFromNull = 0;
            }
            Debug.Assert(pos_is_ok());
        }
Beispiel #22
0
 internal static void init()
 {
     for (int i = 0; i < Constants.BROKER_SLOTS; i++)
     {
         _pool[i] = new StateInfo[0];
     }
 }
Beispiel #23
0
 public StateInfoArray()
 {
     for (int i = 0; i < (Constants.MAX_PLY_PLUS_2); i++) { state[i] = new StateInfo(); }
 }