/// Entry::do_king_safety() calculates a bonus for king safety. It is called only
            /// when king square changes, which is about 20% of total king_safety() calls.
            public Score do_king_safety(Position pos, Square ksq, Color Us)
            {
                kingSquares[Us]    = ksq;
                castlingRights[Us] = pos.can_castle_color(Us);
                minKPdistance[Us]  = 0;

                Bitboard pawns = pos.pieces_color_piecetype(Us, PieceTypeS.PAWN);

                if (pawns != 0)
                {
                    while (0 == (BitBoard.DistanceRingsBB[ksq][minKPdistance[Us]++] & pawns))
                    {
                    }
                }

                if (Types.relative_rank_square(Us, ksq) > RankS.RANK_4)
                {
                    return(Types.make_score(0, -16 * minKPdistance[Us]));
                }

                Value bonus = shelter_storm(pos, ksq, Us);

                // If we can castle use the bonus after the castle if is bigger
                if (pos.can_castle_castleright((new MakeCastlingS(Us, CastlingSideS.KING_SIDE)).right) != 0)
                {
                    bonus = Math.Max(bonus, shelter_storm(pos, Types.relative_square(Us, SquareS.SQ_G1), Us));
                }

                if (pos.can_castle_castleright((new MakeCastlingS(Us, CastlingSideS.QUEEN_SIDE)).right) != 0)
                {
                    bonus = Math.Max(bonus, shelter_storm(pos, Types.relative_square(Us, SquareS.SQ_C1), Us));
                }

                return(Types.make_score(bonus, -16 * minKPdistance[Us]));
            }
Exemple #2
0
        // evaluate_outposts() evaluates bishop and knight outpost squares
        public static Score evaluate_outposts(Position pos, EvalInfo ei, Square s, PieceType Pt, Color Us)
        {
            Color Them = (Us == ColorS.WHITE ? ColorS.BLACK : ColorS.WHITE);

            Debug.Assert(Pt == PieceTypeS.BISHOP || Pt == PieceTypeS.KNIGHT);

            // Initial bonus based on square
            Value bonus = Outpost[Pt == PieceTypeS.BISHOP ? 1 : 0][Types.relative_square(Us, s)];

            // Increase bonus if supported by pawn, especially if the opponent has
            // no minor piece which can trade with the outpost piece.
            if (bonus != 0 && (ei.attackedBy[Us][PieceTypeS.PAWN] & BitBoard.SquareBB[s]) != 0)
            {
                if (0 == pos.pieces_color_piecetype(Them, PieceTypeS.KNIGHT) &&
                    0 == (BitBoard.squares_of_color(s) & pos.pieces_color_piecetype(Them, PieceTypeS.BISHOP)))
                {
                    bonus += bonus + bonus / 2;
                }
                else
                {
                    bonus += bonus / 2;
                }
            }
            return(Types.make_score(bonus, bonus));
        }
        public static void init()
        {
            int bonus;

            //Score[/*FILE_NB*/][/*RANK_NB*/] Connected
            Connected = new Score[FileS.FILE_NB][];
            for (File f = FileS.FILE_A; f <= FileS.FILE_H; ++f)
            {
                Connected[f] = new Score[RankS.RANK_NB];
            }

            for (Rank r = RankS.RANK_1; r < RankS.RANK_8; ++r)
            {
                for (File f = FileS.FILE_A; f <= FileS.FILE_H; ++f)
                {
                    bonus           = r * (r - 1) * (r - 2) + bonusesByFile[f] * (r / 2 + 1);
                    Connected[f][r] = Types.make_score(bonus, bonus);
                }
            }
        }
Exemple #4
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]);
            }
        }
 public static Score S(int mg, int eg)
 {
     return(Types.make_score(mg, eg));
 }
Exemple #6
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]));
        }
Exemple #7
0
        // evaluate_pieces() assigns bonuses and penalties to the pieces of a given color
        public static Score evaluate_pieces(Position pos, EvalInfo ei, Score[] mobility, Bitboard[] mobilityArea, PieceType Pt, Color Us, bool Trace)
        {
            if (Us == ColorS.WHITE && Pt == PieceTypeS.KING)
            {
                return(ScoreS.SCORE_ZERO);
            }

            Bitboard b;
            Square   s;
            Score    score = ScoreS.SCORE_ZERO;

            PieceType NextPt = (Us == ColorS.WHITE ? Pt : (Pt + 1));
            Color     Them   = (Us == ColorS.WHITE ? ColorS.BLACK : ColorS.WHITE);

            Square[] pl    = pos.list(Us, Pt);
            int      plPos = 0;

            ei.attackedBy[Us][Pt] = 0;

            while ((s = pl[plPos++]) != SquareS.SQ_NONE)
            {
                // Find attacked squares, including x-ray attacks for bishops and rooks
                b = Pt == PieceTypeS.BISHOP ? BitBoard.attacks_bb_SBBPT(s, pos.pieces() ^ pos.pieces_color_piecetype(Us, PieceTypeS.QUEEN), PieceTypeS.BISHOP)
                  : Pt == PieceTypeS.ROOK ? BitBoard.attacks_bb_SBBPT(s, pos.pieces() ^ pos.pieces_color_piecetype(Us, PieceTypeS.ROOK, PieceTypeS.QUEEN), PieceTypeS.ROOK)
                                    : pos.attacks_from_square_piecetype(s, Pt);

                if ((ei.pinnedPieces[Us] & BitBoard.SquareBB[s]) != 0)
                {
                    b &= BitBoard.LineBB[pos.king_square(Us)][s];
                }

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

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

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

                int mob = (Pt != PieceTypeS.QUEEN ? Bitcount.popcount_Max15(b & mobilityArea[Us])
                                                  : Bitcount.popcount(b & mobilityArea[Us]));

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

                // Decrease score if we are attacked by an enemy pawn. The remaining part
                // of threat evaluation must be done later when we have full attack info.
                if ((ei.attackedBy[Them][PieceTypeS.PAWN] & BitBoard.SquareBB[s]) != 0)
                {
                    score -= ThreatenedByPawn[Pt];
                }

                if (Pt == PieceTypeS.BISHOP || Pt == PieceTypeS.KNIGHT)
                {
                    // Penalty for bishop with same coloured pawns
                    if (Pt == PieceTypeS.BISHOP)
                    {
                        score -= BishopPawns * ei.pi.pawns_on_same_color_squares(Us, s);
                    }

                    // Bishop and knight outposts squares
                    if (0 == (pos.pieces_color_piecetype(Them, PieceTypeS.PAWN) & BitBoard.pawn_attack_span(Us, s)))
                    {
                        score += evaluate_outposts(pos, ei, s, Pt, Us);
                    }

                    // Bishop or knight behind a pawn
                    if (Types.relative_rank_square(Us, s) < RankS.RANK_5 &&
                        (pos.pieces_piecetype(PieceTypeS.PAWN) & BitBoard.SquareBB[(s + Types.pawn_push(Us))]) != 0)
                    {
                        score += MinorBehindPawn;
                    }
                }

                if (Pt == PieceTypeS.ROOK)
                {
                    // Rook piece attacking enemy pawns on the same rank/file
                    if (Types.relative_rank_square(Us, s) >= RankS.RANK_5)
                    {
                        Bitboard pawns = pos.pieces_color_piecetype(Them, PieceTypeS.PAWN) & BitBoard.PseudoAttacks[PieceTypeS.ROOK][s];
                        if (pawns != 0)
                        {
                            score += Bitcount.popcount_Max15(pawns) * RookOnPawn;
                        }
                    }

                    // Give a bonus for a rook on a open or semi-open file
                    if (ei.pi.semiopen_file(Us, Types.file_of(s)) != 0)
                    {
                        score += ei.pi.semiopen_file(Them, Types.file_of(s)) != 0 ? RookOpenFile : RookSemiopenFile;
                    }

                    if (mob > 3 || ei.pi.semiopen_file(Us, Types.file_of(s)) != 0)
                    {
                        continue;
                    }

                    Square ksq = pos.king_square(Us);

                    // Penalize rooks which are trapped by a king. Penalize more if the
                    // king has lost its castling capability.
                    if (((Types.file_of(ksq) < FileS.FILE_E) == (Types.file_of(s) < Types.file_of(ksq))) &&
                        (Types.rank_of(ksq) == Types.rank_of(s) || Types.relative_rank_square(Us, ksq) == RankS.RANK_1) &&
                        0 == ei.pi.semiopen_side(Us, Types.file_of(ksq), Types.file_of(s) < Types.file_of(ksq)))
                    {
                        score -= (TrappedRook - Types.make_score(mob * 8, 0)) * (1 + (pos.can_castle_color(Us) == 0 ? 1 : 0));
                    }
                }

                // 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 == PieceTypeS.BISHOP &&
                    pos.is_chess960() != 0 &&
                    (s == Types.relative_square(Us, SquareS.SQ_A1) || s == Types.relative_square(Us, SquareS.SQ_H1)))
                {
                    Square d = Types.pawn_push(Us) + (Types.file_of(s) == FileS.FILE_A ? SquareS.DELTA_E : SquareS.DELTA_W);
                    if (pos.piece_on(s + d) == Types.make_piece(Us, PieceTypeS.PAWN))
                    {
                        score -= !pos.empty(s + d + Types.pawn_push(Us)) ? TrappedBishopA1H1 * 4
                            : pos.piece_on(s + d + d) == Types.make_piece(Us, PieceTypeS.PAWN) ? TrappedBishopA1H1 * 2
                                                                            : TrappedBishopA1H1;
                    }
                }
            }

            if (Trace)
            {
                Tracing.terms[Us][Pt] = score;
            }

            return(score - evaluate_pieces(pos, ei, mobility, mobilityArea, NextPt, Them, Trace));
        }
Exemple #8
0
        public static Score[][] KingDanger = new Score[ColorS.COLOR_NB][] { new Score[128], new Score[128] }; // 2, 128

        // apply_weight() weighs score 'v' by weight 'w' trying to prevent overflow
        public static Score apply_weight(Score v, WeightS w)
        {
            return(Types.make_score(Types.mg_value(v) * w.mg / 256, Types.eg_value(v) * w.eg / 256));
        }
 public Score material_value()
 {
     return(Types.make_score(value, value));
 }
        /// Material::probe() takes a position object as input, looks up a MaterialEntry
        /// object, and returns a pointer to it. If the material configuration is not
        /// already present in the table, it is computed and stored there, so we don't
        /// have to recompute everything when the same material configuration occurs again.

        public static Material.Entry probe(Position pos, Material.Table entries, Endgames endgames)
        {
            Key key = pos.material_key();

            Material.Entry e = entries[key];

            // If e.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(e);
            }

            e.value = 0;
            e.evaluationFunction = null;
            e.scalingFunction[0] = e.scalingFunction[1] = null;
            e.spaceWeight        = 0;
            e.key = key;
            e.factor[ColorS.WHITE] = e.factor[ColorS.BLACK] = (byte)ScaleFactorS.SCALE_FACTOR_NORMAL;
            e.gamePhase            = game_phase(pos);

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

            if (is_KXK(pos, ColorS.WHITE))
            {
                e.evaluationFunction = EvaluateKXK[ColorS.WHITE];
                return(e);
            }

            if (is_KXK(pos, ColorS.BLACK))
            {
                e.evaluationFunction = EvaluateKXK[ColorS.BLACK];
                return(e);
            }


            // 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.
            EndgameBase sf;

            if (endgames.probeScaleFunction(key, out sf) != null)
            {
                e.scalingFunction[sf.color()] = sf;
                return(e);
            }

            // Generic scaling functions that refer to more than one material
            // distribution. They should be probed after the specialized ones.
            // Note that these ones don't return after setting the function.
            if (is_KBPsKs(pos, ColorS.WHITE))
            {
                e.scalingFunction[ColorS.WHITE] = ScaleKBPsK[ColorS.WHITE];
            }

            if (is_KBPsKs(pos, ColorS.BLACK))
            {
                e.scalingFunction[ColorS.BLACK] = ScaleKBPsK[ColorS.BLACK];
            }

            if (is_KQKRPs(pos, ColorS.WHITE))
            {
                e.scalingFunction[ColorS.WHITE] = ScaleKQKRPs[ColorS.WHITE];
            }

            else if (is_KQKRPs(pos, ColorS.BLACK))
            {
                e.scalingFunction[ColorS.BLACK] = ScaleKQKRPs[ColorS.BLACK];
            }

            Value npm_w = pos.non_pawn_material(ColorS.WHITE);
            Value npm_b = pos.non_pawn_material(ColorS.BLACK);

            if (npm_w + npm_b == ValueS.VALUE_ZERO && pos.pieces_piecetype(PieceTypeS.PAWN) != 0)
            {
                if (0 == pos.count(ColorS.BLACK, PieceTypeS.PAWN))
                {
                    Debug.Assert(pos.count(ColorS.WHITE, PieceTypeS.PAWN) >= 2);
                    e.scalingFunction[ColorS.WHITE] = ScaleKPsK[ColorS.WHITE];
                }
                else if (0 == pos.count(ColorS.WHITE, PieceTypeS.PAWN))
                {
                    Debug.Assert(pos.count(ColorS.BLACK, PieceTypeS.PAWN) >= 2);
                    e.scalingFunction[ColorS.BLACK] = ScaleKPsK[ColorS.BLACK];
                }
                else if (pos.count(ColorS.WHITE, PieceTypeS.PAWN) == 1 && pos.count(ColorS.BLACK, PieceTypeS.PAWN) == 1)
                {
                    // This is a special case because we set scaling functions
                    // for both colors instead of only one.
                    e.scalingFunction[ColorS.WHITE] = ScaleKPKP[ColorS.WHITE];
                    e.scalingFunction[ColorS.BLACK] = ScaleKPKP[ColorS.BLACK];
                }
            }

            // No pawns makes it difficult to win, even with a material advantage. This
            // catches some trivial draws like KK, KBK and KNK and gives a very drawish
            // scale factor for cases such as KRKBP and KmmKm (except for KBBKN).
            if (0 == pos.count(ColorS.WHITE, PieceTypeS.PAWN) && npm_w - npm_b <= ValueS.BishopValueMg)
            {
                e.factor[ColorS.WHITE] = (byte)(npm_w < ValueS.RookValueMg ? ScaleFactorS.SCALE_FACTOR_DRAW : npm_b <= ValueS.BishopValueMg ? 4 : 12);
            }

            if (0 == pos.count(ColorS.BLACK, PieceTypeS.PAWN) && npm_b - npm_w <= ValueS.BishopValueMg)
            {
                e.factor[ColorS.BLACK] = (byte)(npm_b < ValueS.RookValueMg ? ScaleFactorS.SCALE_FACTOR_DRAW : npm_w <= ValueS.BishopValueMg ? 4 : 12);
            }

            if (pos.count(ColorS.WHITE, PieceTypeS.PAWN) == 1 && npm_w - npm_b <= ValueS.BishopValueMg)
            {
                e.factor[ColorS.WHITE] = (byte)ScaleFactorS.SCALE_FACTOR_ONEPAWN;
            }

            if (pos.count(ColorS.BLACK, PieceTypeS.PAWN) == 1 && npm_b - npm_w <= ValueS.BishopValueMg)
            {
                e.factor[ColorS.BLACK] = (byte)ScaleFactorS.SCALE_FACTOR_ONEPAWN;
            }

            // Compute the space weight
            if (npm_w + npm_b >= 2 * ValueS.QueenValueMg + 4 * ValueS.RookValueMg + 2 * ValueS.KnightValueMg)
            {
                int minorPieceCount = pos.count(ColorS.WHITE, PieceTypeS.KNIGHT) + pos.count(ColorS.WHITE, PieceTypeS.BISHOP)
                                      + pos.count(ColorS.BLACK, PieceTypeS.KNIGHT) + pos.count(ColorS.BLACK, PieceTypeS.BISHOP);

                e.spaceWeight = Types.make_score(minorPieceCount * minorPieceCount, 0);
            }

            // 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.
            int[][] pieceCount = new int[ColorS.COLOR_NB][] {
                new int[] { pos.count(ColorS.WHITE, PieceTypeS.BISHOP) > 1 ? 1 : 0, pos.count(ColorS.WHITE, PieceTypeS.PAWN), pos.count(ColorS.WHITE, PieceTypeS.KNIGHT),
                            pos.count(ColorS.WHITE, PieceTypeS.BISHOP), pos.count(ColorS.WHITE, PieceTypeS.ROOK), pos.count(ColorS.WHITE, PieceTypeS.QUEEN) },
                new int[] { pos.count(ColorS.BLACK, PieceTypeS.BISHOP) > 1 ? 1 : 0, pos.count(ColorS.BLACK, PieceTypeS.PAWN), pos.count(ColorS.BLACK, PieceTypeS.KNIGHT),
                            pos.count(ColorS.BLACK, PieceTypeS.BISHOP), pos.count(ColorS.BLACK, PieceTypeS.ROOK), pos.count(ColorS.BLACK, PieceTypeS.QUEEN) }
            };

            e.value = (Int16)((imbalance(pieceCount, ColorS.WHITE) - imbalance(pieceCount, ColorS.BLACK)) / 16);
            return(e);
        }