Example #1
0
        public Engine(string[] args)
        {
            inOut.WriteLine(Misc.engine_info(), MutexAction.ATOMIC);

            Uci.init(Options);
            BitBoard.init();
            Position.init();
            Bitbases.init_kpk();
            Search.init();
            Pawns.init();
            Eval.init();
            Threads.init();
            TT.resize((ulong)Options["Hash"].getInt());

            Uci.loop(args);

            Threads.exit();
        }
Example #2
0
        /// init() computes evaluation weights from the corresponding UCI parameters
        /// and setup king tables.
        public static void init()
        {
            Weights[EvalWeightS.Mobility]       = weight_option("Mobility (Midgame)", "Mobility (Endgame)", WeightsInternal[EvalWeightS.Mobility]);
            Weights[EvalWeightS.PawnStructure]  = weight_option("Pawn Structure (Midgame)", "Pawn Structure (Endgame)", WeightsInternal[EvalWeightS.PawnStructure]);
            Weights[EvalWeightS.PassedPawns]    = weight_option("Passed Pawns (Midgame)", "Passed Pawns (Endgame)", WeightsInternal[EvalWeightS.PassedPawns]);
            Weights[EvalWeightS.Space]          = weight_option("Space", "Space", WeightsInternal[EvalWeightS.Space]);
            Weights[EvalWeightS.KingDangerUs]   = weight_option("Cowardice", "Cowardice", WeightsInternal[EvalWeightS.KingDangerUs]);
            Weights[EvalWeightS.KingDangerThem] = weight_option("Aggressiveness", "Aggressiveness", WeightsInternal[EvalWeightS.KingDangerThem]);

            const int MaxSlope = 30;
            const int Peak     = 1280;

            for (int t = 0, i = 1; i < 100; ++i)
            {
                t = Math.Min(Peak, Math.Min((int)(0.4 * i * i), t + MaxSlope));

                KingDanger[1][i] = Eval.apply_weight(Types.make_score(t, 0), Weights[EvalWeightS.KingDangerUs]);
                KingDanger[0][i] = Eval.apply_weight(Types.make_score(t, 0), Weights[EvalWeightS.KingDangerThem]);
            }
        }
Example #3
0
        // do_evaluate() is the evaluation entry point, called directly from evaluate()
        public static Value do_evaluate(Position pos, bool Trace)
        {
            Debug.Assert(0 == pos.checkers());

            EvalInfo ei = new EvalInfo();
            Score    score;

            Score[] mobility   = new Score[] { ScoreS.SCORE_ZERO, ScoreS.SCORE_ZERO };
            Thread  thisThread = pos.this_thread();

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

            // Probe the material hash table
            ei.mi  = Material.probe(pos, thisThread.materialTable, thisThread.endgames);
            score += ei.mi.material_value();

            // If we have a specialized evaluation function for the current material
            // configuration, call it and return.
            if (ei.mi.specialized_eval_exists())
            {
                return(ei.mi.evaluate(pos));
            }

            // Probe the pawn hash table
            ei.pi  = Pawns.probe(pos, thisThread.pawnsTable);
            score += apply_weight(ei.pi.pawns_value(), Weights[EvalWeightS.PawnStructure]);

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

            ei.attackedBy[ColorS.WHITE][PieceTypeS.ALL_PIECES] |= ei.attackedBy[ColorS.WHITE][PieceTypeS.KING];
            ei.attackedBy[ColorS.BLACK][PieceTypeS.ALL_PIECES] |= ei.attackedBy[ColorS.BLACK][PieceTypeS.KING];

            // Do not include in mobility squares protected by enemy pawns or occupied by our pawns or king
            Bitboard[] mobilityArea = new Bitboard[] { ~(ei.attackedBy[ColorS.BLACK][PieceTypeS.PAWN] | pos.pieces_color_piecetype(ColorS.WHITE, PieceTypeS.PAWN, PieceTypeS.KING)),
                                                       ~(ei.attackedBy[ColorS.WHITE][PieceTypeS.PAWN] | pos.pieces_color_piecetype(ColorS.BLACK, PieceTypeS.PAWN, PieceTypeS.KING)) };
            // Evaluate pieces and mobility
            score += evaluate_pieces(pos, ei, mobility, mobilityArea, PieceTypeS.KNIGHT, ColorS.WHITE, Trace);
            score += Eval.apply_weight(mobility[ColorS.WHITE] - mobility[ColorS.BLACK], Weights[EvalWeightS.Mobility]);

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

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

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

            // If one side has only a king, check whether exists any unstoppable passed pawn
            if (0 == pos.non_pawn_material(ColorS.WHITE) || 0 == pos.non_pawn_material(ColorS.BLACK))
            {
                score += evaluate_unstoppable_pawns(pos, ColorS.WHITE, ei)
                         - evaluate_unstoppable_pawns(pos, ColorS.BLACK, ei);
            }

            // Evaluate space for both sides, only in middle-game.
            if (ei.mi.space_weight() != 0)
            {
                int s = evaluate_space(pos, ei, ColorS.WHITE) - evaluate_space(pos, ei, ColorS.BLACK);
                score += Eval.apply_weight(s * ei.mi.space_weight(), Weights[EvalWeightS.Space]);
            }

            // Scale winning side if position is more drawish that what it appears
            ScaleFactor sf = Types.eg_value(score) > ValueS.VALUE_DRAW ? ei.mi.scale_factor(pos, ColorS.WHITE)
                                                                       : ei.mi.scale_factor(pos, ColorS.BLACK);

            // 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.game_phase() < PhaseS.PHASE_MIDGAME &&
                pos.opposite_bishops() &&
                (sf == ScaleFactorS.SCALE_FACTOR_NORMAL || sf == ScaleFactorS.SCALE_FACTOR_ONEPAWN))
            {
                // Ignoring any pawns, do both sides only have a single bishop and no
                // other pieces?
                if (pos.non_pawn_material(ColorS.WHITE) == ValueS.BishopValueMg &&
                    pos.non_pawn_material(ColorS.BLACK) == ValueS.BishopValueMg)
                {
                    // Check for KBP vs KB with only a single pawn that is almost
                    // certainly a draw or at least two pawns.
                    bool one_pawn = (pos.count(ColorS.WHITE, PieceTypeS.PAWN) + pos.count(ColorS.BLACK, PieceTypeS.PAWN) == 1);
                    sf = one_pawn ? (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 * sf / ScaleFactorS.SCALE_FACTOR_NORMAL);
                }
            }

            // Interpolate between a middlegame and a (scaled by 'sf') endgame score
            Value v = Types.mg_value(score) * (ei.mi.game_phase())
                      + Types.eg_value(score) * (PhaseS.PHASE_MIDGAME - ei.mi.game_phase()) * sf / ScaleFactorS.SCALE_FACTOR_NORMAL;

            v /= (PhaseS.PHASE_MIDGAME);

            // In case of tracing add all single evaluation contributions for both white and black
            if (Trace)
            {
                //Tracing.add_term(Tracing.PST, pos.psq_score());
                //Tracing.add_term(Tracing.IMBALANCE, ei.mi.material_value());
                //Tracing.add_term(PAWN, ei.pi.pawns_value());
                //Tracing.add_term(Tracing.MOBILITY, apply_weight(mobility[WHITE], Weights[Mobility])
                //                                   , apply_weight(mobility[BLACK], Weights[Mobility]));
                //Score w = ei.mi->space_weight() * evaluate_space<WHITE>(pos, ei);
                //Score b = ei.mi->space_weight() * evaluate_space<BLACK>(pos, ei);
                //Tracing.add_term(Tracing.SPACE, apply_weight(w, Weights[Space]), apply_weight(b, Weights[Space]));
                //Tracing.add_term(Tracing.TOTAL, score);
                //Tracing.ei = ei;
                //Tracing.sf = sf;
            }

            return(pos.side_to_move() == ColorS.WHITE ? v : -v);
        }
Example #4
0
        // evaluate_passed_pawns() evaluates the passed pawns of the given color
        public static Score evaluate_passed_pawns(Position pos, EvalInfo ei, Color Us, bool Trace)
        {
            Color Them = (Us == ColorS.WHITE ? ColorS.BLACK : ColorS.WHITE);

            Bitboard b, squaresToQueen, defendedSquares, unsafeSquares;
            Score    score = ScoreS.SCORE_ZERO;

            b = ei.pi.passed_pawns(Us);

            while (b != 0)
            {
                Square s = BitBoard.pop_lsb(ref b);

                Debug.Assert(pos.pawn_passed(Us, s));

                int r  = (int)(Types.relative_rank_square(Us, s) - RankS.RANK_2);
                int rr = r * (r - 1);

                // Base bonus based on rank
                Value mbonus = (17 * rr), ebonus = (7 * (rr + r + 1));

                if (rr != 0)
                {
                    Square blockSq = s + Types.pawn_push(Us);

                    // Adjust bonus based on kings proximity
                    ebonus += (BitBoard.square_distance(pos.king_square(Them), blockSq) * 5 * rr)
                              - (BitBoard.square_distance(pos.king_square(Us), blockSq) * 2 * rr);

                    // If blockSq is not the queening square then consider also a second push
                    if (Types.relative_rank_square(Us, blockSq) != RankS.RANK_8)
                    {
                        ebonus -= (BitBoard.square_distance(pos.king_square(Us), blockSq + Types.pawn_push(Us)) * rr);
                    }

                    // If the pawn is free to advance, increase bonus
                    if (pos.empty(blockSq))
                    {
                        squaresToQueen = BitBoard.forward_bb(Us, s);

                        // If there is an enemy rook or queen attacking the pawn from behind,
                        // add all X-ray attacks by the rook or queen. Otherwise consider only
                        // the squares in the pawn's path attacked or occupied by the enemy.
                        if ((BitBoard.forward_bb(Them, s) & pos.pieces_color_piecetype(Them, PieceTypeS.ROOK, PieceTypeS.QUEEN)) != 0 &&
                            (BitBoard.forward_bb(Them, s) & pos.pieces_color_piecetype(Them, PieceTypeS.ROOK, PieceTypeS.QUEEN) & pos.attacks_from_square_piecetype(s, PieceTypeS.ROOK)) != 0)
                        {
                            unsafeSquares = squaresToQueen;
                        }
                        else
                        {
                            unsafeSquares = squaresToQueen & (ei.attackedBy[Them][PieceTypeS.ALL_PIECES] | pos.pieces_color(Them));
                        }

                        if ((BitBoard.forward_bb(Them, s) & pos.pieces_color_piecetype(Us, PieceTypeS.ROOK, PieceTypeS.QUEEN)) != 0 &&
                            (BitBoard.forward_bb(Them, s) & pos.pieces_color_piecetype(Us, PieceTypeS.ROOK, PieceTypeS.QUEEN) & pos.attacks_from_square_piecetype(s, PieceTypeS.ROOK)) != 0)
                        {
                            defendedSquares = squaresToQueen;
                        }
                        else
                        {
                            defendedSquares = squaresToQueen & ei.attackedBy[Us][PieceTypeS.ALL_PIECES];
                        }

                        // If there aren't any enemy attacks, assign a big bonus. Otherwise
                        // assign a smaller bonus if the block square isn't attacked.
                        int k = 0 == unsafeSquares? 15 : 0 == (unsafeSquares & BitBoard.SquareBB[blockSq]) ? 9 : 0;


                        // If the path to queen is fully defended, assign a big bonus.
                        // Otherwise assign a smaller bonus if the block square is defended.
                        if (defendedSquares == squaresToQueen)
                        {
                            k += 6;
                        }

                        else if ((defendedSquares & BitBoard.SquareBB[blockSq]) != 0)
                        {
                            k += 4;
                        }

                        mbonus += (k * rr); ebonus += (k * rr);
                    }
                } // rr != 0

                if (pos.count(Us, PieceTypeS.PAWN) < pos.count(Them, PieceTypeS.PAWN))
                {
                    ebonus += ebonus / 4;
                }

                score += Types.make_score(mbonus, ebonus);
            }

            if (Trace)
            {
                Tracing.terms[Us][TermsS.PASSED] = apply_weight(score, Weights[EvalWeightS.PassedPawns]);
            }

            // Add the scores to the middle game and endgame eval
            return(Eval.apply_weight(score, Weights[EvalWeightS.PassedPawns]));
        }