Example #1
0
 internal MaterialTable()
 {
     pieceCount[0] = new int[6];
     pieceCount[1] = new int[6];
     for (int i = 0; i < Constants.MaterialTableSize; i++)
     {
         entries[i] = new MaterialEntry();
     }
 }
Example #2
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);
        }
Example #3
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)
        {
            Key key = pos.material_key();

            e = entries[((UInt32)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
            Value 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;
            Color 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;
            }

            Value npm_w = pos.non_pawn_material(ColorC.WHITE);
            Value 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)
            {
                int 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.
            pieceCount[0][0] = pos.piece_count(ColorC.WHITE, PieceTypeC.BISHOP) > 1 ? 1 : 0;
            pieceCount[0][1] = pos.piece_count(ColorC.WHITE, PieceTypeC.PAWN);
            pieceCount[0][2] = pos.piece_count(ColorC.WHITE, PieceTypeC.KNIGHT);
            pieceCount[0][3] = pos.piece_count(ColorC.WHITE, PieceTypeC.BISHOP);
            pieceCount[0][4] = pos.piece_count(ColorC.WHITE, PieceTypeC.ROOK);
            pieceCount[0][5] = pos.piece_count(ColorC.WHITE, PieceTypeC.QUEEN);

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

            e.value = (Int16)((imbalance(ColorC.WHITE) - imbalance(ColorC.BLACK)) / 16);

            return;
        }
Example #4
0
 internal MaterialTable()
 {
     pieceCount[0] = new int[6];
     pieceCount[1] = new int[6];
     for (int i = 0; i < Constants.MaterialTableSize; i++)
     {
         entries[i] = new MaterialEntry();
     }
 }