Пример #1
0
        /// RootMove::extract_pv_from_tt() builds a PV by adding moves from the TT table.
        /// We consider also failing high nodes and not only BOUND_EXACT nodes so to
        /// allow to always have a ponder move even when we fail high at root, and a
        /// long PV to print that is important for position analysis.
        internal void extract_pv_from_tt(Position pos)
        {
            StateInfoArray sia = StateInfoArrayBroker.GetObject();

            int stPos = 0;
            TTEntry tte;
            int ply = 1;
            Move m = pv[0];

            Debug.Assert(m != MoveC.MOVE_NONE && pos.is_pseudo_legal(m));

            pv.Clear();
            pv.Add(m);
            pos.do_move(m, sia.state[stPos++]);

            UInt32 ttePos = 0;

            while (TT.probe(pos.key(), ref ttePos, out tte)
               && (m = tte.move()) != MoveC.MOVE_NONE // Local copy, TT entry could change
               && pos.is_pseudo_legal(m)
               && pos.pl_move_is_legal(m, pos.pinned_pieces())
               && ply < Constants.MAX_PLY
               && (!pos.is_draw(false) || ply < 2))
            {
                pv.Add(m);
                pos.do_move(m, sia.state[stPos++]);
                ply++;
            }
            pv.Add(MoveC.MOVE_NONE);

            do pos.undo_move(pv[--ply]); while (ply != 0);

            StateInfoArrayBroker.Free();
        }
Пример #2
0
        internal ScaleFactor scale_factor_BLACK(Position pos)
        {
            if (scalingFunctionBLACK == null)
                return (factorBLACK);

            ScaleFactor sf = scalingFunctionBLACK(ColorC.BLACK, pos);
            return sf == ScaleFactorC.SCALE_FACTOR_NONE ? factorBLACK : sf;
        }
Пример #3
0
        internal ScaleFactor scale_factor_WHITE(Position pos)
        {
            if (scalingFunctionWHITE == null)
                return factorWHITE;

            ScaleFactor sf = scalingFunctionWHITE(ColorC.WHITE, pos);
            return sf == ScaleFactorC.SCALE_FACTOR_NONE ? factorWHITE : sf;
        }
Пример #4
0
        private static void generate_castle(
            int Side,
            bool Checks,
            Position pos,
            MoveStack[] ms,
            ref int mpos,
            int us)
        {
            if (pos.castle_impeded(us, Side) || (pos.can_castle_CR(Utils.make_castle_right(us, Side)) == 0))
            {
                return;
            }

            // After castling, the rook and king final positions are the same in Chess960
            // as they would be in standard chess.
            var kfrom = pos.king_square(us);
            var rfrom = pos.castle_rook_square(us, Side);
            var kto = Utils.relative_square(us, Side == CastlingSideC.KING_SIDE ? SquareC.SQ_G1 : SquareC.SQ_C1);

            var enemies = pos.pieces_C(us ^ 1);

            Debug.Assert(!pos.in_check());

            int K = pos.chess960 ? kto > kfrom ? -1 : 1 : Side == CastlingSideC.KING_SIDE ? -1 : 1;
            
            for (Square s = kto; s != kfrom; s += (Square)K)
            {
                if ((pos.attackers_to(s) & enemies) != 0)
                {
                    return;
                }
            }

            // Because we generate only legal castling moves we need to verify that
            // when moving the castling rook we do not discover some hidden checker.
            // For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1.
            if (pos.chess960 && ((pos.attackers_to(kto, Utils.xor_bit(pos.occupied_squares, rfrom)) & enemies) != 0))
            {
                return;
            }

            var m = Utils.make(kfrom, rfrom, MoveTypeC.CASTLING);

            if (Checks)
            {
                var ci = CheckInfoBroker.GetObject();
                ci.CreateCheckInfo(pos);
                var givesCheck = pos.move_gives_check(m, ci);
                CheckInfoBroker.Free();
                if (!givesCheck)
                {
                    return;
                }
            }

            ms[mpos++].move = m;
        }
Пример #5
0
        internal int scale_factor_BLACK(Position pos)
        {
            if (this.scalingFunctionBLACK == null)
            {
                return (this.factorBLACK);
            }

            var sf = this.scalingFunctionBLACK(ColorC.BLACK, pos);
            return sf == ScaleFactorC.SCALE_FACTOR_NONE ? this.factorBLACK : sf;
        }
Пример #6
0
        internal int scale_factor_WHITE(Position pos)
        {
            if (this.scalingFunctionWHITE == null)
            {
                return this.factorWHITE;
            }

            var sf = this.scalingFunctionWHITE(ColorC.WHITE, pos);
            return sf == ScaleFactorC.SCALE_FACTOR_NONE ? this.factorWHITE : sf;
        }
Пример #7
0
        public void Run(object arguments)
        {
            string[] args = (string[])arguments;

            Plug.Write(Utils.engine_info());
            Plug.Write(Constants.endl);

            CheckInfoBroker.init();
            EvalInfoBroker.init();
            SwapListBroker.init();
            MovesSearchedBroker.init();
            PositionBroker.init();
            StateInfoArrayBroker.init();

            MListBroker.init();
            LoopStackBroker.init();
            MovePickerBroker.init();
            StateInfoBroker.init();

            Utils.init();
            #if WINDOWS_RT
            #else
            Book.init();
            #endif
            Position.init();
            KPKPosition.init();
            Endgame.init();
            Search.init();
            Evaluate.init();

            Threads.init();

            // .Net warmup sequence
            Plug.IsWarmup = true;
            Position pos = new Position(Uci.StartFEN, false, Threads.main_thread());
            Stack<string> stack = Utils.CreateStack("go depth 7");
            Uci.go(pos, stack);
            Threads.wait_for_search_finished();
            Plug.IsWarmup = false;

            StringBuilder sb = new StringBuilder();
            for (int i = 1; i < args.Length; i++)
            {
                sb.Append(args[i]).Append(" ");
            }

            Uci.uci_loop(sb.ToString());

            Threads.exit();
        }
Пример #8
0
        internal void CreateCheckInfo(Position pos)
        {
            Color them = pos.sideToMove ^ 1;
            ksq = pos.pieceList[them][PieceTypeC.KING][0];

            pinned = pos.pinned_pieces();
            dcCandidates = pos.discovered_check_candidates();

            checkSq[PieceTypeC.PAWN] = Utils.StepAttacksBB[((them << 3) | PieceTypeC.PAWN)][ksq];
            checkSq[PieceTypeC.KNIGHT] = Utils.StepAttacksBB_KNIGHT[ksq];
#if X64
            checkSq[PieceTypeC.BISHOP] = Utils.BAttacks[ksq][(((pos.occupied_squares & Utils.BMasks[ksq]) * Utils.BMagics[ksq]) >> Utils.BShifts[ksq])];
            checkSq[PieceTypeC.ROOK] = Utils.RAttacks[ksq][(((pos.occupied_squares & Utils.RMasks[ksq]) * Utils.RMagics[ksq]) >> Utils.RShifts[ksq])];
#else
            checkSq[PieceTypeC.BISHOP] = pos.attacks_from_BISHOP(ksq);
            checkSq[PieceTypeC.ROOK] = pos.attacks_from_ROOK(ksq);
#endif
            checkSq[PieceTypeC.QUEEN] = checkSq[PieceTypeC.BISHOP] | checkSq[PieceTypeC.ROOK];
            checkSq[PieceTypeC.KING] = 0;
        }
Пример #9
0
        private static void generate_castle(CastlingSide Side, bool OnlyChecks, Position pos, MoveStack[] ms, ref int mpos, Color us)
        {
            if (pos.castle_impeded(us, Side) || (pos.can_castle_CR(Utils.make_castle_right(us, Side))==0) )
                return;

            // After castling, the rook and king final positions are the same in Chess960
            // as they would be in standard chess.
            Square kfrom = pos.king_square(us);
            Square rfrom = pos.castle_rook_square(us, Side);
            Square kto = Utils.relative_square(us, Side == CastlingSideC.KING_SIDE ? SquareC.SQ_G1 : SquareC.SQ_C1);

            Bitboard enemies = pos.pieces_C(us ^ 1);

            Debug.Assert(!pos.in_check());

            for (Square s = Math.Min(kfrom, kto), e = Math.Max(kfrom, kto); s <= e; s++)
                if (s != kfrom // We are not in check
                    && ((pos.attackers_to(s) & enemies) != 0))
                    return;

            // Because we generate only legal castling moves we need to verify that
            // when moving the castling rook we do not discover some hidden checker.
            // For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1.
            if (pos.chess960
                && ((pos.attackers_to(kto, Utils.xor_bit(pos.occupied_squares, rfrom)) & enemies) != 0))
                return;

            Move m = Utils.make_castle(kfrom, rfrom);

            if (OnlyChecks)
            {
                CheckInfo ci = CheckInfoBroker.GetObject();
                ci.CreateCheckInfo(pos);
                bool givesCheck = pos.move_gives_check(m, ci);
                CheckInfoBroker.Free();
                if (!givesCheck) return;
            }

            ms[mpos++].move = m;
        }
Пример #10
0
        internal static int SetupStatePos = 0; // *SetupState = StateRingBuf;

        #endregion Fields

        #region Methods

        // go() is called when engine receives the "go" UCI command. The function sets
        // the thinking time and other parameters from the input string, and then starts
        // the main searching thread.
        internal static void go(Position pos, Stack<string> stack)
        {
            string token = string.Empty;
            LimitsType limits = new LimitsType();
            List<Move> searchMoves = new List<Phase>();

            while (stack.Count > 0)
            {
                token = stack.Pop();

                if (token == "wtime")
                    limits.time[ColorC.WHITE] = int.Parse(stack.Pop());
                else if (token == "btime")
                    limits.time[ColorC.BLACK] = int.Parse(stack.Pop());
                else if (token == "winc")
                    limits.inc[ColorC.WHITE] = int.Parse(stack.Pop());
                else if (token == "binc")
                    limits.inc[ColorC.BLACK] = int.Parse(stack.Pop());
                else if (token == "movestogo")
                    limits.movesToGo = int.Parse(stack.Pop());
                else if (token == "depth")
                    limits.depth = int.Parse(stack.Pop());
                else if (token == "nodes")
                    limits.nodes = int.Parse(stack.Pop());
                else if (token == "movetime")
                    limits.movetime = int.Parse(stack.Pop());
                else if (token == "infinite")
                    limits.infinite = 1;
                else if (token == "ponder")
                    limits.ponder = true;
                else if (token == "searchmoves")
                    while ((token = stack.Pop()) != null)
                    {
                        searchMoves.Add(Utils.move_from_uci(pos, token));
                    }
            }

            Threads.start_searching(pos, limits, searchMoves);
        }
Пример #11
0
        /// PawnTable::evaluate_pawns() evaluates each pawn of the given color
        internal static Score evaluate_pawns(Color Us, Position pos, Bitboard ourPawns, Bitboard theirPawns, PawnEntry e)
        {
            Color Them = (Us == ColorC.WHITE ? ColorC.BLACK : ColorC.WHITE);

            Bitboard b;
            Square s;
            File f;
            Rank r;
            bool passed, isolated, doubled, opposed, chain, backward, candidate;
            Score value = ScoreC.SCORE_ZERO;
            Square[] pl = pos.pieceList[Us][PieceTypeC.PAWN];
            int plPos = 0;

            // Loop through all pawns of the current color and score each pawn
            while ((s = pl[plPos++]) != SquareC.SQ_NONE)
            {
                Debug.Assert(pos.piece_on(s) == Utils.make_piece(Us, PieceTypeC.PAWN));

                f = (s & 7);
                r = (s >> 3);

                // This file cannot be half open
                if (Us == ColorC.WHITE)
                {
                    e.halfOpenFilesWHITE &= ~(1 << f);
                }
                else
                {
                    e.halfOpenFilesBLACK &= ~(1 << f);
                }

                // Our rank plus previous one. Used for chain detection
                b = Utils.RankBB[r] | Utils.RankBB[Us == ColorC.WHITE ? r - 1 : r + 1];

                // Flag the pawn as passed, isolated, doubled or member of a pawn
                // chain (but not the backward one).
                chain = (ourPawns & Utils.AdjacentFilesBB[f] & b) != 0;
                isolated = (ourPawns & Utils.AdjacentFilesBB[f]) == 0;
                doubled = (ourPawns & Utils.ForwardBB[Us][s]) != 0;
                opposed = (theirPawns & Utils.ForwardBB[Us][s]) != 0;
                passed = (theirPawns & Utils.PassedPawnMask[Us][s]) == 0;

                // Test for backward pawn
                backward = false;

                // If the pawn is passed, isolated, or member of a pawn chain it cannot
                // be backward. If there are friendly pawns behind on adjacent files
                // or if can capture an enemy pawn it cannot be backward either.
                if (!(passed | isolated | chain)
                    && (((ourPawns & Utils.AttackSpanMask[Them][s])) == 0)
                    && ((((Utils.StepAttacksBB[((Us << 3) | PieceTypeC.PAWN)][s]) & theirPawns)) == 0))
                {
                    // We now know that there are no friendly pawns beside or behind this
                    // pawn on adjacent files. We now check whether the pawn is
                    // backward by looking in the forward direction on the adjacent
                    // files, and seeing whether we meet a friendly or an enemy pawn first.
                    b = Utils.StepAttacksBB[((Us << 3) | PieceTypeC.PAWN)][s];

                    // Note that we are sure to find something because pawn is not passed
                    // nor isolated, so loop is potentially infinite, but it isn't.
                    while ((b & (ourPawns | theirPawns)) == 0)
                    {
                        if (Us == ColorC.WHITE) { b <<= 8; } else { b >>= 8; }
                    }

                    // The friendly pawn needs to be at least two ranks closer than the
                    // enemy pawn in order to help the potentially backward pawn advance.
                    backward = (((b | (Us == ColorC.WHITE ? b << 8 : b >> 8)) & theirPawns) != 0);
                }

                Debug.Assert(opposed | passed | (((Utils.AttackSpanMask[Us][s] & theirPawns)) != 0));

                // A not passed pawn is a candidate to become passed if it is free to
                // advance and if the number of friendly pawns beside or behind this
                // pawn on adjacent files is higher or equal than the number of
                // enemy pawns in the forward direction on the adjacent files.
                candidate = !(opposed | passed | backward | isolated)
                           && (b = Utils.AttackSpanMask[Them][s + (Us == ColorC.WHITE ? SquareC.DELTA_N : SquareC.DELTA_S)] & ourPawns) != 0
                           && Bitcount.popcount_1s_Max15(b) >= Bitcount.popcount_1s_Max15(Utils.AttackSpanMask[Us][s] & theirPawns);

                // Passed pawns will be properly scored in evaluation because we need
                // full attack info to evaluate passed pawns. Only the frontmost passed
                // pawn on each file is considered a true passed pawn.
                if (passed && !doubled)
                {
                    if (Us == ColorC.WHITE)
                    {
                        e.passedPawnsWHITE |= Utils.SquareBB[s];
                    }
                    else
                    {
                        e.passedPawnsBLACK |= Utils.SquareBB[s];
                    }
                }

                // Score this pawn
                if (isolated)
                    value -= IsolatedPawnPenalty[opposed ? 1 : 0][f];

                if (doubled)
                    value -= DoubledPawnPenalty[opposed ? 1 : 0][f];

                if (backward)
                    value -= BackwardPawnPenalty[opposed ? 1 : 0][f];

                if (chain)
                    value += ChainBonus[f];

                if (candidate)
                    value += CandidateBonus[((s >> 3) ^ (Us * 7))];
            }
            return value;
        }
Пример #12
0
        /// PawnTable::pawn_info() takes a position object as input, computes
        /// a PawnInfo object, and returns a pointer to it. The result is also stored
        /// in an hash table, so we don't have to recompute everything when the same
        /// pawn structure occurs again.
        internal void probe(Position pos, out PawnEntry e)
        {
            Key key = pos.pawn_key();
            e = entries[((UInt32)key) & Constants.PawnTableMask];

            // If pi.key matches the position's pawn hash key, it means that we
            // have analysed this pawn structure before, and we can simply return
            // the information we found the last time instead of recomputing it.
            if (e.key == key) return;

            // Initialize PawnInfo entry
            e.key = key;
            e.passedPawnsWHITE = e.passedPawnsBLACK = 0;
            e.kingSquaresWHITE = e.kingSquaresBLACK = SquareC.SQ_NONE;
            e.halfOpenFilesWHITE = e.halfOpenFilesBLACK = 0xFF;

            // Calculate pawn attacks
            Bitboard wPawns = pos.pieces_PTC(PieceTypeC.PAWN, ColorC.WHITE);
            Bitboard bPawns = pos.pieces_PTC(PieceTypeC.PAWN, ColorC.BLACK);

            e.pawnAttacksWHITE = ((wPawns & ~Constants.FileHBB) << 9) | ((wPawns & ~Constants.FileABB) << 7);
            e.pawnAttacksBLACK = ((bPawns & ~Constants.FileHBB) >> 7) | ((bPawns & ~Constants.FileABB) >> 9);

            // Evaluate pawns for both colors and weight the result
            e.value = evaluate_pawns(ColorC.WHITE, pos, wPawns, bPawns, e)
                       - evaluate_pawns(ColorC.BLACK, pos, bPawns, wPawns, e);

            e.value = Utils.apply_weight(e.value, PawnStructureWeight);

            return;
        }
Пример #13
0
        internal Score update_safety_BLACK(Position pos, Square ksq)
        {
            kingSquaresBLACK = ksq;
            castleRightsBLACK = pos.st.castleRights & CastleRightC.BLACK_ANY;

            if (((ksq >> 3) ^ (ColorC.BLACK * 7)) > RankC.RANK_4)
                return kingSafetyBLACK = ScoreC.SCORE_ZERO;

            Value bonus = shelter_storm(ColorC.BLACK, pos, ksq);

            // If we can castle use the bonus after the castle if is bigger
            if ((pos.st.castleRights & CastleRightC.BLACK_OO) != 0)
                bonus = Math.Max(bonus, shelter_storm(ColorC.BLACK, pos, (SquareC.SQ_G1 ^ (ColorC.BLACK * 56))));

            if ((pos.st.castleRights & CastleRightC.BLACK_OOO) != 0)
                bonus = Math.Max(bonus, shelter_storm(ColorC.BLACK, pos, (SquareC.SQ_C1 ^ (ColorC.BLACK * 56))));

            return kingSafetyBLACK = (bonus << 16);
        }
Пример #14
0
        /// PawnEntry::shelter_storm() calculates shelter and storm penalties for the file
        /// the king is on, as well as the two adjacent files.
        internal static Value shelter_storm(Color Us, Position pos, Square ksq)
        {
            Color Them = (Us == ColorC.WHITE ? ColorC.BLACK : ColorC.WHITE);

            Value safety = PawnTable.MaxSafetyBonus;
            Bitboard b = pos.byTypeBB[PieceTypeC.PAWN] & (Utils.InFrontBB[Us][ksq >> 3] | Utils.RankBB[ksq >> 3]);
            Bitboard ourPawns = b & pos.byColorBB[Us] & ~Utils.RankBB[ksq >> 3];
            Bitboard theirPawns = b & pos.byColorBB[Them];
            Rank rkUs, rkThem;
            File kf = ksq & 7;

            kf = (kf == FileC.FILE_A) ? kf + 1 : ((kf == FileC.FILE_H) ? kf - 1 : kf);

            for (int f = kf - 1; f <= kf + 1; f++)
            {
                // Shelter penalty is higher for the pawn in front of the king
                b = ourPawns & Utils.FileBB[f];
                rkUs = (b != 0) ? ((Us == ColorC.WHITE ? Utils.first_1(b) : (Utils.last_1(b) ^ 56)) >> 3) : RankC.RANK_1;
                safety -= PawnTable.ShelterWeakness[f != kf ? 1 : 0][rkUs];

                // Storm danger is smaller if enemy pawn is blocked
                b = theirPawns & Utils.FileBB[f];
                rkThem = (b != 0) ? ((Us == ColorC.WHITE ? Utils.first_1(b) : (Utils.last_1(b) ^ 56)) >> 3) : RankC.RANK_1;
                safety -= PawnTable.StormDanger[rkThem == rkUs + 1 ? 1 : 0][rkThem];
            }

            return safety;
        }
Пример #15
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();
        }
Пример #16
0
 /// move_from_uci() takes a position and a string representing a move in
 /// simple coordinate notation and returns an equivalent legal Move if any.
 internal static int move_from_uci(Position pos, string str)
 {
     var strLowerPromotion = (str.Length == 5 ? str.Substring(0, 4) + str.Substring(4).ToLowerInvariant() : str);
     var mlist = MListBroker.GetObject();
     mlist.pos = 0;
     Movegen.generate_legal(pos, mlist.moves, ref mlist.pos);
     for (var i = 0; i < mlist.pos; i++)
     {
         if (strLowerPromotion == move_to_uci(mlist.moves[i].move, pos.chess960))
         {
             var retval = mlist.moves[i].move;
             MListBroker.Free();
             return retval;
         }
     }
     MListBroker.Free();
     return MoveC.MOVE_NONE;
 }
Пример #17
0
 internal static bool is_KXK(int Us, Position pos)
 {
     var Them = (Us == ColorC.WHITE ? ColorC.BLACK : ColorC.WHITE);
     return pos.non_pawn_material(Them) == ValueC.VALUE_ZERO && pos.piece_count(Them, PieceTypeC.PAWN) == 0
            && pos.non_pawn_material(Us) >= Constants.RookValueMidgame;
 }
Пример #18
0
 internal static Position GetObject()
 {
     int slotID = System.Threading.Thread.CurrentThread.ManagedThreadId & Constants.BROKER_SLOT_MASK;
     if (_cnt[slotID] == _pool[slotID].Length)
     {
         int poolLength = _pool[slotID].Length;
         Position[] temp = new Position[poolLength + Constants.BrokerCapacity];
         Array.Copy(_pool[slotID], temp, poolLength);
         for (int i = 0; i < Constants.BrokerCapacity; i++)
         {
             temp[poolLength + i] = new Position();
         }
         _pool[slotID] = temp;
     }
     return _pool[slotID][_cnt[slotID]++];
 }
Пример #19
0
        /// Book::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.
        internal static Move probe(Position pos, string filename, bool pickBest)
        {
            #if PORTABLE

            #region DLL book

            if (bookNotExists) { return MoveC.MOVE_NONE; }

            BookEntry e = new BookEntry();
            UInt16 best = 0;
            uint sum = 0;
            Move move = MoveC.MOVE_NONE;
            UInt64 key = book_key(pos);

            try
            {
                System.Reflection.Assembly bookAssembly = System.Reflection.Assembly.Load("PortfishBook");
                using (Stream fs = bookAssembly.GetManifestResourceStream("PortfishBook.book.bin"))
                {
                    UInt64 size = (UInt64)(fs.Length / SIZE_OF_BOOKENTRY);
                    using (BinaryReader br = new BinaryReader(fs))
                    {
                        binary_search(key, size, br);
                        while (Read(ref e, br) && (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 ((RKiss.rand() % sum < e.count)
                                || (pickBest && e.count == best))
                            {
                                move = e.move;
                            }
                        }
                    }
                }
            }
            catch(System.IO.FileNotFoundException)
            {
                bookNotExists = true;
                return MoveC.MOVE_NONE;
            }

            #endregion

            #else

            #region File system read

            if (!System.IO.File.Exists(filename)) return MoveC.MOVE_NONE;

            BookEntry e = new BookEntry();
            UInt16 best = 0;
            uint sum = 0;
            Move move = MoveC.MOVE_NONE;
            UInt64 key = book_key(pos);

            using (FileStream fs = new FileStream(filename, FileMode.Open))
            {
                UInt64 size = (UInt64)(fs.Length / SIZE_OF_BOOKENTRY);
                using (BinaryReader br = new BinaryReader(fs))
                {
                    binary_search(key, size, br);
                    while (Read(ref e, br) && (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) && (RKiss.rand() % sum < e.count))
                            || (pickBest && e.count == best))
                        {
                            move = e.move;
                        }
                    }
                    br.Close();
                }
                fs.Close();
            }

            #endregion

            #endif

            if (move != 0)
            {
                // 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 = Utils.make_promotion(Utils.from_sq(move), Utils.to_sq(move), (pt + 1));
                }

                // Add 'special move' flags and verify it is legal
                MList mlist = MListBroker.GetObject(); mlist.pos = 0;
                Movegen.generate_legal(pos, mlist.moves, ref mlist.pos);
                for (int i = 0; i < mlist.pos; i++)
                {
                    if (move == (mlist.moves[i].move & 0x3FFF))
                    {
                        Move retval = mlist.moves[i].move;
                        MListBroker.Free();
                        return retval;
                    }
                }
                MListBroker.Free();
            }

            return MoveC.MOVE_NONE;
        }
Пример #20
0
        // split() does the actual work of distributing the work at a node between
        // several available threads. If it does not succeed in splitting the node
        // (because no idle threads are available, or because we have no unused split
        // point objects), the function immediately returns. If splitting is possible, a
        // SplitPoint object is initialized with all the data that must be copied to the
        // helper threads and then helper threads are told that they have been assigned
        // work. This will cause them to instantly leave their idle loops and call
        // search(). When all threads have returned from search() then split() returns.
        internal static Value split(bool Fake, Position pos, Stack[] ss, int ssPos, Value alpha, Value beta,
                                    Value bestValue, ref Move bestMove, Depth depth, Move threatMove,
                                    int moveCount, MovePicker mp, int nodeType)
        {
            Debug.Assert(pos.pos_is_ok());
            Debug.Assert(bestValue > -ValueC.VALUE_INFINITE);
            Debug.Assert(bestValue <= alpha);
            Debug.Assert(alpha < beta);
            Debug.Assert(beta <= ValueC.VALUE_INFINITE);
            Debug.Assert(depth > DepthC.DEPTH_ZERO);

            Thread master = pos.this_thread();

            if (master.splitPointsCnt >= Constants.MAX_SPLITPOINTS_PER_THREAD)
                return bestValue;

            // Pick the next available split point from the split point stack
            SplitPoint sp = master.splitPoints[master.splitPointsCnt];

            sp.parent = master.curSplitPoint;
            sp.master = master;
            sp.cutoff = false;
            sp.slavesMask = 1UL << master.idx;
#if ACTIVE_REPARENT
            sp.allSlavesRunning = true;
#endif

            sp.depth = depth;
            sp.bestMove = bestMove;
            sp.threatMove = threatMove;
            sp.alpha = alpha;
            sp.beta = beta;
            sp.nodeType = nodeType;
            sp.bestValue = bestValue;
            sp.mp = mp;
            sp.moveCount = moveCount;
            sp.pos = pos;
            sp.nodes = 0;
            sp.ss = ss;
            sp.ssPos = ssPos;

            Debug.Assert(master.is_searching);
            master.curSplitPoint = sp;

            int slavesCnt = 0;

            ThreadHelper.lock_grab(sp.Lock);
            ThreadHelper.lock_grab(splitLock);

            for (int i = 0; i < size() && !Fake; ++i)
                if (threads[i].is_available_to(master))
                {
                    sp.slavesMask |= 1UL << i;
                    threads[i].curSplitPoint = sp;
                    threads[i].is_searching = true; // Slave leaves idle_loop()

                    if (useSleepingThreads)
                        threads[i].wake_up();

                    if (++slavesCnt + 1 >= maxThreadsPerSplitPoint) // Master is always included
                        break;
                }

            master.splitPointsCnt++;

            ThreadHelper.lock_release(splitLock);
            ThreadHelper.lock_release(sp.Lock);

            // Everything is set up. The master thread enters the idle loop, from which
            // it will instantly launch a search, because its is_searching flag is set.
            // We pass the split point as a parameter to the idle loop, which means that
            // the thread will return from the idle loop when all slaves have finished
            // their work at this split point.
            if (slavesCnt != 0 || Fake)
            {
                master.idle_loop(sp, null);
                // In helpful master concept a master can help only a sub-tree of its split
                // point, and because here is all finished is not possible master is booked.
                Debug.Assert(!master.is_searching);
            }

            // We have returned from the idle loop, which means that all threads are
            // finished. Note that setting is_searching and decreasing activeSplitPoints is
            // done under lock protection to avoid a race with Thread::is_available_to().
            ThreadHelper.lock_grab(sp.Lock); // To protect sp->nodes
            ThreadHelper.lock_grab(splitLock);

            master.is_searching = true;
            master.splitPointsCnt--;
            master.curSplitPoint = sp.parent;
            pos.nodes += sp.nodes;
            bestMove = sp.bestMove;

            ThreadHelper.lock_release(splitLock);
            ThreadHelper.lock_release(sp.Lock);

            return sp.bestValue;
        }
Пример #21
0
        /// MaterialTable::material_info() takes a position object as input,
        /// computes or looks up a MaterialInfo object, and returns a pointer to it.
        /// If the material configuration is not already present in the table, it
        /// is stored there, so we don't have to recompute everything when the
        /// same material configuration occurs again.
        internal void probe(Position pos, out MaterialEntry e)
        {
            var key = pos.material_key();
            e = this.entries[((uint)key) & Constants.MaterialTableMask];

            // If mi->key matches the position's material hash key, it means that we
            // have analysed this material configuration before, and we can simply
            // return the information we found the last time instead of recomputing it.
            if (e.key == key)
            {
                return;
            }

            // Initialize MaterialInfo entry
            var npm = pos.non_pawn_material(ColorC.WHITE) + pos.non_pawn_material(ColorC.BLACK);
            e.value = 0;
            e.scalingFunctionWHITE = null;
            e.scalingFunctionBLACK = null;
            e.spaceWeight = 0;
            e.key = key;
            e.factorWHITE = e.factorBLACK = ScaleFactorC.SCALE_FACTOR_NORMAL;
            e.gamePhase = npm >= MidgameLimit
                              ? PhaseC.PHASE_MIDGAME
                              : npm <= EndgameLimit
                                    ? PhaseC.PHASE_ENDGAME
                                    : (((npm - EndgameLimit) * 128) / (MidgameLimit - EndgameLimit));

            // Let's look if we have a specialized evaluation function for this
            // particular material configuration. First we look for a fixed
            // configuration one, then a generic one if previous search failed.
            if ((e.evaluationFunction = Endgame.probeValue(key, out e.evaluationFunctionColor)) != null)
            {
                return;
            }

            if (is_KXK(ColorC.WHITE, pos))
            {
                e.evaluationFunction = Endgame.Endgame_KXK;
                e.evaluationFunctionColor = ColorC.WHITE;
                return;
            }

            if (is_KXK(ColorC.BLACK, pos))
            {
                e.evaluationFunction = Endgame.Endgame_KXK;
                e.evaluationFunctionColor = ColorC.BLACK;
                return;
            }

            if ((pos.pieces_PT(PieceTypeC.PAWN) == 0) && (pos.pieces_PT(PieceTypeC.ROOK) == 0)
                && (pos.pieces_PT(PieceTypeC.QUEEN) == 0))
            {
                // Minor piece endgame with at least one minor piece per side and
                // no pawns. Note that the case KmmK is already handled by KXK.
                Debug.Assert(
                    (pos.pieces_PTC(PieceTypeC.KNIGHT, ColorC.WHITE) | pos.pieces_PTC(PieceTypeC.BISHOP, ColorC.WHITE))
                    != 0);
                Debug.Assert(
                    (pos.pieces_PTC(PieceTypeC.KNIGHT, ColorC.BLACK) | pos.pieces_PTC(PieceTypeC.BISHOP, ColorC.BLACK))
                    != 0);

                if (pos.piece_count(ColorC.WHITE, PieceTypeC.BISHOP) + pos.piece_count(ColorC.WHITE, PieceTypeC.KNIGHT)
                    <= 2
                    && pos.piece_count(ColorC.BLACK, PieceTypeC.BISHOP)
                    + pos.piece_count(ColorC.BLACK, PieceTypeC.KNIGHT) <= 2)
                {
                    e.evaluationFunction = Endgame.Endgame_KmmKm;
                    e.evaluationFunctionColor = pos.sideToMove;
                    return;
                }
            }

            // OK, we didn't find any special evaluation function for the current
            // material configuration. Is there a suitable scaling function?
            //
            // We face problems when there are several conflicting applicable
            // scaling functions and we need to decide which one to use.
            EndgameScaleFactor sf;
            int c;
            if ((sf = Endgame.probeScaleFactor(key, out c)) != null)
            {
                if (c == ColorC.WHITE)
                {
                    e.scalingFunctionWHITE = sf;
                }
                else
                {
                    e.scalingFunctionBLACK = sf;
                }
                return;
            }

            // Generic scaling functions that refer to more then one material
            // distribution. Should be probed after the specialized ones.
            // Note that these ones don't return after setting the function.
            if (is_KBPsKs(ColorC.WHITE, pos))
            {
                e.scalingFunctionWHITE = Endgame.Endgame_KBPsK;
            }

            if (is_KBPsKs(ColorC.BLACK, pos))
            {
                e.scalingFunctionBLACK = Endgame.Endgame_KBPsK;
            }

            if (is_KQKRPs(ColorC.WHITE, pos))
            {
                e.scalingFunctionWHITE = Endgame.Endgame_KQKRPs;
            }

            else if (is_KQKRPs(ColorC.BLACK, pos))
            {
                e.scalingFunctionBLACK = Endgame.Endgame_KQKRPs;
            }

            var npm_w = pos.non_pawn_material(ColorC.WHITE);
            var npm_b = pos.non_pawn_material(ColorC.BLACK);

            if (npm_w + npm_b == ValueC.VALUE_ZERO)
            {
                if (pos.piece_count(ColorC.BLACK, PieceTypeC.PAWN) == 0)
                {
                    Debug.Assert(pos.piece_count(ColorC.WHITE, PieceTypeC.PAWN) >= 2);
                    e.scalingFunctionWHITE = Endgame.Endgame_KPsK;
                }
                else if (pos.piece_count(ColorC.WHITE, PieceTypeC.PAWN) == 0)
                {
                    Debug.Assert(pos.piece_count(ColorC.BLACK, PieceTypeC.PAWN) >= 2);
                    e.scalingFunctionBLACK = Endgame.Endgame_KPsK;
                }
                else if (pos.piece_count(ColorC.WHITE, PieceTypeC.PAWN) == 1
                         && pos.piece_count(ColorC.BLACK, PieceTypeC.PAWN) == 1)
                {
                    // This is a special case because we set scaling functions
                    // for both colors instead of only one.
                    e.scalingFunctionWHITE = Endgame.Endgame_KPKP;
                    e.scalingFunctionBLACK = Endgame.Endgame_KPKP;
                }
            }

            // No pawns makes it difficult to win, even with a material advantage
            if (pos.piece_count(ColorC.WHITE, PieceTypeC.PAWN) == 0 && npm_w - npm_b <= Constants.BishopValueMidgame)
            {
                e.factorWHITE =
                    (byte)
                    (npm_w == npm_b || npm_w < Constants.RookValueMidgame
                         ? 0
                         : NoPawnsSF[Math.Min(pos.piece_count(ColorC.WHITE, PieceTypeC.BISHOP), 2)]);
            }

            if (pos.piece_count(ColorC.BLACK, PieceTypeC.PAWN) == 0 && npm_b - npm_w <= Constants.BishopValueMidgame)
            {
                e.factorBLACK =
                    (byte)
                    (npm_w == npm_b || npm_b < Constants.RookValueMidgame
                         ? 0
                         : NoPawnsSF[Math.Min(pos.piece_count(ColorC.BLACK, PieceTypeC.BISHOP), 2)]);
            }

            // Compute the space weight
            if (npm_w + npm_b
                >= 2 * Constants.QueenValueMidgame + 4 * Constants.RookValueMidgame + 2 * Constants.KnightValueMidgame)
            {
                var minorPieceCount = pos.piece_count(ColorC.WHITE, PieceTypeC.KNIGHT)
                                      + pos.piece_count(ColorC.WHITE, PieceTypeC.BISHOP)
                                      + pos.piece_count(ColorC.BLACK, PieceTypeC.KNIGHT)
                                      + pos.piece_count(ColorC.BLACK, PieceTypeC.BISHOP);

                e.spaceWeight = minorPieceCount * minorPieceCount;
            }

            // Evaluate the material imbalance. We use PIECE_TYPE_NONE as a place holder
            // for the bishop pair "extended piece", this allow us to be more flexible
            // in defining bishop pair bonuses.
            this.pieceCount[0][0] = pos.piece_count(ColorC.WHITE, PieceTypeC.BISHOP) > 1 ? 1 : 0;
            this.pieceCount[0][1] = pos.piece_count(ColorC.WHITE, PieceTypeC.PAWN);
            this.pieceCount[0][2] = pos.piece_count(ColorC.WHITE, PieceTypeC.KNIGHT);
            this.pieceCount[0][3] = pos.piece_count(ColorC.WHITE, PieceTypeC.BISHOP);
            this.pieceCount[0][4] = pos.piece_count(ColorC.WHITE, PieceTypeC.ROOK);
            this.pieceCount[0][5] = pos.piece_count(ColorC.WHITE, PieceTypeC.QUEEN);

            this.pieceCount[1][0] = pos.piece_count(ColorC.BLACK, PieceTypeC.BISHOP) > 1 ? 1 : 0;
            this.pieceCount[1][1] = pos.piece_count(ColorC.BLACK, PieceTypeC.PAWN);
            this.pieceCount[1][2] = pos.piece_count(ColorC.BLACK, PieceTypeC.KNIGHT);
            this.pieceCount[1][3] = pos.piece_count(ColorC.BLACK, PieceTypeC.BISHOP);
            this.pieceCount[1][4] = pos.piece_count(ColorC.BLACK, PieceTypeC.ROOK);
            this.pieceCount[1][5] = pos.piece_count(ColorC.BLACK, PieceTypeC.QUEEN);

            e.value = (short)((this.imbalance(ColorC.WHITE) - this.imbalance(ColorC.BLACK)) / 16);
        }
Пример #22
0
 internal static bool is_KQKRPs(int Us, Position pos)
 {
     var Them = (Us == ColorC.WHITE ? ColorC.BLACK : ColorC.WHITE);
     return pos.piece_count(Us, PieceTypeC.PAWN) == 0 && pos.non_pawn_material(Us) == Constants.QueenValueMidgame
            && pos.piece_count(Us, PieceTypeC.QUEEN) == 1 && pos.piece_count(Them, PieceTypeC.ROOK) == 1
            && pos.piece_count(Them, PieceTypeC.PAWN) >= 1;
 }
Пример #23
0
 internal static bool is_KBPsKs(int Us, Position pos)
 {
     return pos.non_pawn_material(Us) == Constants.BishopValueMidgame
            && pos.piece_count(Us, PieceTypeC.BISHOP) == 1 && pos.piece_count(Us, PieceTypeC.PAWN) >= 1;
 }
Пример #24
0
 internal Score king_safety(Color Us, Position pos, Square ksq)
 {
     if (Us == ColorC.WHITE)
     {
         return kingSquaresWHITE == ksq && castleRightsWHITE == (pos.st.castleRights & (CastleRightC.WHITE_ANY))
             ? kingSafetyWHITE : update_safety_WHITE(pos, ksq);
     }
     else
     {
         return kingSquaresBLACK == ksq && castleRightsBLACK == (pos.st.castleRights & (CastleRightC.WHITE_ANY << 2))
             ? kingSafetyBLACK : update_safety_BLACK(pos, ksq);
     }
 }
Пример #25
0
        /// benchmark() runs a simple benchmark by letting Stockfish analyze a set
        /// of positions for a given limit each. There are five parameters; the
        /// transposition table size, the number of search threads that should
        /// be used, the limit value spent for each position (optional, default is
        /// depth 12), an optional file name where to look for positions in fen
        /// format (defaults are the positions defined above) and the type of the
        /// limit value: depth (default), time in secs or number of nodes.
        internal static void benchmark(Position current, Stack<string> stack)
        {
            List<string> fens = new List<string>();

            LimitsType limits = new LimitsType();
            Int64 nodes = 0;
            Int64 nodesAll = 0;
            long e = 0;
            long eAll = 0;

            // Assign default values to missing arguments
            string ttSize = (stack.Count > 0) ? (stack.Pop()) : "128";
            string threads = (stack.Count > 0) ? (stack.Pop()) : "1";
            string limit = (stack.Count > 0) ? (stack.Pop()) : "12";
            string fenFile = (stack.Count > 0) ? (stack.Pop()) : "default";
            string limitType = (stack.Count > 0) ? (stack.Pop()) : "depth";

            OptionMap.Instance["Hash"].v = ttSize;
            OptionMap.Instance["Threads"].v = threads;
            TT.clear();

            if (limitType == "time")
                limits.movetime = 1000 * int.Parse(limit); // maxTime is in ms

            else if (limitType == "nodes")
                limits.nodes = int.Parse(limit);

            else
                limits.depth = int.Parse(limit);

            if (fenFile == "default")
            {
                fens.AddRange(Defaults);
            }
            else if (fenFile == "current")
            {
                fens.Add(current.to_fen());
            }
            else
            {
            #if PORTABLE
                throw new Exception("File cannot be read.");
            #else
                System.IO.StreamReader sr = new System.IO.StreamReader(fenFile, true);
                string fensFromFile = sr.ReadToEnd();
                sr.Close();
                sr.Dispose();

                string[] split = fensFromFile.Replace("\r", "").Split('\n');
                foreach (string fen in split)
                {
                    if (fen.Trim().Length > 0)
                    {
                        fens.Add(fen.Trim());
                    }
                }
            #endif
            }

            Stopwatch time = new Stopwatch();
            long[] res = new long[fens.Count];
            for (int i = 0; i < fens.Count; i++)
            {
                time.Reset(); time.Start();
                Position pos = new Position(fens[i], bool.Parse(OptionMap.Instance["UCI_Chess960"].v), Threads.main_thread());

                Plug.Write("\nPosition: ");
                Plug.Write((i + 1).ToString());
                Plug.Write("/");
                Plug.Write(fens.Count.ToString());
                Plug.Write(Constants.endl);

                if (limitType == "perft")
                {
                    Int64 cnt = Search.perft(pos, limits.depth * DepthC.ONE_PLY);
                    Plug.Write("\nPerft ");
                    Plug.Write(limits.depth.ToString());
                    Plug.Write(" leaf nodes: ");
                    Plug.Write(cnt.ToString());
                    Plug.Write(Constants.endl);
                    nodes = cnt;
                }
                else
                {
                    Threads.start_searching(pos, limits, new List<Move>());
                    Threads.wait_for_search_finished();
                    nodes = Search.RootPosition.nodes;
                    res[i] = nodes;
                }

                e = time.ElapsedMilliseconds;

                nodesAll += nodes;
                eAll += e;

                Plug.Write("\n===========================");
                Plug.Write("\nTotal time (ms) : ");
                Plug.Write(e.ToString());
                Plug.Write("\nNodes searched  : ");
                Plug.Write(nodes.ToString());
                Plug.Write("\nNodes/second    : ");
                Plug.Write(((int)(nodes / (e / 1000.0))).ToString());
                Plug.Write(Constants.endl);

            }

            Plug.Write("\n===========================");
            Plug.Write("\nTotal time (ms) : ");
            Plug.Write(eAll.ToString());
            Plug.Write("\nNodes searched  : ");
            Plug.Write(nodesAll.ToString());
            Plug.Write("\nNodes/second    : ");
            Plug.Write(((int)(nodesAll / (eAll / 1000.0))).ToString());
            Plug.Write(Constants.endl);

            //for (int i = 0; i < res.Length; i++)
            //{
            //    Plug.Write(string.Format("{0}: {1}", i, res[i]));
            //    Plug.Write(Constants.endl);
            //}
        }
Пример #26
0
        // ThreadsManager::start_searching() wakes up the main thread sleeping in
        // main_loop() so to start a new search, then returns immediately.
        internal static void start_searching(Position pos, LimitsType limits, List<Move> searchMoves)
        {
            wait_for_search_finished();

            Search.SearchTime.Reset(); Search.SearchTime.Start(); // As early as possible

            Search.SignalsStopOnPonderhit = Search.SignalsFirstRootMove = false;
            Search.SignalsStop = Search.SignalsFailedLowAtRoot = false;

            Search.RootPosition.copy(pos);
            Search.Limits = limits;
            Search.RootMoves.Clear();

            MList mlist = MListBroker.GetObject(); mlist.pos = 0;
            Movegen.generate_legal(pos, mlist.moves, ref mlist.pos);
            for (int i = 0; i < mlist.pos; i++)
            {
                Move move = mlist.moves[i].move;
                if ((searchMoves.Count == 0) || Utils.existSearchMove(searchMoves, move))
                {
                    Search.RootMoves.Add(new RootMove(move));
                }
            }
            MListBroker.Free();

            main_thread().do_sleep = false;
            main_thread().wake_up();
        }
Пример #27
0
 internal static void init()
 {
     for (int i = 0; i < Constants.BROKER_SLOTS; i++)
     {
         _pool[i] = new Position[0];
     }
 }
Пример #28
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;
                }

            }
        }
Пример #29
0
        // book_key() returns the PolyGlot hash key of the given position
        private static UInt64 book_key(Position pos)
        {
            UInt64 key = 0;
            Bitboard b = pos.occupied_squares;

            while (b != 0)
            {
                // Piece offset is at 64 * polyPiece where polyPiece is defined as:
                // BP = 0, WP = 1, BN = 2, WN = 3, ... BK = 10, WK = 11
                Square s = Utils.pop_1st_bit(ref b);
                Piece p = pos.piece_on(s);
                int polyPiece = 2 * (Utils.type_of(p) - 1) + (Utils.color_of(p) == ColorC.WHITE ? 1 : 0);
                key ^= PolyGlotRandoms[ZobPieceOffset + (64 * polyPiece + s)];
            }

            b = (ulong)pos.can_castle_CR(CastleRightC.ALL_CASTLES);

            while (b != 0)
                key ^= PolyGlotRandoms[ZobCastleOffset + Utils.pop_1st_bit(ref b)];

            if (pos.st.epSquare != SquareC.SQ_NONE)
                key ^= PolyGlotRandoms[ZobEnPassantOffset + Utils.file_of(pos.st.epSquare)];

            if (pos.sideToMove == ColorC.WHITE)
                key ^= PolyGlotRandoms[ZobTurnOffset + 0];

            return key;
        }
Пример #30
0
        // set_position() is called when engine receives the "position" UCI
        // command. The function sets up the position described in the given
        // fen string ("fen") or the starting position ("startpos") and then
        // makes the moves given in the following move list ("moves").
        internal static void set_position(Position pos, Stack<string> stack)
        {
            Move m;
            string token, fen = string.Empty;

            token = stack.Pop();

            if (token == "startpos")
            {
                fen = StartFEN;
                if (stack.Count > 0) { token = stack.Pop(); } // Consume "moves" token if any
            }
            else if (token == "fen")
                while ((stack.Count > 0) && (token = stack.Pop()) != "moves")
                    fen += token + " ";
            else
                return;

            pos.from_fen(fen, bool.Parse(OptionMap.Instance["UCI_Chess960"].v), Threads.main_thread());

            // Parse move list (if any)
            while ((stack.Count > 0) && (m = Utils.move_from_uci(pos, token = stack.Pop())) != MoveC.MOVE_NONE)
            {
                pos.do_move(m, StateRingBuf[SetupStatePos]);

                // Increment pointer to StateRingBuf circular buffer
                SetupStatePos = (SetupStatePos + 1) % 102;
            }
        }