示例#1
0
        /// move_to_uci() converts a move to a string in coordinate notation
        /// (g1f3, a7a8q, etc.). The only special case is castling moves, where we print
        /// in the e1g1 notation in normal chess mode, and in e1h1 notation in chess960
        /// mode. Internally castling moves are always encoded as "king captures rook".
        public static string move_to_uci(Move m, bool chess960)
        {
            Square from = Types.from_sq(m);
            Square to   = Types.to_sq(m);

            if (m == MoveS.MOVE_NONE)
            {
                return("(none)");
            }

            if (m == MoveS.MOVE_NULL)
            {
                return("0000");
            }

            if (Types.type_of_move(m) == MoveTypeS.CASTLING && !chess960)
            {
                to = Types.make_square((to > from ? FileS.FILE_G : FileS.FILE_C), Types.rank_of(from));
            }

            string move = Types.square_to_string(from) + Types.square_to_string(to);

            if (Types.type_of_move(m) == MoveTypeS.PROMOTION)
            {
                move += PieceToChar[ColorS.BLACK][Types.promotion_type(m)]; // Lower case
            }
            return(move);
        }
        /// score() assign a numerical value to each move in a move list. The moves with
        /// highest values will be picked first.
        public void score_captures()
        {
            // Winning and equal captures in the main search are ordered by MVV/LVA.
            // Suprisingly, this appears to perform slightly better than SEE based
            // move ordering. The reason is probably that in a position with a winning
            // capture, capturing a more valuable (but sufficiently defended) piece
            // first usually doesn't hurt. The opponent will have to recapture, and
            // the hanging piece will still be hanging (except in the unusual cases
            // where it is possible to recapture with the hanging piece). Exchanging
            // big pieces before capturing a hanging piece probably helps to reduce
            // the subtree size.
            // In main search we want to push captures with negative SEE values to the
            // badCaptures[] array, but instead of doing it now we delay until the move
            // has been picked up in pick_move_from_list(). This way we save some SEE
            // calls in case we get a cutoff.
            Move m;

            for (int it = 0; it != end; ++it)
            {
                m = moves[it].move;
                moves[it].value = Position.PieceValue[PhaseS.MG][pos.piece_on(Types.to_sq(m))]
                                  - Types.type_of_piece(pos.moved_piece(m));

                if (Types.type_of_move(m) == MoveTypeS.ENPASSANT)
                {
                    moves[it].value += Position.PieceValue[PhaseS.MG][PieceTypeS.PAWN];
                }

                else if (Types.type_of_move(m) == MoveTypeS.PROMOTION)
                {
                    moves[it].value += Position.PieceValue[PhaseS.MG][Types.promotion_type(m)] - Position.PieceValue[PhaseS.MG][PieceTypeS.PAWN];
                }
            }
        }
示例#3
0
        /// generate<LEGAL> generates all the legal moves in the given position
        public static int generate_legal(Position pos, ExtMove[] mlist, int mPos)
        {
            int      end, cur = mPos;
            Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
            Square   ksq    = pos.king_square(pos.side_to_move());

            end = pos.checkers() != 0 ? generate_evasions(pos, mlist, mPos)
                               : generate(pos, mlist, mPos, GenTypeS.NON_EVASIONS);
            while (cur != end)
            {
                if ((pinned != 0 || Types.from_sq(mlist[cur].move) == ksq || Types.type_of_move(mlist[cur].move) == MoveTypeS.ENPASSANT) &&
                    !pos.legal(mlist[cur].move, pinned))
                {
                    mlist[cur].move = mlist[--end].move;
                }
                else
                {
                    ++cur;
                }
            }

            return(end);
        }
示例#4
0
        /// move_to_san() takes a position and a legal Move as input and returns its
        /// short algebraic notation representation.
        public static string move_to_san(Position pos, Move m)
        {
            if (m == MoveS.MOVE_NONE)
            {
                return("(none)");
            }

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

            Debug.Assert((new MoveList(pos, GenTypeS.LEGAL).contains(m)));

            Bitboard  others, b;
            string    san  = "";
            Color     us   = pos.side_to_move();
            Square    from = Types.from_sq(m);
            Square    to   = Types.to_sq(m);
            Piece     pc   = pos.piece_on(from);
            PieceType pt   = Types.type_of_piece(pc);

            if (Types.type_of_move(m) == MoveTypeS.CASTLING)
            {
                san = to > from ? "O-O" : "O-O-O";
            }
            else
            {
                if (pt != PieceTypeS.PAWN)
                {
                    san = "" + PieceToChar[ColorS.WHITE][pt]; // Upper case

                    // A disambiguation occurs if we have more then one piece of type 'pt'
                    // that can reach 'to' with a legal move.
                    others = b = (pos.attacks_from_piece_square(pc, to) & pos.pieces_color_piecetype(us, pt)) ^ BitBoard.SquareBB[from];

                    while (b != 0)
                    {
                        Square s = BitBoard.pop_lsb(ref b);
                        if (!pos.legal(Types.make_move(s, to), pos.pinned_pieces(us)))
                        {
                            others ^= BitBoard.SquareBB[s];
                        }
                    }

                    if (0 == others)
                    { /* Disambiguation is not needed */
                    }

                    else if (0 == (others & BitBoard.file_bb_square(from)))
                    {
                        san += Types.file_to_char(Types.file_of(from));
                    }

                    else if (0 == (others & BitBoard.rank_bb_square(from)))
                    {
                        san += Types.rank_to_char(Types.rank_of(from));
                    }

                    else
                    {
                        san += Types.square_to_string(from);
                    }
                }
                else if (pos.capture(m))
                {
                    san = "" + Types.file_to_char(Types.file_of(from));
                }

                if (pos.capture(m))
                {
                    san += 'x';
                }

                san += Types.square_to_string(to);

                if (Types.type_of_move(m) == MoveTypeS.PROMOTION)
                {
                    san += "=" + PieceToChar[ColorS.WHITE][Types.promotion_type(m)];
                }
            }

            if (pos.gives_check(m, new CheckInfo(pos)))
            {
                StateInfo st = new StateInfo();
                pos.do_move(m, st);
                san += (new MoveList(pos, GenTypeS.LEGAL)).size() > 0 ? "+" : "#";
                pos.undo_move(m);
            }

            return(san);
        }
示例#5
0
        /// probe() tries to find a book move for the given position. If no move is
        /// found returns MOVE_NONE. If pickBest is true returns always the highest
        /// rated move, otherwise randomly chooses one, based on the move score.
        public Move probe(Position pos, string fName, bool pickBest)
        {
            if (fName == null || (fileName != fName && !open(fName)))
            {
                return(MoveS.MOVE_NONE);
            }

            PolyglotBook.Entry e    = new PolyglotBook.Entry();
            UInt16             best = 0;
            uint sum  = 0;
            Move move = MoveS.MOVE_NONE;
            Key  key  = polyglot_key(pos);

            stream.Seek(find_first(key) * SIZE_OF_BOOKENTRY, SeekOrigin.Begin);
            while (read(ref e) && e.key == key)
            {
                best = Math.Max(best, e.count);
                sum += e.count;

                // Choose book move according to its score. If a move has a very
                // high score it has higher probability to be choosen than a move
                // with lower score. Note that first entry is always chosen.
                if ((sum != 0 && ((((uint)RKiss.rand64()) % sum) < e.count)) ||
                    (pickBest && e.count == best))
                {
                    move = (e.move);
                }
            }

            if (move == 0)
            {
                return(MoveS.MOVE_NONE);
            }

            // A PolyGlot book move is encoded as follows:
            //
            // bit  0- 5: destination square (from 0 to 63)
            // bit  6-11: origin square (from 0 to 63)
            // bit 12-14: promotion piece (from KNIGHT == 1 to QUEEN == 4)
            //
            // Castling moves follow "king captures rook" representation. So in case book
            // move is a promotion we have to convert to our representation, in all the
            // other cases we can directly compare with a Move after having masked out
            // the special Move's flags (bit 14-15) that are not supported by PolyGlot.
            int pt = (move >> 12) & 7;

            if (pt != 0)
            {
                move = Types.make(Types.from_sq(move), Types.to_sq(move), MoveTypeS.PROMOTION, (pt + 1));
            }

            // Add 'special move' flags and verify it is legal
            for (MoveList ml = new MoveList(pos, GenTypeS.LEGAL); ml.mlist[ml.cur].move != MoveS.MOVE_NONE; ++ml)
            {
                if (move == (ml.move() ^ Types.type_of_move(ml.move())))
                {
                    return(ml.move());
                }
            }

            return(MoveS.MOVE_NONE);
        }