public static void Main()
        {
            var fens = Tuner.LoadFens("d:\\backup\\chess\\epds\\quiet-labeled.epd", true, false);

            Console.WriteLine(fens.Count + " fens found");

            var cb         = ChessBoardInstances.Get(0);
            var threadData = ThreadData.GetInstance(0);

            foreach (var(key, value) in fens)
            {
                ChessBoardUtil.SetFen(key, cb);
                var error = Math.Pow(value - ErrorCalculator.CalculateSigmoid(EvalUtil.CalculateScore(cb, threadData)),
                                     2);

                for (var i = 0; i < LargestError.Length; i++)
                {
                    if (!(error > LargestError[i]))
                    {
                        continue;
                    }
                    LargestError[i]    = error;
                    LargestErrorFen[i] = key;
                    break;
                }
            }

            for (var i = 0; i < LargestError.Length; i++)
            {
                Console.WriteLine($"{LargestErrorFen[i],60} -> {LargestError[i]}");
            }
        }
Esempio n. 2
0
        private static int Perft(ChessBoard cb, ThreadData threadData, int depth)
        {
            threadData.StartPly();
            MoveGenerator.GenerateMoves(threadData, cb);
            MoveGenerator.GenerateAttacks(threadData, cb);

            if (depth == 0)
            {
                threadData.EndPly();
                return(1);
            }

            var counter = 0;

            while (threadData.HasNext())
            {
                var move = threadData.Next();
                if (!cb.IsLegal(move))
                {
                    continue;
                }

                cb.DoMove(move);
                EvalUtil.CalculateScore(cb, threadData);
                counter += Perft(cb, threadData, depth - 1);
                cb.UndoMove(move);
            }

            threadData.EndPly();
            return(counter);
        }
Esempio n. 3
0
        public static void Main()
        {
            var cb = ChessBoardInstances.Get(0);

            ChessBoardUtil.SetFen("1r1q1rk1/2p1npb1/b3p1p1/p5N1/1ppPB2R/P1N1P1P1/1P2QPP1/2K4R w - - 0 20 ", cb);
            EvalUtil.CalculateScore(cb, ThreadData.GetInstance(0));
        }
Esempio n. 4
0
        public static void Main()
        {
            var cb = ChessBoardInstances.Get(0);

            // read all fens, including score
            var fens = Tuner.LoadFens("d:\\backup\\chess\\epds\\violent.epd", false, true);

            Console.WriteLine("Fens found : " + fens.Count);

            double sameScore    = 0;
            double totalAttacks = 0;
            var    start        = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

            foreach (var entry in fens)
            {
                ChessBoardUtil.SetFen(entry.Key, cb);
                _threadData.StartPly();
                MoveGenerator.GenerateAttacks(_threadData, cb);
                while (_threadData.HasNext())
                {
                    var move = _threadData.Next();
                    if (!cb.IsLegal(move))
                    {
                        continue;
                    }

                    totalAttacks++;
                    var seeScore      = SeeUtil.GetSeeCaptureScore(cb, move);
                    var materialScore = EvalUtil.CalculateMaterialScore(cb);
                    var qScore        = ChessConstants.ColorFactor[cb.ColorToMoveInverse] * materialScore -
                                        CalculateQScore(cb, move, true);
                    if (seeScore == qScore)
                    {
                        sameScore++;
                    }

                    // else {
                    // seeScore = SEEUtil.getSeeCaptureScore(cb, move);
                    // qScore = ChessConstants.COLOR_FACTOR[cb.colorToMoveInverse] * materialScore - calculateQScore(cb,
                    // move, true);
                    // }
                }

                _threadData.EndPly();
            }

            Console.WriteLine($"{sameScore:f0} {totalAttacks:f0} = {sameScore / totalAttacks:f4}");
            Console.WriteLine("msec: " + (DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - start));
        }
Esempio n. 5
0
        public double Call()
        {
            double totalError = 0;

            foreach (var(key, value) in _fens)
            {
                ChessBoardUtil.SetFen(key, _cb);
                totalError += Math.Pow(
                    value - CalculateSigmoid(ChessConstants.ColorFactor[_cb.ColorToMove] *
                                             EvalUtil.CalculateScore(_cb, _threadData)),
                    2);
            }

            totalError /= _fens.Count;
            return(totalError);
        }
Esempio n. 6
0
        public static void Init(ChessBoard cb)
        {
            MaterialUtil.SetKey(cb);

            cb.KingIndex[White] = BitOperations.TrailingZeroCount(cb.Pieces[White][King]);
            cb.KingIndex[Black] = BitOperations.TrailingZeroCount(cb.Pieces[Black][King]);

            cb.ColorToMoveInverse = 1 - cb.ColorToMove;
            cb.Pieces[White][All] = cb.Pieces[White][Pawn] | cb.Pieces[White][Bishop] | cb.Pieces[White][Knight] |
                                    cb.Pieces[White][King] | cb.Pieces[White][Rook]
                                    | cb.Pieces[White][Queen];
            cb.Pieces[Black][All] = cb.Pieces[Black][Pawn] | cb.Pieces[Black][Bishop] | cb.Pieces[Black][Knight] |
                                    cb.Pieces[Black][King] | cb.Pieces[Black][Rook]
                                    | cb.Pieces[Black][Queen];
            cb.AllPieces   = cb.Pieces[White][All] | cb.Pieces[Black][All];
            cb.EmptySpaces = ~cb.AllPieces;

            Array.Fill(cb.PieceIndexes, Empty);
            foreach (var t in cb.Pieces)
            {
                for (var pieceIndex = 1; pieceIndex < cb.Pieces[0].Length; pieceIndex++)
                {
                    var piece = t[pieceIndex];
                    while (piece != 0)
                    {
                        cb.PieceIndexes[BitOperations.TrailingZeroCount(piece)] = pieceIndex;
                        piece &= piece - 1;
                    }
                }
            }

            cb.SetCheckingPinnedAndDiscoPieces();
            cb.PsqtScore = EvalUtil.CalculatePositionScores(cb);

            cb.Phase = EvalUtil.PhaseTotal -
                       (BitOperations.PopCount((ulong)(cb.Pieces[White][Knight] | cb.Pieces[Black][Knight])) *
                        EvalConstants.Phase[Knight]
                        + BitOperations.PopCount((ulong)(cb.Pieces[White][Bishop] | cb.Pieces[Black][Bishop])) *
                        EvalConstants.Phase[Bishop]
                        + BitOperations.PopCount((ulong)(cb.Pieces[White][Rook] | cb.Pieces[Black][Rook])) *
                        EvalConstants.Phase[Rook]
                        + BitOperations.PopCount((ulong)(cb.Pieces[White][Queen] | cb.Pieces[Black][Queen])) *
                        EvalConstants.Phase[Queen]);

            Zobrist.SetPawnKey(cb);
            Zobrist.SetKey(cb);
        }
Esempio n. 7
0
        private static int CalculateQScore(ChessBoard cb, int move, bool isFirstMove)
        {
            var bestScore = Util.ShortMin;

            cb.DoMove(move);

            _threadData.StartPly();
            MoveGenerator.GenerateAttacks(_threadData, cb);

            var movePerformed = false;

            while (_threadData.HasNext())
            {
                // only attacks on the same square
                var currentMove = _threadData.Next();
                if (!cb.IsLegal(currentMove))
                {
                    continue;
                }

                if (MoveUtil.GetToIndex(currentMove) != MoveUtil.GetToIndex(move))
                {
                    continue;
                }

                var score = -CalculateQScore(cb, currentMove, false);
                score = Math.Max(score,
                                 ChessConstants.ColorFactor[cb.ColorToMove] * EvalUtil.CalculateMaterialScore(cb));

                movePerformed = true;
                if (score > bestScore)
                {
                    bestScore = score;
                }
            }

            _threadData.EndPly();

            if (!movePerformed)
            {
                bestScore = ChessConstants.ColorFactor[cb.ColorToMove] * EvalUtil.CalculateMaterialScore(cb);
            }

            cb.UndoMove(move);
            return(bestScore);
        }
Esempio n. 8
0
        public static void Eval(ChessBoard cb, ThreadData threadData)
        {
            var mobilityScore = EvalUtil.CalculateMobilityScoresAndSetAttacks(cb);

            Console.WriteLine(" Material imbalance: " + EvalUtil.GetImbalances(cb, threadData.MaterialCache));
            Console.WriteLine("          Position : " + GetMgEgString(cb.PsqtScore));
            Console.WriteLine("          Mobility : " + GetMgEgString(mobilityScore));
            Console.WriteLine(" Pawn : " + EvalUtil.GetPawnScores(cb, threadData.PawnCache));
            Console.WriteLine("       Pawn-passed : " + GetMgEgString(PassedPawnEval.CalculateScores(cb)));
            Console.WriteLine("       Pawn shield : " + GetMgEgString(EvalUtil.CalculatePawnShieldBonus(cb)));
            Console.WriteLine("       King-safety : " + KingSafetyEval.CalculateScores(cb));
            Console.WriteLine("           Threats : " + GetMgEgString(EvalUtil.CalculateThreats(cb)));
            Console.WriteLine("             Other : " + EvalUtil.CalculateOthers(cb));
            Console.WriteLine("             Space : " + EvalUtil.CalculateSpace(cb));
            Console.WriteLine("-----------------------------");
            Console.WriteLine(" Total : " +
                              ChessConstants.ColorFactor[cb.ColorToMove] * EvalUtil.GetScore(cb, threadData));
        }
        private static void CompareScores(ChessBoard cb1, ChessBoard cb2, int factor)
        {
            EvalUtil.CalculateMobilityScoresAndSetAttacks(cb1);
            EvalUtil.CalculateMobilityScoresAndSetAttacks(cb2);

            if (KingSafetyEval.CalculateScores(cb2) != KingSafetyEval.CalculateScores(cb1) * factor)
            {
                Console.WriteLine("Unequal king-safety: " + KingSafetyEval.CalculateScores(cb1) + " " +
                                  KingSafetyEval.CalculateScores(cb2) * factor);
            }

            if (EvalUtil.CalculatePositionScores(cb1) != EvalUtil.CalculatePositionScores(cb2) * factor)
            {
                Console.WriteLine("Unequal position score: " + EvalUtil.CalculatePositionScores(cb1) + " " +
                                  EvalUtil.CalculatePositionScores(cb2) * factor);
            }

            // if (EvalUtil.getPawnScores(cb1) != EvalUtil.getPawnScores(cb2) * factor) {
            // System.out.println("Unequal pawns: " + EvalUtil.getPawnScores(cb1) + " " + EvalUtil.getPawnScores(cb2) *
            // factor);
            // }
            // if (EvalUtil.getImbalances(cb1) != EvalUtil.getImbalances(cb2) * factor) {
            // System.out.println("Unequal imbalances: " + EvalUtil.getImbalances(cb1) + " " + EvalUtil.getImbalances(cb2) *
            // factor);
            // }
            if (EvalUtil.CalculateOthers(cb2) != EvalUtil.CalculateOthers(cb1) * factor)
            {
                Console.WriteLine("Unequal others: " + EvalUtil.CalculateOthers(cb1) + " " +
                                  EvalUtil.CalculateOthers(cb2) * factor);
            }

            if (EvalUtil.CalculateThreats(cb2) != EvalUtil.CalculateThreats(cb1) * factor)
            {
                Console.WriteLine("Unequal threats: " + EvalUtil.CalculateThreats(cb1) + " " +
                                  EvalUtil.CalculateThreats(cb2) * factor);
            }

            if (PassedPawnEval.CalculateScores(cb1) != PassedPawnEval.CalculateScores(cb2) * factor)
            {
                Console.WriteLine("Unequal passed-pawns: " + PassedPawnEval.CalculateScores(cb1) + " " +
                                  PassedPawnEval.CalculateScores(cb2) * factor);
            }
        }
Esempio n. 10
0
        public static int CalculateBestMove(ChessBoard cb, ThreadData threadData, int ply, int depth,
                                            int alpha, int beta,
                                            int nullMoveCounter)
        {
            if (!IsRunning)
            {
                return(ChessConstants.ScoreNotRunning);
            }

            if (EngineConstants.Assert)
            {
                Assert.IsTrue(depth >= 0);
                Assert.IsTrue(alpha >= Util.ShortMin && alpha <= Util.ShortMax);
                Assert.IsTrue(beta >= Util.ShortMin && beta <= Util.ShortMax);
            }

            var alphaOrig = alpha;

            // get extensions
            depth += Extensions(cb);

            /* mate-distance pruning */
            if (EngineConstants.EnableMateDistancePruning)
            {
                alpha = Math.Max(alpha, Util.ShortMin + ply);
                beta  = Math.Min(beta, Util.ShortMax - ply - 1);
                if (alpha >= beta)
                {
                    return(alpha);
                }
            }

            // TODO JITWatch unpredictable branch
            if (depth == 0)
            {
                return(QuiescenceUtil.CalculateBestMove(cb, threadData, alpha, beta));
            }

            /* transposition-table */
            var ttEntry = TtUtil.GetEntry(cb.ZobristKey);
            var score   = ttEntry.GetScore(ply);

            if (ttEntry.Key != 0)
            {
                if (!EngineConstants.TestTtValues)
                {
                    if (ttEntry.Depth >= depth)
                    {
                        switch (ttEntry.Flag)
                        {
                        case TtUtil.FlagExact:
                            return(score);

                        case TtUtil.FlagLower:
                            if (score >= beta)
                            {
                                return(score);
                            }

                            break;

                        case TtUtil.FlagUpper:
                            if (score <= alpha)
                            {
                                return(score);
                            }

                            break;
                        }
                    }
                }
            }

            if (Statistics.Enabled)
            {
                Statistics.AbNodes++;
            }

            var eval = Util.ShortMin;
            var isPv = beta - alpha != 1;

            if (!isPv && cb.CheckingPieces == 0)
            {
                eval = EvalUtil.GetScore(cb, threadData);

                /* use tt value as eval */
                if (EngineConstants.UseTtScoreAsEval)
                {
                    if (TtUtil.CanRefineEval(ttEntry, eval, score))
                    {
                        eval = score;
                    }
                }

                /* static null move pruning */
                if (EngineConstants.EnableStaticNullMove && depth < StaticNullmoveMargin.Length)
                {
                    if (eval - StaticNullmoveMargin[depth] >= beta)
                    {
                        if (Statistics.Enabled)
                        {
                            Statistics.StaticNullMoved[depth]++;
                        }

                        return(eval);
                    }
                }

                /* razoring */
                if (EngineConstants.EnableRazoring && depth < RazoringMargin.Length &&
                    Math.Abs(alpha) < EvalConstants.ScoreMateBound)
                {
                    if (eval + RazoringMargin[depth] < alpha)
                    {
                        score = QuiescenceUtil.CalculateBestMove(cb, threadData, alpha - RazoringMargin[depth],
                                                                 alpha - RazoringMargin[depth] + 1);
                        if (score + RazoringMargin[depth] <= alpha)
                        {
                            if (Statistics.Enabled)
                            {
                                Statistics.Razored[depth]++;
                            }

                            return(score);
                        }
                    }
                }

                /* null-move */
                if (EngineConstants.EnableNullMove)
                {
                    if (nullMoveCounter < 2 && eval >= beta &&
                        MaterialUtil.HasNonPawnPieces(cb.MaterialKey, cb.ColorToMove))
                    {
                        cb.DoNullMove();
                        // TODO less reduction if stm (other side) has only 1 major piece
                        var reduction = depth / 4 + 3 + Math.Min((eval - beta) / 80, 3);
                        score = depth - reduction <= 0
                            ? -QuiescenceUtil.CalculateBestMove(cb, threadData, -beta, -beta + 1)
                            : -CalculateBestMove(cb, threadData, ply + 1, depth - reduction, -beta, -beta + 1,
                                                 nullMoveCounter + 1);
                        cb.UndoNullMove();
                        if (score >= beta)
                        {
                            if (Statistics.Enabled)
                            {
                                Statistics.NullMoveHit++;
                            }

                            return(score);
                        }

                        if (Statistics.Enabled)
                        {
                            Statistics.NullMoveMiss++;
                        }
                    }
                }
            }

            var parentMove     = ply == 0 ? 0 : threadData.Previous();
            var bestMove       = 0;
            var bestScore      = Util.ShortMin - 1;
            var ttMove         = 0;
            var counterMove    = 0;
            var killer1Move    = 0;
            var killer2Move    = 0;
            var movesPerformed = 0;

            threadData.StartPly();
            var phase = PhaseTt;

            while (phase <= PhaseQuiet)
            {
                switch (phase)
                {
                case PhaseTt:
                    if (ttEntry.Key != 0)
                    {
                        ttMove = ttEntry.Move;
                        if (cb.IsValidMove(ttMove))
                        {
                            threadData.AddMove(ttMove);
                        }

                        // else {
                        // throw new RuntimeException("invalid tt-move found: " + new MoveWrapper(ttMove));
                        // }
                    }

                    break;

                case PhaseAttacking:
                    MoveGenerator.GenerateAttacks(threadData, cb);
                    threadData.SetMvvlvaScores();
                    threadData.Sort();
                    break;

                case PhaseKiller1:
                    killer1Move = threadData.GetKiller1(ply);
                    if (killer1Move != 0 && killer1Move != ttMove && cb.IsValidMove(killer1Move))
                    {
                        threadData.AddMove(killer1Move);
                        break;
                    }

                    phase++;
                    goto case PhaseKiller2;

                case PhaseKiller2:
                    killer2Move = threadData.GetKiller2(ply);
                    if (killer2Move != 0 && killer2Move != ttMove && cb.IsValidMove(killer2Move))
                    {
                        threadData.AddMove(killer2Move);
                        break;
                    }

                    phase++;
                    goto case PhaseCounter;

                case PhaseCounter:
                    counterMove = threadData.GetCounter(cb.ColorToMove, parentMove);
                    if (counterMove != 0 && counterMove != ttMove && counterMove != killer1Move &&
                        counterMove != killer2Move && cb.IsValidMove(counterMove))
                    {
                        threadData.AddMove(counterMove);
                        break;
                    }

                    phase++;
                    goto case PhaseQuiet;

                case PhaseQuiet:
                    MoveGenerator.GenerateMoves(threadData, cb);
                    threadData.SetHhScores(cb.ColorToMove);
                    threadData.Sort();
                    break;
                }

                while (threadData.HasNext())
                {
                    var move = threadData.Next();

                    switch (phase)
                    {
                    case PhaseQuiet when move == ttMove || move == killer1Move || move == killer2Move ||
                        move == counterMove ||
                        !cb.IsLegal(move):
                    case PhaseAttacking when move == ttMove || !cb.IsLegal(move):
                        continue;
                    }

                    // pruning allowed?
                    if (!isPv && cb.CheckingPieces == 0 && movesPerformed > 0 && threadData.GetMoveScore() < 100 &&
                        !cb.IsDiscoveredMove(MoveUtil.GetFromIndex(move)))
                    {
                        if (phase == PhaseQuiet)
                        {
                            /* late move pruning */
                            if (EngineConstants.EnableLmp && depth <= 4 && movesPerformed >= depth * 3 + 3)
                            {
                                if (Statistics.Enabled)
                                {
                                    Statistics.Lmped[depth]++;
                                }

                                continue;
                            }

                            /* futility pruning */
                            if (EngineConstants.EnableFutilityPruning && depth < FutilityMargin.Length)
                            {
                                if (!MoveUtil.IsPawnPush78(move))
                                {
                                    if (eval == Util.ShortMin)
                                    {
                                        eval = EvalUtil.GetScore(cb, threadData);
                                    }

                                    if (eval + FutilityMargin[depth] <= alpha)
                                    {
                                        if (Statistics.Enabled)
                                        {
                                            Statistics.Futile[depth]++;
                                        }

                                        continue;
                                    }
                                }
                            }
                        }
                        /* SEE Pruning */
                        else if (EngineConstants.EnableSeePruning && depth <= 6 && phase == PhaseAttacking &&
                                 SeeUtil.GetSeeCaptureScore(cb, move) < -20 * depth * depth)
                        {
                            continue;
                        }
                    }

                    cb.DoMove(move);
                    movesPerformed++;

                    /* draw check */
                    if (cb.IsRepetition(move) || MaterialUtil.IsDrawByMaterial(cb))
                    {
                        score = EvalConstants.ScoreDraw;
                    }
                    else
                    {
                        score = alpha + 1; // initial is above alpha

                        var reduction = 1;
                        if (depth > 2 && movesPerformed > 1 && MoveUtil.IsQuiet(move) && !MoveUtil.IsPawnPush78(move))
                        {
                            reduction = LmrTable[Math.Min(depth, 63)][Math.Min(movesPerformed, 63)];
                            if (threadData.GetMoveScore() > 40)
                            {
                                reduction -= 1;
                            }

                            if (move == killer1Move || move == killer2Move || move == counterMove)
                            {
                                reduction -= 1;
                            }

                            if (!isPv)
                            {
                                reduction += 1;
                            }

                            reduction = Math.Min(depth - 1, Math.Max(reduction, 1));
                        }

                        /* LMR */
                        if (EngineConstants.EnableLmr && reduction != 1)
                        {
                            score = -CalculateBestMove(cb, threadData, ply + 1, depth - reduction, -alpha - 1, -alpha,
                                                       0);
                        }

                        /* PVS */
                        if (EngineConstants.EnablePvs && score > alpha && movesPerformed > 1)
                        {
                            score = -CalculateBestMove(cb, threadData, ply + 1, depth - 1, -alpha - 1, -alpha, 0);
                        }

                        /* normal bounds */
                        if (score > alpha)
                        {
                            score = -CalculateBestMove(cb, threadData, ply + 1, depth - 1, -beta, -alpha, 0);
                        }
                    }

                    cb.UndoMove(move);

                    if (score > bestScore)
                    {
                        bestScore = score;
                        bestMove  = move;

                        if (ply == 0 && IsRunning)
                        {
                            threadData.SetBestMove(cb, bestMove, alphaOrig, beta, bestScore, depth);
                        }

                        alpha = Math.Max(alpha, score);
                        if (alpha >= beta)
                        {
                            if (Statistics.Enabled)
                            {
                                Statistics.FailHigh[Math.Min(movesPerformed - 1, Statistics.FailHigh.Length - 1)]++;
                            }

                            /* killer and history */
                            if (MoveUtil.IsQuiet(move) && cb.CheckingPieces == 0)
                            {
                                threadData.AddCounterMove(cb.ColorToMove, parentMove, move);
                                threadData.AddKillerMove(move, ply);
                                threadData.AddHhValue(cb.ColorToMove, move, depth);
                            }

                            phase += 10;
                            break;
                        }
                    }

                    if (MoveUtil.IsQuiet(move))
                    {
                        threadData.AddBfValue(cb.ColorToMove, move, depth);
                    }
                }

                phase++;
            }

            threadData.EndPly();

            /* checkmate or stalemate */
            if (movesPerformed == 0)
            {
                if (cb.CheckingPieces == 0)
                {
                    if (Statistics.Enabled)
                    {
                        Statistics.StaleMateCount++;
                    }

                    return(EvalConstants.ScoreDraw);
                }

                if (Statistics.Enabled)
                {
                    Statistics.MateCount++;
                }

                return(Util.ShortMin + ply);
            }

            if (EngineConstants.Assert)
            {
                Assert.IsTrue(bestMove != 0);
            }

            // set tt-flag
            var flag = TtUtil.FlagExact;

            if (bestScore >= beta)
            {
                flag = TtUtil.FlagLower;
            }
            else if (bestScore <= alphaOrig)
            {
                flag = TtUtil.FlagUpper;
            }

            if (IsRunning)
            {
                TtUtil.AddValue(cb.ZobristKey, bestScore, ply, depth, flag, bestMove);
            }

            Statistics.SetBestMove(cb, bestMove, ttMove, ttEntry, flag, counterMove, killer1Move, killer2Move);

            if (EngineConstants.TestTtValues)
            {
                SearchTestUtil.TestTtValues(score, bestScore, depth, bestMove, flag, ttEntry, ply);
            }

            return(bestScore);
        }
Esempio n. 11
0
 private static string GetMgEgString(int mgEgScore)
 {
     return(EvalUtil.GetMgScore(mgEgScore) + "/" + EvalUtil.GetEgScore(mgEgScore));
 }
Esempio n. 12
0
        public static void Main()
        {
            var fens = Tuner.LoadFens("d:\\backup\\chess\\epds\\quiet-labeled.epd", true, false);

            Console.WriteLine(fens.Count + " fens found");

            var kpk   = new ErrorCount("KPK ");
            var kbnk  = new ErrorCount("KBNK");
            var kbpk  = new ErrorCount("KBPK");
            var krkp  = new ErrorCount("KRKP");
            var kqkp  = new ErrorCount("KQKP");
            var krkb  = new ErrorCount("KRKB");
            var krkn  = new ErrorCount("KRKN");
            var kbpkp = new ErrorCount("KBPKP");
            var krbkb = new ErrorCount("KRBKB");
            var krbkr = new ErrorCount("KRBKR");

            var cb         = ChessBoardInstances.Get(0);
            var threadData = ThreadData.GetInstance(0);

            foreach (var(key, value) in fens)
            {
                ChessBoardUtil.SetFen(key, cb);

                var error = Math.Pow(
                    value - ErrorCalculator.CalculateSigmoid(ChessConstants.ColorFactor[cb.ColorToMove] *
                                                             EvalUtil.CalculateScore(cb, threadData)),
                    2);
                if (MaterialUtil.IsKbnk(cb.MaterialKey))
                {
                    kbnk.AddError(error);
                }
                else if (MaterialUtil.IsKqkp(cb.MaterialKey))
                {
                    kqkp.AddError(error);
                }
                else if (MaterialUtil.IsKrkp(cb.MaterialKey))
                {
                    krkp.AddError(error);
                }
                else if (MaterialUtil.IsKrkb(cb.MaterialKey))
                {
                    krkb.AddError(error);
                }
                else if (MaterialUtil.IsKrkn(cb.MaterialKey))
                {
                    krkn.AddError(error);
                }
                else if (MaterialUtil.IsKpk(cb.MaterialKey))
                {
                    krkn.AddError(error);
                }
                else if (MaterialUtil.IsKbpk(cb.MaterialKey))
                {
                    kbpk.AddError(error);
                }
                else if (MaterialUtil.IsKbpkp(cb.MaterialKey))
                {
                    kbpkp.AddError(error);
                }
                else if (MaterialUtil.IsKrbkb(cb.MaterialKey))
                {
                    krbkb.AddError(error);
                }
                else if (MaterialUtil.IsKrbkr(cb.MaterialKey))
                {
                    krbkr.AddError(error);
                }
            }

            kpk.Print();
            kbnk.Print();
            krkp.Print();
            kqkp.Print();
            krkb.Print();
            krkn.Print();
            krbkb.Print();
            krbkr.Print();
            kbpk.Print();
            kbpkp.Print();
        }