Пример #1
0
        /// evaluate() is the main evaluation function. It always computes two
        /// values, an endgame score and a middle game score, and interpolates
        /// between them based on the remaining material.
        internal static int do_evaluate(bool Trace, Position pos, ref int margin)
        {
            Debug.Assert(!pos.in_check());

            var ei = EvalInfoBroker.GetObject();

            Value marginsWHITE, marginsBLACK;
            int score = 0, mobilityWhite = 0, mobilityBlack = 0;

            // margins[] store the uncertainty estimation of position's evaluation
            // that typically is used by the search for pruning decisions.
            marginsWHITE = marginsBLACK = ValueC.VALUE_ZERO;

            // Initialize score by reading the incrementally updated scores included
            // in the position object (material + piece square tables) and adding
            // Tempo bonus. Score is computed from the point of view of white.
            score = pos.st.psqScore + (pos.sideToMove == ColorC.WHITE ? Tempo : -Tempo);

            // Probe the material hash table
            pos.this_thread().materialTable.probe(pos, out ei.mi);
            score += ((ei.mi.value << 16) + ei.mi.value);

            // If we have a specialized evaluation function for the current material
            // configuration, call it and return.
            if (ei.mi.evaluationFunction != null)
            {
                margin = ValueC.VALUE_ZERO;
                var retval = ei.mi.evaluationFunction(ei.mi.evaluationFunctionColor, pos);
                ei.pi = null;
                ei.mi = null;
                EvalInfoBroker.Free();
                return retval;
            }

            // Probe the pawn hash table
            pos.this_thread().pawnTable.probe(pos, out ei.pi);
            score += ei.pi.value;

            // Initialize attack and king safety bitboards
            init_eval_info(ColorC.WHITE, pos, ei);
            init_eval_info(ColorC.BLACK, pos, ei);

            // Evaluate pieces and mobility
            score += evaluate_pieces_of_color(ColorC.WHITE, Trace, pos, ei, ref mobilityWhite)
                     - evaluate_pieces_of_color(ColorC.BLACK, Trace, pos, ei, ref mobilityBlack);

            score += (((((((mobilityWhite - mobilityBlack) + 32768) & ~0xffff) / 0x10000
                         * (((Weights[EvalWeightC.Mobility] + 32768) & ~0xffff) / 0x10000)) / 0x100) << 16)
                      + (((short)((mobilityWhite - mobilityBlack) & 0xffff)
                          * ((short)(Weights[EvalWeightC.Mobility] & 0xffff))) / 0x100));

            // Evaluate kings after all other pieces because we need complete attack
            // information when computing the king safety evaluation.
            score += evaluate_king(ColorC.WHITE, Trace, pos, ei, ref marginsWHITE, ref marginsBLACK)
                     - evaluate_king(ColorC.BLACK, Trace, pos, ei, ref marginsWHITE, ref marginsBLACK);

            // Evaluate tactical threats, we need full attack information including king
            score += evaluate_threats(ColorC.WHITE, pos, ei) - evaluate_threats(ColorC.BLACK, pos, ei);

            // Evaluate passed pawns, we need full attack information including king
            score += evaluate_passed_pawns(ColorC.WHITE, pos, ei) - evaluate_passed_pawns(ColorC.BLACK, pos, ei);

            // If one side has only a king, check whether exists any unstoppable passed pawn
            if ((pos.st.npMaterialWHITE == 0) || (pos.st.npMaterialBLACK == 0))
            {
                score += evaluate_unstoppable_pawns(pos, ei);
            }

            // Evaluate space for both sides, only in middle-game.
            if (ei.mi.spaceWeight != 0)
            {
                var s = evaluate_space(ColorC.WHITE, pos, ei) - evaluate_space(ColorC.BLACK, pos, ei);
                score += ((((((((s * ei.mi.spaceWeight) << 16) + 32768) & ~0xffff) / 0x10000
                             * (((Weights[EvalWeightC.Space] + 32768) & ~0xffff) / 0x10000)) / 0x100) << 16)
                          + (((short)(((s * ei.mi.spaceWeight) << 16) & 0xffff)
                              * ((short)(Weights[EvalWeightC.Space] & 0xffff))) / 0x100));
            }

            // Scale winning side if position is more drawish that what it appears
            var sf = ((short)(score & 0xffff)) > ValueC.VALUE_DRAW
                         ? ei.mi.scale_factor_WHITE(pos)
                         : ei.mi.scale_factor_BLACK(pos);

            // If we don't already have an unusual scale factor, check for opposite
            // colored bishop endgames, and use a lower scale for those.
            if (ei.mi.gamePhase < PhaseC.PHASE_MIDGAME
                && (pos.pieceCount[ColorC.WHITE][PieceTypeC.BISHOP] == 1
                    && pos.pieceCount[ColorC.BLACK][PieceTypeC.BISHOP] == 1
                    && (((((pos.pieceList[ColorC.WHITE][PieceTypeC.BISHOP][0]
                            ^ pos.pieceList[ColorC.BLACK][PieceTypeC.BISHOP][0]) >> 3)
                          ^ (pos.pieceList[ColorC.WHITE][PieceTypeC.BISHOP][0]
                             ^ pos.pieceList[ColorC.BLACK][PieceTypeC.BISHOP][0])) & 1) != 0))
                && sf == ScaleFactorC.SCALE_FACTOR_NORMAL)
            {
                // Only the two bishops ?
                if (pos.st.npMaterialWHITE == Constants.BishopValueMidgame
                    && pos.st.npMaterialBLACK == Constants.BishopValueMidgame)
                {
                    // Check for KBP vs KB with only a single pawn that is almost
                    // certainly a draw or at least two pawns.
                    sf = (pos.pieceCount[ColorC.WHITE][PieceTypeC.PAWN] + pos.pieceCount[ColorC.BLACK][PieceTypeC.PAWN]
                          == 1)
                             ? (8)
                             : (32);
                }
                else
                {
                    // Endgame with opposite-colored bishops, but also other pieces. Still
                    // a bit drawish, but not as drawish as with only the two bishops.
                    sf = (50);
                }
            }

            // Interpolate between the middle game and the endgame score
            margin = pos.sideToMove == ColorC.WHITE ? marginsWHITE : marginsBLACK;

            // interpolate
            //Value v = interpolate(score, ei.mi.game_phase(), sf);
            var ev = (((short)(score & 0xffff)) * sf) / ScaleFactorC.SCALE_FACTOR_NORMAL;
            var result = ((((score + 32768) & ~0xffff) / 0x10000) * ei.mi.gamePhase + ev * (128 - ei.mi.gamePhase)) / 128;
            var v = ((result + GrainSize / 2) & ~(GrainSize - 1));

            // In case of tracing add all single evaluation contributions for both white and black
            if (Trace)
            {
                trace_add(TracedTypeC.PST, pos.psq_score());
                trace_add(TracedTypeC.IMBALANCE, ei.mi.material_value());
                trace_add(PieceTypeC.PAWN, ei.pi.pawns_value());
                trace_add(
                    TracedTypeC.MOBILITY,
                    Utils.apply_weight(mobilityWhite, Weights[EvalWeightC.Mobility]),
                    Utils.apply_weight(mobilityBlack, Weights[EvalWeightC.Mobility]));
                trace_add(
                    TracedTypeC.THREAT,
                    evaluate_threats(ColorC.WHITE, pos, ei),
                    evaluate_threats(ColorC.BLACK, pos, ei));
                trace_add(
                    TracedTypeC.PASSED,
                    evaluate_passed_pawns(ColorC.WHITE, pos, ei),
                    evaluate_passed_pawns(ColorC.BLACK, pos, ei));
                trace_add(TracedTypeC.UNSTOPPABLE, evaluate_unstoppable_pawns(pos, ei));
                var w = Utils.make_score(ei.mi.space_weight() * evaluate_space(ColorC.WHITE, pos, ei), 0);
                var b = Utils.make_score(ei.mi.space_weight() * evaluate_space(ColorC.BLACK, pos, ei), 0);
                trace_add(
                    TracedTypeC.SPACE,
                    Utils.apply_weight(w, Weights[EvalWeightC.Space]),
                    Utils.apply_weight(b, Weights[EvalWeightC.Space]));
                trace_add(TracedTypeC.TOTAL, score);

                TraceStream.Append("\nUncertainty margin: White: ");
                TraceStream.Append(FormatDouble(to_cp(marginsWHITE), null, true));
                TraceStream.Append(", Black: ");
                TraceStream.Append(FormatDouble(to_cp(marginsBLACK), null, true));
                TraceStream.Append("\nScaling: ");
                TraceStream.Append(FormatDouble((100.0 * ei.mi.game_phase() / 128.0), 6, false));
                TraceStream.Append("% MG, ");
                TraceStream.Append(FormatDouble((100.0 * (1.0 - ei.mi.game_phase() / 128.0)), 6, false));
                TraceStream.Append("% * ");
                TraceStream.Append(FormatDouble(((100.0 * sf) / ScaleFactorC.SCALE_FACTOR_NORMAL), 6, false));
                TraceStream.Append("% EG.\n");
                TraceStream.Append("Total evaluation: ");
                TraceStream.Append(FormatDouble(to_cp(v), null, false));
            }

            ei.pi = null;
            ei.mi = null;
            EvalInfoBroker.Free();

            return pos.sideToMove == ColorC.WHITE ? v : -v;
        }