예제 #1
0
        public void score_evasions()
        {
            // Try good captures ordered by MVV/LVA, then non-captures if destination square
            // is not under attack, ordered by history value, then bad-captures and quiet
            // moves with a negative SEE. This last group is ordered by the SEE value.
            Move m;
            int  see;

            for (int it = 0; it != end; ++it)
            {
                m = moves[it].move;
                if ((see = pos.see_sign(m)) < ValueS.VALUE_ZERO)
                {
                    moves[it].value = see - HistoryStats.Max; // At the bottom
                }
                else if (pos.capture(m))
                {
                    moves[it].value = Position.PieceValue[PhaseS.MG][pos.piece_on(Types.to_sq(m))]
                                      - Types.type_of_piece(pos.moved_piece(m)) + HistoryStats.Max;
                }
                else
                {
                    moves[it].value = history[pos.moved_piece(m)][Types.to_sq(m)];
                }
            }
        }
예제 #2
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);
        }
예제 #3
0
        /// 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];
                }
            }
        }
예제 #4
0
        public void score_quiets()
        {
            Move m;

            for (int it = 0; it != end; ++it)
            {
                m = moves[it].move;
                moves[it].value = history[pos.moved_piece(m)][Types.to_sq(m)];
            }
        }
예제 #5
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);
        }
예제 #6
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);
        }
예제 #7
0
        /// next_move() is the most important method of the MovePicker class. It returns
        /// a new pseudo legal move every time it is called, until there are no more moves
        /// left. It picks the move with the biggest value from a list of generated moves
        /// taking care not to return the ttMove if it has already been searched.
        public Move next_move_false()
        {
            Move move;

            while (true)
            {
                while (cur == end)
                {
                    generate_next_stage();
                }

                switch (stage)
                {
                case StagesS.MAIN_SEARCH:
                case StagesS.EVASION:
                case StagesS.QSEARCH_0:
                case StagesS.QSEARCH_1:
                case StagesS.PROBCUT:
                    ++cur;
                    return(ttMove);

                case StagesS.CAPTURES_S1:
                    move = moves[pick_best(moves, cur++, end)].move;
                    if (move != ttMove)
                    {
                        if (pos.see_sign(move) >= ValueS.VALUE_ZERO)
                        {
                            return(move);
                        }

                        // Losing capture, move it to the tail of the array
                        moves[endBadCaptures--].move = move;
                    }
                    break;

                case StagesS.KILLERS_S1:
                    move = moves[cur++].move;
                    if (move != MoveS.MOVE_NONE &&
                        move != ttMove &&
                        pos.pseudo_legal(move) &&
                        !pos.capture(move))
                    {
                        return(move);
                    }
                    break;

                case StagesS.QUIETS_1_S1:
                case StagesS.QUIETS_2_S1:
                    move = moves[cur++].move;
                    if (move != ttMove &&
                        move != moves[Types.MAX_MOVES].move &&
                        move != moves[Types.MAX_MOVES + 1].move &&
                        move != moves[Types.MAX_MOVES + 2].move &&
                        move != moves[Types.MAX_MOVES + 3].move &&
                        move != moves[Types.MAX_MOVES + 4].move &&
                        move != moves[Types.MAX_MOVES + 5].move)
                    {
                        return(move);
                    }
                    break;

                case StagesS.BAD_CAPTURES_S1:
                    return(moves[cur--].move);

                case StagesS.EVASIONS_S2:
                case StagesS.CAPTURES_S3:
                case StagesS.CAPTURES_S4:
                    move = moves[pick_best(moves, cur++, end)].move;
                    if (move != ttMove)
                    {
                        return(move);
                    }
                    break;

                case StagesS.CAPTURES_S5:
                    move = moves[pick_best(moves, cur++, end)].move;
                    if (move != ttMove && pos.see(move) > captureThreshold)
                    {
                        return(move);
                    }
                    break;

                case StagesS.CAPTURES_S6:
                    move = moves[pick_best(moves, cur++, end)].move;
                    if (Types.to_sq(move) == recaptureSquare)
                    {
                        return(move);
                    }
                    break;

                case StagesS.QUIET_CHECKS_S3:
                    move = moves[cur++].move;
                    if (move != ttMove)
                    {
                        return(move);
                    }
                    break;

                case StagesS.STOP:
                    return(MoveS.MOVE_NONE);

                default:
                    Debug.Assert(false);
                    break;
                }
            }
        }