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]}"); } }
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); }
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)); }
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)); }
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); }
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); }
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); }
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); } }
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); }
private static string GetMgEgString(int mgEgScore) { return(EvalUtil.GetMgScore(mgEgScore) + "/" + EvalUtil.GetEgScore(mgEgScore)); }
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(); }