Пример #1
0
 internal static void init()
 {
     for (int i = 0; i < Constants.BROKER_SLOTS; i++)
     {
         _pool[i] = new EvalInfo[0];
     }
 }
Пример #2
0
        internal static EvalInfo GetObject()
        {
            int slotID = System.Threading.Thread.CurrentThread.ManagedThreadId & Constants.BROKER_SLOT_MASK;

            if (_cnt[slotID] == _pool[slotID].Length)
            {
                int        poolLength = _pool[slotID].Length;
                EvalInfo[] temp       = new EvalInfo[poolLength + Constants.BrokerCapacity];
                Array.Copy(_pool[slotID], temp, poolLength);
                for (int i = 0; i < Constants.BrokerCapacity; i++)
                {
                    temp[poolLength + i] = new EvalInfo();
                }
                _pool[slotID] = temp;
            }
            return(_pool[slotID][_cnt[slotID]++]);
        }
Пример #3
0
    IEnumerator SpawnTrees()
    {
        while (true)
        {
            try {
                ls = LSystem.Instance;

                if (ls.N < this.N)
                {
                    ls.UpdateRuleByNumber(this.N - ls.N);
                }
                else if (resetSyntax)
                {
                    ls.ResetRule("X");
                    resetSyntax = false;
                    continue;
                }
                for (int i = 0; i < trees.Length; i++)
                {
                    float x  = Random.Range(-SpawnRange, SpawnRange);
                    float z  = Random.Range(-SpawnRange, SpawnRange);
                    var   to = Instantiate(trees[i], new Vector3(x, 0, z), Quaternion.identity, transform);
                    Destroy(to, 10f * Random.Range(0.5f, 2.0f));
                    evalInfo = ls.EvaluationInfo;
                    if (evalInfo != null)
                    {
                        updateRules[i] = true;
                        EvalThreadRun(); // 一つでも true になったら start
                    }
                }
            } catch (System.NullReferenceException e) {
                Debug.LogWarning("Error occured: (spawn trees)" + e);
            }
            yield return(new WaitForSeconds(0.5f));
        }
    }
Пример #4
0
    // evaluate_space() computes the space evaluation for a given side. The
    // space evaluation is a simple bonus based on the number of safe squares
    // available for minor pieces on the central four files on ranks 2--4. Safe
    // squares one, two or three squares behind a friendly pawn are counted
    // twice. Finally, the space bonus is multiplied by a weight. The aim is to
    // improve play on game opening.
    private static ScoreT evaluate_space(ColorT Us, Position pos, EvalInfo ei)
    {
        var Them = (Us == Color.WHITE ? Color.BLACK : Color.WHITE);

        // Find the safe squares for our pieces inside the area defined by
        // SpaceMask[]. A square is unsafe if it is attacked by an enemy
        // pawn, or if it is undefended and attacked by an enemy piece.
        var safe = SpaceMask[Us] & ~pos.pieces_CtPt(Us, PieceType.PAWN) & ~ei.attackedBy[Them, PieceType.PAWN]
                   & (ei.attackedBy[Us, PieceType.ALL_PIECES] | ~ei.attackedBy[Them, PieceType.ALL_PIECES]);

        // Find all squares which are at most three squares behind some friendly pawn
        var behind = pos.pieces_CtPt(Us, PieceType.PAWN);
        behind |= (Us == Color.WHITE ? behind >> 8 : behind << 8);
        behind |= (Us == Color.WHITE ? behind >> 16 : behind << 16);

        // Since SpaceMask[Us.Value] is fully on our half of the board...
        Debug.Assert((uint) (safe >> (Us == Color.WHITE ? 32 : 0)) == 0);

        // ...count safe + (behind & safe) with a single popcount
        var bonus = Bitcount.popcount_Full((Us == Color.WHITE ? safe << 32 : safe >> 32) | (behind & safe));
        var weight = pos.count(PieceType.KNIGHT, Us) + pos.count(PieceType.BISHOP, Us)
                     + pos.count(PieceType.KNIGHT, Them) + pos.count(PieceType.BISHOP, Them);

        return Score.make_score(bonus*weight*weight, 0);
    }
Пример #5
0
    /// evaluate() is the main evaluation function. It returns a static evaluation
    /// of the position always from the point of view of the side to move.
    internal static ValueT evaluate(bool DoTrace, Position pos)
    {
        Debug.Assert(pos.checkers() == 0);

        var ei = new EvalInfo();
        ScoreT[] mobility = {Score.SCORE_ZERO, Score.SCORE_ZERO};

        // Initialize score by reading the incrementally updated scores included
        // in the position object (material + piece square tables).
        // Score is computed from the point of view of white.
        var score = pos.psq_score();

        // Probe the material hash table
        var me = Material.probe(pos);
        score += me.imbalance();

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

        // Probe the pawn hash table
        ei.pi = Pawns.probe(pos);
        score += Score.Multiply(ei.pi.pawns_score(), Weights[PawnStructure]);

        // Initialize attack and king safety bitboards
        ei.attackedBy[Color.WHITE, PieceType.ALL_PIECES] =
            ei.attackedBy[Color.BLACK, PieceType.ALL_PIECES] = Bitboard.Create(0);
        init_eval_info(Color.WHITE, pos, ei);
        init_eval_info(Color.BLACK, pos, ei);

        // Pawns blocked or on ranks 2 and 3. Will be excluded from the mobility area
        BitboardT[] blockedPawns =
        {
            pos.pieces_CtPt(Color.WHITE, PieceType.PAWN)
            & (Bitboard.shift_bb(Square.DELTA_S, pos.pieces()) | Bitboard.Rank2BB
               | Bitboard.Rank3BB),
            pos.pieces_CtPt(Color.BLACK, PieceType.PAWN)
            & (Bitboard.shift_bb(Square.DELTA_N, pos.pieces()) | Bitboard.Rank7BB
               | Bitboard.Rank6BB)
        };

        // Do not include in mobility squares protected by enemy pawns, or occupied
        // by our blocked pawns or king.
        BitboardT[] mobilityArea =
        {
            ~(Bitboard.OrWithSquare(ei.attackedBy[Color.BLACK, PieceType.PAWN] | blockedPawns[Color.WHITE]
              , pos.square(PieceType.KING, Color.WHITE))),
            ~(Bitboard.OrWithSquare(ei.attackedBy[Color.WHITE, PieceType.PAWN] | blockedPawns[Color.BLACK]
              , pos.square(PieceType.KING, Color.BLACK)))
        };

        // Evaluate pieces and mobility
        score += evaluate_pieces(PieceType.KNIGHT, Color.WHITE, DoTrace, pos, ei, mobility, mobilityArea);
        score += Score.Multiply(mobility[Color.WHITE] - mobility[Color.BLACK], Weights[Mobility]);

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

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

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

        // If both sides have only pawns, score for potential unstoppable pawns
        if (pos.non_pawn_material(Color.WHITE) == 0 && pos.non_pawn_material(Color.BLACK) == 0)
        {
            BitboardT b;
            if ((b = ei.pi.passed_pawns(Color.WHITE)) != 0)
            {
                score += Rank.relative_rank_CtSt(Color.WHITE, Utils.frontmost_sq(Color.WHITE, b)) * Unstoppable;
            }

            if ((b = ei.pi.passed_pawns(Color.BLACK)) != 0)
            {
                score -= Rank.relative_rank_CtSt(Color.BLACK, Utils.frontmost_sq(Color.BLACK, b)) * Unstoppable;
            }
        }

        // Evaluate space for both sides, only during opening
        if (pos.non_pawn_material(Color.WHITE) + pos.non_pawn_material(Color.BLACK) >= 12222)
        {
            score += Score.Multiply(evaluate_space(Color.WHITE, pos, ei) - evaluate_space(Color.BLACK, pos, ei), Weights[Space]);
        }

        // Scale winning side if position is more drawish than it appears
        var strongSide = Score.eg_value(score) > Value.VALUE_DRAW ? Color.WHITE : Color.BLACK;
        var sf = me.scale_factor(pos, strongSide);

        // If we don't already have an unusual scale factor, check for certain
        // types of endgames, and use a lower scale for those.
        if (me.game_phase() < Phase.PHASE_MIDGAME
            && (sf == ScaleFactor.SCALE_FACTOR_NORMAL || sf == ScaleFactor.SCALE_FACTOR_ONEPAWN))
        {
            if (pos.opposite_bishops())
            {
                // Endgame with opposite-colored bishops and no other pieces (ignoring pawns)
                // is almost a draw, in case of KBP vs KB is even more a draw.
                if (pos.non_pawn_material(Color.WHITE) == Value.BishopValueMg
                    && pos.non_pawn_material(Color.BLACK) == Value.BishopValueMg)
                {
                    sf = Bitboard.more_than_one(pos.pieces_Pt(PieceType.PAWN)) ? (ScaleFactor) (31) : (ScaleFactor) (9);
                }

                // Endgame with opposite-colored bishops, but also other pieces. Still
                // a bit drawish, but not as drawish as with only the two bishops.
                else
                {
                    sf = (ScaleFactor) (46*(int) sf/(int) ScaleFactor.SCALE_FACTOR_NORMAL);
                }
            }
            // Endings where weaker side can place his king in front of the opponent's
            // pawns are drawish.
            else if (Math.Abs(Score.eg_value(score)) <= Value.BishopValueEg && ei.pi.pawn_span(strongSide) <= 1
                     && !pos.pawn_passed(Color.opposite(strongSide), pos.square(PieceType.KING, Color.opposite(strongSide))))
            {
                sf = ei.pi.pawn_span(strongSide) != 0 ? (ScaleFactor) (51) : (ScaleFactor) (37);
            }
        }

        // Scale endgame by number of pawns
        var p = pos.count(PieceType.PAWN, Color.WHITE) + pos.count(PieceType.PAWN, Color.BLACK);
        var vEg = 1 + Math.Abs(Score.eg_value(score));
        sf = (ScaleFactor) (Math.Max((int) sf/2, (int) sf - 8*(int) ScaleFactor.SCALE_FACTOR_NORMAL*(12 - p)/vEg));

        // Interpolate between a middlegame and a (scaled by 'sf') endgame score
        var v = Score.mg_value(score)*(int) (me.game_phase())
                + Score.eg_value(score)*(Phase.PHASE_MIDGAME - me.game_phase())*(int) sf
                /(int) ScaleFactor.SCALE_FACTOR_NORMAL;

        v /= (int) (Phase.PHASE_MIDGAME);

        // In case of tracing add all single evaluation terms
        if (DoTrace)
        {
            add_IdxSt((int) Term.MATERIAL, pos.psq_score());
            add_IdxSt((int) Term.IMBALANCE, me.imbalance());
            add_IdxSt(PieceType.PAWN, ei.pi.pawns_score());
            add_IdxStSt(
                (int) Term.MOBILITY,
                Score.Multiply(mobility[Color.WHITE], Weights[Mobility]),
                Score.Multiply(mobility[Color.BLACK], Weights[Mobility]));
            add_IdxStSt(
                (int) Term.SPACE,
                Score.Multiply(evaluate_space(Color.WHITE, pos, ei), Weights[Space]),
                Score.Multiply(evaluate_space(Color.BLACK, pos, ei), Weights[Space]));
            add_IdxSt((int) Term.TOTAL, score);
        }

        return (pos.side_to_move() == Color.WHITE ? v : -v) + Tempo; // Side to move point of view
    }
Пример #6
0
    // evaluate_passed_pawns() evaluates the passed pawns of the given color
    private static ScoreT evaluate_passed_pawns(ColorT Us, bool DoTrace, Position pos, EvalInfo ei)
    {
        var Them = (Us == Color.WHITE ? Color.BLACK : Color.WHITE);

        var score = Score.SCORE_ZERO;

        var b = ei.pi.passed_pawns(Us);

        while (b!=0)
        {
            var s = Utils.pop_lsb(ref b);

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

            int r = Rank.relative_rank_CtSt(Us, s) - Rank.RANK_2;
            var rr = r*(r - 1);

            ValueT mbonus = Passed[(int) Phase.MG][r], ebonus = Passed[(int) Phase.EG][r];

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

                // Adjust bonus based on the king's proximity
                ebonus += Utils.distance_Square(pos.square(PieceType.KING, Them), blockSq)*5*rr
                          - Utils.distance_Square(pos.square(PieceType.KING, Us), blockSq)*2*rr;

                // If blockSq is not the queening square then consider also a second push
                if (Rank.relative_rank_CtSt(Us, blockSq) != Rank.RANK_8)
                {
                    ebonus -= Utils.distance_Square(pos.square(PieceType.KING, Us), blockSq + Square.pawn_push(Us))*rr;
                }

                // If the pawn is free to advance, then increase the bonus
                if (pos.empty(blockSq))
                {
                    // If there is a rook or queen attacking/defending the pawn from behind,
                    // consider all the squaresToQueen. Otherwise consider only the squares
                    // in the pawn's path attacked or occupied by the enemy.
                    BitboardT squaresToQueen;
                    BitboardT unsafeSquares;
                    var defendedSquares = unsafeSquares = squaresToQueen = Utils.forward_bb(Us, s);

                    var bb = Utils.forward_bb(Them, s) & pos.pieces_PtPt(PieceType.ROOK, PieceType.QUEEN)
                             & pos.attacks_from_PtS(PieceType.ROOK, s);

                    if ((pos.pieces_Ct(Us) & bb)==0)
                    {
                        defendedSquares &= ei.attackedBy[Us, PieceType.ALL_PIECES];
                    }

                    if ((pos.pieces_Ct(Them) & bb) == 0)
                    {
                        unsafeSquares &= ei.attackedBy[Them, PieceType.ALL_PIECES] | pos.pieces_Ct(Them);
                    }

                    // If there aren't any enemy attacks, assign a big bonus. Otherwise
                    // assign a smaller bonus if the block square isn't attacked.
                    var k = unsafeSquares == 0 ? 18 : Bitboard.AndWithSquare(unsafeSquares, blockSq)==0 ? 8 : 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 (Bitboard.AndWithSquare(defendedSquares, blockSq)!=0)
                    {
                        k += 4;
                    }

                    mbonus += k*rr;
                    ebonus += k*rr;
                }
                else if (Bitboard.AndWithSquare(pos.pieces_Ct(Us), blockSq)!=0)
                {
                    mbonus += rr*3 + r*2 + 3;
                    ebonus += rr + r*2;
                }
            } // rr != 0

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

            score += Score.make_score(mbonus, ebonus) + PassedFile[Square.file_of(s)];
        }

        if (DoTrace)
        {
            add_IdxCtSt((int) Term.PASSED, Us, Score.Multiply(score, Weights[PassedPawns]));
        }

        // Add the scores to the middlegame and endgame eval
        return Score.Multiply(score, Weights[PassedPawns]);
    }
Пример #7
0
    // evaluate_threats() assigns bonuses according to the type of attacking piece
    // and the type of attacked one.

    private static ScoreT evaluate_threats(ColorT Us, bool DoTrace, Position pos, EvalInfo ei)
    {
        var Them = (Us == Color.WHITE ? Color.BLACK : Color.WHITE);
        var Up = (Us == Color.WHITE ? Square.DELTA_N : Square.DELTA_S);
        var Left = (Us == Color.WHITE ? Square.DELTA_NW : Square.DELTA_SE);
        var Right = (Us == Color.WHITE ? Square.DELTA_NE : Square.DELTA_SW);
        var TRank2BB = (Us == Color.WHITE ? Bitboard.Rank2BB : Bitboard.Rank7BB);
        var TRank7BB = (Us == Color.WHITE ? Bitboard.Rank7BB : Bitboard.Rank2BB);

        const int Defended = 0;
        const int Weak = 1;
        const int Minor = 0;
        const int Rook = 1;

        BitboardT b;
        var score = Score.SCORE_ZERO;

        // Non-pawn enemies attacked by a pawn
        var weak = (pos.pieces_Ct(Them) ^ pos.pieces_CtPt(Them, PieceType.PAWN)) & ei.attackedBy[Us, PieceType.PAWN];

        if (weak!=0)
        {
            b = pos.pieces_CtPt(Us, PieceType.PAWN)
                & (~ei.attackedBy[Them, PieceType.ALL_PIECES] | ei.attackedBy[Us, PieceType.ALL_PIECES]);

            var safeThreats = (Bitboard.shift_bb(Right, b) | Bitboard.shift_bb(Left, b)) & weak;

            if ((weak ^ safeThreats)!=0)
            {
                score += ThreatenedByHangingPawn;
            }

            while (safeThreats!=0)
            {
                score += ThreatenedByPawn[Piece.type_of(pos.piece_on(Utils.pop_lsb(ref safeThreats)))];
            }
        }

        // Non-pawn enemies defended by a pawn
        var defended = (pos.pieces_Ct(Them) ^ pos.pieces_CtPt(Them, PieceType.PAWN)) & ei.attackedBy[Them, PieceType.PAWN];

        // Add a bonus according to the kind of attacking pieces
        if (defended!=0)
        {
            b = defended & (ei.attackedBy[Us, PieceType.KNIGHT] | ei.attackedBy[Us, PieceType.BISHOP]);
            while (b!=0)
            {
                score += Threat[Defended][Minor][Piece.type_of(pos.piece_on(Utils.pop_lsb(ref b)))];
            }

            b = defended & ei.attackedBy[Us, PieceType.ROOK];
            while (b!=0)
            {
                score += Threat[Defended][Rook][Piece.type_of(pos.piece_on(Utils.pop_lsb(ref b)))];
            }
        }

        // Enemies not defended by a pawn and under our attack
        weak = pos.pieces_Ct(Them) & ~ei.attackedBy[Them, PieceType.PAWN] & ei.attackedBy[Us, PieceType.ALL_PIECES];

        // Add a bonus according to the kind of attacking pieces
        if (weak!=0)
        {
            b = weak & (ei.attackedBy[Us, PieceType.KNIGHT] | ei.attackedBy[Us, PieceType.BISHOP]);
            while (b!=0)
            {
                score += Threat[Weak][Minor][Piece.type_of(pos.piece_on(Utils.pop_lsb(ref b)))];
            }

            b = weak & ei.attackedBy[Us, PieceType.ROOK];
            while (b!=0)
            {
                score += Threat[Weak][Rook][Piece.type_of(pos.piece_on(Utils.pop_lsb(ref b)))];
            }

            b = weak & ~ei.attackedBy[Them, PieceType.ALL_PIECES];
            if (b!=0)
            {
                score += Hanging*Bitcount.popcount_Max15(b);
            }

            b = weak & ei.attackedBy[Us, PieceType.KING];
            if (b!=0)
            {
                score += Bitboard.more_than_one(b) ? KingOnMany : KingOnOne;
            }
        }

        // Bonus if some pawns can safely push and attack an enemy piece
        b = pos.pieces_CtPt(Us, PieceType.PAWN) & ~TRank7BB;
        b = Bitboard.shift_bb(Up, b | (Bitboard.shift_bb(Up, b & TRank2BB) & ~pos.pieces()));

        b &= ~pos.pieces() & ~ei.attackedBy[Them, PieceType.PAWN]
             & (ei.attackedBy[Us, PieceType.ALL_PIECES] | ~ei.attackedBy[Them, PieceType.ALL_PIECES]);

        b = (Bitboard.shift_bb(Left, b) | Bitboard.shift_bb(Right, b)) & pos.pieces_Ct(Them)
            & ~ei.attackedBy[Us, PieceType.PAWN];

        if (b!=0)
        {
            score += Bitcount.popcount_Max15(b)*PawnAttackThreat;
        }

        if (DoTrace)
        {
            add_IdxCtSt((int) Term.THREAT, Us, score);
        }

        return score;
    }
Пример #8
0
    // evaluate_king() assigns bonuses and penalties to a king of a given color

    private static ScoreT evaluate_king(ColorT Us, bool DoTrace, Position pos, EvalInfo ei)
    {
        var Them = (Us == Color.WHITE ? Color.BLACK : Color.WHITE);

        var ksq = pos.square(PieceType.KING, Us);

        // King shelter and enemy pawns storm
        var score = ei.pi.king_safety(Us, pos, ksq);

        // Main king safety evaluation
        if (ei.kingAttackersCount[Them] != 0)
        {
            // Find the attacked squares around the king which have no defenders
            // apart from the king itself
            var undefended = ei.attackedBy[Them, PieceType.ALL_PIECES] & ei.attackedBy[Us, PieceType.KING]
                                  & ~(ei.attackedBy[Us, PieceType.PAWN] | ei.attackedBy[Us, PieceType.KNIGHT]
                                      | ei.attackedBy[Us, PieceType.BISHOP] | ei.attackedBy[Us, PieceType.ROOK]
                                      | ei.attackedBy[Us, PieceType.QUEEN]);

            // Initialize the 'attackUnits' variable, which is used later on as an
            // index into the KingDanger[] array. The initial value is based on the
            // number and types of the enemy's attacking pieces, the number of
            // attacked and undefended squares around our king and the quality of
            // the pawn shelter (current 'score' value).
            var attackUnits = Math.Min(72, ei.kingAttackersCount[Them] *ei.kingAttackersWeight[Them])
                              + 9*ei.kingAdjacentZoneAttacksCount[Them] + 27*Bitcount.popcount_Max15(undefended)
                              + 11*((ulong)ei.pinnedPieces[Us] != 0 ? 1 : 0)
                              - 64*(pos.count(PieceType.QUEEN, Them) == 0 ? 1 : 0) - Score.mg_value(score)/8;

            // Analyse the enemy's safe queen contact checks. Firstly, find the
            // undefended squares around the king reachable by the enemy queen...
            var b = undefended & ei.attackedBy[Them, PieceType.QUEEN] & ~pos.pieces_Ct(Them);
            if (b!=0)
            {
                // ...and then remove squares not supported by another enemy piece
                b &= ei.attackedBy[Them, PieceType.PAWN] | ei.attackedBy[Them, PieceType.KNIGHT]
                     | ei.attackedBy[Them, PieceType.BISHOP] | ei.attackedBy[Them, PieceType.ROOK];

                if (b!=0)
                {
                    attackUnits += QueenContactCheck*Bitcount.popcount_Max15(b);
                }
            }

            // Analyse the enemy's safe distance checks for sliders and knights
            var safe = ~(ei.attackedBy[Us, PieceType.ALL_PIECES] | pos.pieces_Ct(Them));

            var b1 = pos.attacks_from_PtS(PieceType.ROOK, ksq) & safe;
            var b2 = pos.attacks_from_PtS(PieceType.BISHOP, ksq) & safe;

            // Enemy queen safe checks
            b = (b1 | b2) & ei.attackedBy[Them, PieceType.QUEEN];
            if (b!=0)
            {
                attackUnits += QueenCheck*Bitcount.popcount_Max15(b);
                score -= Checked;
            }

            // Enemy rooks safe checks
            b = b1 & ei.attackedBy[Them, PieceType.ROOK];
            if (b!=0)
            {
                attackUnits += RookCheck*Bitcount.popcount_Max15(b);
                score -= Checked;
            }

            // Enemy bishops safe checks
            b = b2 & ei.attackedBy[Them, PieceType.BISHOP];
            if (b!=0)
            {
                attackUnits += BishopCheck*Bitcount.popcount_Max15(b);
                score -= Checked;
            }

            // Enemy knights safe checks
            b = pos.attacks_from_PtS(PieceType.KNIGHT, ksq) & ei.attackedBy[Them, PieceType.KNIGHT] & safe;
            if (b!=0)
            {
                attackUnits += KnightCheck*Bitcount.popcount_Max15(b);
                score -= Checked;
            }

            // Finally, extract the king danger score from the KingDanger[]
            // array and subtract the score from evaluation.
            score -= KingDanger[Math.Max(Math.Min(attackUnits, 399), 0)];
        }

        if (DoTrace)
        {
            add_IdxCtSt(PieceType.KING, Us, score);
        }

        return score;
    }
Пример #9
0
    // evaluate_pieces() assigns bonuses and penalties to the pieces of a given color

    private static ScoreT evaluate_pieces(
        PieceTypeT pieceType,
        ColorT Us,
        bool DoTrace,
        Position pos,
        EvalInfo ei,
        ScoreT[] mobility,
        BitboardT[] mobilityArea)
    {
        int Pt = pieceType;
        if (Pt == PieceType.KING)
        {
            return Score.SCORE_ZERO;
        }
        var score = Score.SCORE_ZERO;

        var NextPt = (Us == Color.WHITE ? pieceType : pieceType + 1);
        var Them = (Us == Color.WHITE ? Color.BLACK : Color.WHITE);
        
        ei.attackedBy[Us, Pt] = Bitboard.Create(0);

        for(var idx=0; idx<16;idx++)
        {
            var s = pos.square(pieceType, Us, idx);
            if (s == Square.SQ_NONE)
            {
                break;
            }
            // Find attacked squares, including x-ray attacks for bishops and rooks
            var b = Pt == PieceType.BISHOP
                ? Utils.attacks_bb_PtSBb(PieceType.BISHOP, s, pos.pieces() ^ pos.pieces_CtPt(Us, PieceType.QUEEN))
                : Pt == PieceType.ROOK
                    ? Utils.attacks_bb_PtSBb(
                        PieceType.ROOK,
                        s,
                        pos.pieces() ^ pos.pieces_CtPtPt(Us, PieceType.ROOK, PieceType.QUEEN))
                    : pos.attacks_from_PtS(pieceType, s);

            if (Bitboard.AndWithSquare(ei.pinnedPieces[Us], s)!=0)
            {
                b &= Utils.LineBB[pos.square(PieceType.KING, Us), s];
            }

            ei.attackedBy[Us, PieceType.ALL_PIECES] |= ei.attackedBy[Us, Pt] |= b;

            if ((b & ei.kingRing[Them])!=0)
            {
                ei.kingAttackersCount[Us]++;
                ei.kingAttackersWeight[Us] += KingAttackWeights[Pt];
                var bb = b & ei.attackedBy[Them, PieceType.KING];
                if (bb!=0)
                {
                    ei.kingAdjacentZoneAttacksCount[Us] += Bitcount.popcount_Max15(bb);
                }
            }

            if (Pt == PieceType.QUEEN)
            {
                b &=
                    ~(ei.attackedBy[Them, PieceType.KNIGHT] | ei.attackedBy[Them, PieceType.BISHOP]
                      | ei.attackedBy[Them, PieceType.ROOK]);
            }

            var mob = Pt == PieceType.QUEEN
                ? Bitcount.popcount_Full(b & mobilityArea[Us])
                : Bitcount.popcount_Max15(b & mobilityArea[Us]);

            mobility[Us] += MobilityBonus[Pt][mob];

            if (Pt == PieceType.BISHOP || Pt == PieceType.KNIGHT)
            {
                // Bonus for outpost square
                if (Rank.relative_rank_CtSt(Us, s) >= Rank.RANK_4 && Rank.relative_rank_CtSt(Us, s) <= Rank.RANK_6
                    && (pos.pieces_CtPt(Them, PieceType.PAWN) & Utils.pawn_attack_span(Us, s))==0)
                {
                    score +=
                        Outpost[Pt == PieceType.BISHOP ? 1 : 0][Bitboard.AndWithSquare(ei.attackedBy[Us, PieceType.PAWN], s)!=0 ? 1 : 0];
                }

                // Bonus when behind a pawn
                if (Rank.relative_rank_CtSt(Us, s) < Rank.RANK_5 && Bitboard.AndWithSquare(pos.pieces_Pt(PieceType.PAWN), (s + Square.pawn_push(Us)))!=0)
                {
                    score += MinorBehindPawn;
                }

                // Penalty for pawns on same color square of bishop
                if (Pt == PieceType.BISHOP)
                {
                    score -= BishopPawns*ei.pi.pawns_on_same_color_squares(Us, s);
                }

                // An important Chess960 pattern: A cornered bishop blocked by a friendly
                // pawn diagonally in front of it is a very serious problem, especially
                // when that pawn is also blocked.
                if (Pt == PieceType.BISHOP && pos.is_chess960()
                    && (s == Square.relative_square(Us, Square.SQ_A1) || s == Square.relative_square(Us, Square.SQ_H1)))
                {
                    var d = Square.pawn_push(Us) + (Square.file_of(s) == File.FILE_A ? Square.DELTA_E : Square.DELTA_W);
                    if (pos.piece_on(s + d) == Piece.make_piece(Us, PieceType.PAWN))
                    {
                        score -= !pos.empty(s + d + Square.pawn_push(Us))
                            ? TrappedBishopA1H1*4
                            : pos.piece_on(s + d + d) == Piece.make_piece(Us, PieceType.PAWN)
                                ? TrappedBishopA1H1*2
                                : TrappedBishopA1H1;
                    }
                }
            }

            if (Pt == PieceType.ROOK)
            {
                // Bonus for aligning with enemy pawns on the same rank/file
                if (Rank.relative_rank_CtSt(Us, s) >= Rank.RANK_5)
                {
                    var alignedPawns = pos.pieces_CtPt(Them, PieceType.PAWN) & Utils.PseudoAttacks[PieceType.ROOK, s];
                    if (alignedPawns!=0)
                    {
                        score += Bitcount.popcount_Max15(alignedPawns)*RookOnPawn;
                    }
                }

                // Bonus when on an open or semi-open file
                if (ei.pi.semiopen_file(Us, Square.file_of(s)) != 0)
                {
                    score += ei.pi.semiopen_file(Them, Square.file_of(s)) != 0 ? RookOnOpenFile : RookOnSemiOpenFile;
                }

                // Penalize when trapped by the king, even more if king cannot castle
                if (mob <= 3 && 0 == ei.pi.semiopen_file(Us, Square.file_of(s)))
                {
                    var ksq = pos.square(PieceType.KING, Us);

                    if (((Square.file_of(ksq) < File.FILE_E) == (Square.file_of(s) < Square.file_of(ksq)))
                        && (Square.rank_of(ksq) == Square.rank_of(s) || Rank.relative_rank_CtSt(Us, ksq) == Rank.RANK_1)
                        && 0 == ei.pi.semiopen_side(Us, Square.file_of(ksq), Square.file_of(s) < Square.file_of(ksq)))
                    {
                        score -= (TrappedRook - Score.make_score(mob*22, 0))*(1 + (pos.can_castle(Us) == 0 ? 1 : 0));
                    }
                }
            }
        }

        if (DoTrace)
        {
            add_IdxCtSt(Pt, Us, score);
        }
        // Recursively call evaluate_pieces() of next piece type until KING excluded
        return score - evaluate_pieces(NextPt, Them, DoTrace, pos, ei, mobility, mobilityArea);
    }
Пример #10
0
    // init_eval_info() initializes king bitboards for given color adding
    // pawn attacks. To be done at the beginning of the evaluation.

    private static void init_eval_info(ColorT Us, Position pos, EvalInfo ei)
    {
        var Them = (Us == Color.WHITE ? Color.BLACK : Color.WHITE);
        var Down = (Us == Color.WHITE ? Square.DELTA_S : Square.DELTA_N);

        ei.pinnedPieces[Us] = pos.pinned_pieces(Us);
        var b = ei.attackedBy[Them, PieceType.KING] = pos.attacks_from_PtS(PieceType.KING, pos.square(PieceType.KING, Them));
        ei.attackedBy[Them, PieceType.ALL_PIECES] |= b;
        ei.attackedBy[Us, PieceType.ALL_PIECES] |= ei.attackedBy[Us, PieceType.PAWN] = ei.pi.pawn_attacks(Us);

        // Init king safety tables only if we are going to use them
        if (pos.non_pawn_material(Us) >= Value.QueenValueMg)
        {
            ei.kingRing[Them] = b | Bitboard.shift_bb(Down, b);
            b &= ei.attackedBy[Us, PieceType.PAWN];
            ei.kingAttackersCount[Us] = b!=0 ? Bitcount.popcount_Max15(b) : 0;
            ei.kingAdjacentZoneAttacksCount[Us] = ei.kingAttackersWeight[Us] = 0;
        }
        else
        {
            ei.kingRing[Them] = Bitboard.Create(0);
            ei.kingAttackersCount[Us] = 0;
        }
    }