public static int GetLoudMoves(BoardState boardState, Span <Move> moves, int offset, ulong evasionMask) { var color = boardState.ColorToMove; var enemyColor = ColorOperations.Invert(color); var queens = boardState.Pieces[color][Piece.Queen]; while (queens != 0) { var piece = BitOperations.GetLsb(queens); queens = BitOperations.PopLsb(queens); var from = BitOperations.BitScan(piece); var availableMoves = QueenMovesGenerator.GetMoves(boardState.OccupancySummary, from) & boardState.Occupancy[enemyColor]; availableMoves &= evasionMask; while (availableMoves != 0) { var field = BitOperations.GetLsb(availableMoves); var fieldIndex = BitOperations.BitScan(field); availableMoves = BitOperations.PopLsb(availableMoves); moves[offset++] = new Move(from, fieldIndex, MoveFlags.Capture); } } return(offset); }
private static bool LMRCanBeApplied(SearchContext context, int depth, bool friendlyKingInCheck, bool enemyKingInCheck, int moveIndex, Span <Move> moves, Span <short> moveValues) { if (depth >= SearchConstants.LMRMinDepth && moveIndex >= SearchConstants.LMRMovesWithoutReduction && (moves[moveIndex].IsQuiet() || (moves[moveIndex].IsCapture() && moveValues[moveIndex] < 0)) && !friendlyKingInCheck && !enemyKingInCheck) { var enemyColor = ColorOperations.Invert(context.BoardState.ColorToMove); var piece = context.BoardState.PieceTable[moves[moveIndex].To]; if (HistoryHeuristic.GetRawMoveValue(enemyColor, piece, moves[moveIndex].To) >= HistoryHeuristic.GetMaxValue() / SearchConstants.LMRMaxHistoryValueDivider) { return(false); } if (piece == Piece.Pawn && context.BoardState.IsFieldPassing(enemyColor, moves[moveIndex].To)) { return(false); } #if DEBUG context.Statistics.LMRReductions++; #endif return(true); } return(false); }
private static void Perft(BoardState boardState, int depth, AdvancedPerftResult result) { Span <Move> moves = stackalloc Move[SearchConstants.MaxMovesCount]; var movesCount = boardState.GetAllMoves(moves); if (depth <= 0) { result.Leafs++; return; } if (depth == 1) { UpdateResult(boardState, moves, movesCount, result); return; } for (var i = 0; i < movesCount; i++) { boardState.MakeMove(moves[i]); if (!boardState.IsKingChecked(ColorOperations.Invert(boardState.ColorToMove))) { Perft(boardState, depth - 1, result); } boardState.UndoMove(moves[i]); } }
private static ulong Perft(BoardState boardState, int depth, ref bool verificationSuccess) { if (!VerifyBoard(boardState)) { verificationSuccess = false; return(0); } if (depth <= 0) { return(1); } Span <Move> moves = stackalloc Move[SearchConstants.MaxMovesCount]; var movesCount = boardState.GetAllMoves(moves); ulong nodes = 0; for (var i = 0; i < movesCount; i++) { boardState.MakeNullMove(); boardState.UndoNullMove(); boardState.MakeMove(moves[i]); if (!boardState.IsKingChecked(ColorOperations.Invert(boardState.ColorToMove))) { nodes += Perft(boardState, depth - 1, ref verificationSuccess); } boardState.UndoMove(moves[i]); } return(nodes); }
public static int GetQuietMoves(BoardState boardState, Span <Move> moves, int offset, ulong evasionMask) { var color = boardState.ColorToMove; var enemyColor = ColorOperations.Invert(color); var knights = boardState.Pieces[color][Piece.Knight]; while (knights != 0) { var piece = BitOperations.GetLsb(knights); knights = BitOperations.PopLsb(knights); var from = BitOperations.BitScan(piece); var availableMoves = KnightMovesGenerator.GetMoves(from) & ~boardState.OccupancySummary; availableMoves &= evasionMask; while (availableMoves != 0) { var field = BitOperations.GetLsb(availableMoves); var fieldIndex = BitOperations.BitScan(field); availableMoves = BitOperations.PopLsb(availableMoves); moves[offset++] = new Move(from, fieldIndex, MoveFlags.Quiet); } } return(offset); }
public static int GetAvailableCaptureMoves(BoardState boardState, Span <Move> moves, int offset) { var color = boardState.ColorToMove; var enemyColor = ColorOperations.Invert(color); var rooks = boardState.Pieces[color][Piece.Rook]; while (rooks != 0) { var piece = BitOperations.GetLsb(rooks); rooks = BitOperations.PopLsb(rooks); var from = BitOperations.BitScan(piece); var availableMoves = RookMovesGenerator.GetMoves(boardState.OccupancySummary, from) & boardState.Occupancy[enemyColor]; while (availableMoves != 0) { var field = BitOperations.GetLsb(availableMoves); var fieldIndex = BitOperations.BitScan(field); availableMoves = BitOperations.PopLsb(availableMoves); moves[offset++] = new Move(from, fieldIndex, MoveFlags.Capture); } } return(offset); }
private Color GetTolerance(Point point, Color expected) { // pixelCenter is factored into this point int x = (int)Math.Floor(point.X - Const.pixelCenterX); int y = (int)Math.Floor(point.Y - Const.pixelCenterY); Color missingPixelTolerance = ColorOperations.ColorFromArgb(0, 0, 0, 0); Color lookupTolerance = ColorOperations.ColorFromArgb(0, 0, 0, 0); for (int j = y; j < y + 2; j++) { for (int i = x; i < x + 2; i++) { Color?current = SafeGetPixel(i, j); if (current.HasValue) { // Keep the max of the diff tolerance and the existing tolerance Color diff = ColorOperations.AbsoluteDifference(current.Value, expected); lookupTolerance = ColorOperations.Max(lookupTolerance, diff); lookupTolerance = ColorOperations.Max(lookupTolerance, toleranceBuffer[i, j]); } else { // increase tolerance by 25% since this pixel's value is unknown missingPixelTolerance = ColorOperations.Add(missingPixelTolerance, ColorOperations.ColorFromArgb(.25, .25, .25, .25)); } } } return(ColorOperations.Add(lookupTolerance, missingPixelTolerance)); }
/// <summary> /// Adds the value in tolerance to the tolerance buffer at [x,y] /// </summary> /// <param name="x">x index</param> /// <param name="y">y index</param> /// <param name="tolerance">New tolerance value that will be added</param> public void AddToTolerance(int x, int y, Color tolerance) { if (x >= 0 && x < width && y >= 0 && y < height) { toleranceBuffer[x, y] = ColorOperations.Add(tolerance, toleranceBuffer[x, y]); } }
/// <summary> /// Apply a 2D transform to the RenderBuffer /// </summary> public void ApplyTransform(Transform transform) { if (transform == null || transform.Value == Matrix.Identity) { return; } RenderBuffer clone = Clone(); Matrix inverse = transform.Value; inverse.Invert(); inverse = MathEx.ConvertToAbsolutePixels(inverse); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { Point point = inverse.Transform(new Point(x + Const.pixelCenterX, y + Const.pixelCenterY)); Color?color = clone.GetPixel(point); if (color.HasValue) { frameBuffer[x, y] = color.Value; toleranceBuffer[x, y] = clone.GetTolerance(point, frameBuffer[x, y]); } else { // Transformed outside of the RenderBuffer frameBuffer[x, y] = ColorOperations.ColorFromArgb(0, 0, 0, 0); toleranceBuffer[x, y] = RenderTolerance.DefaultColorTolerance; } } } }
public bool IsFieldPassing(int color, int field) { var enemyColor = ColorOperations.Invert(color); var passingArea = PassingPatternGenerator.GetPattern(color, field); return((passingArea & Pieces[enemyColor][Piece.Pawn]) == 0); }
/// <summary> /// Checks if the specified bitboard is finished or not. /// </summary> /// <param name="bitboard">The bitboard to check.</param> private void CheckIfGameHasEnded(Bitboard bitboard) { var enemyColor = ColorOperations.Invert(_currentColor); if (Bitboard.IsStalemate(enemyColor)) { ConsoleManager.WriteLine("$gStalemate, wins!"); _done = true; return; } if (Bitboard.IsThreefoldRepetition()) { ConsoleManager.WriteLine("$gThreefold repetition!"); _done = true; return; } if (Bitboard.IsMate(enemyColor)) { ConsoleManager.WriteLine($"$gMate, {_currentColor} wins!"); _done = true; return; } }
/// <summary> /// Get only the points where issues were found /// If the captured image is smaller than the expected image, throw an exception and refuse to compare them. /// Otherwise, compare the expected image with the matching region (the upper left corner) of the rendered image. /// We'll do the comparison by x,y coordinates and not pointer math (ie: y*width +x) to ensure correct matching. /// </summary> /// <returns>Array of points where failures ocurred</returns> public static Point[] GetPointsWithFailures(Color[,] captured, RenderBuffer expected) { //we'll do the comparison by x,y coordinates and not pointer math (ie: y*width +x) to ensure correct matching. if (expected.Width > captured.GetLength(0) || expected.Height > captured.GetLength(1)) { throw new ApplicationException(exceptionCapturedRenderedEqual); } System.Collections.ArrayList failures = new System.Collections.ArrayList(); Point[] failPoints; for (int y = 0; y < expected.Height; y++) { for (int x = 0; x < expected.Width; x++) { if (!ColorOperations.AreWithinTolerance( captured[x, y], expected.FrameBuffer[x, y], expected.ToleranceBuffer[x, y])) { failures.Add(new Point(x, y)); } } } // Always return an array, even an empty one failPoints = new Point[failures.Count]; if (failures.Count != 0) { failures.CopyTo(failPoints); } return(failPoints); }
public static Color WeightedSum(Color c1, Color c2, Color c3, Weights weights) { double a, r, g, b; a = WeightedSum(ColorOperations.ByteToDouble(c1.A), ColorOperations.ByteToDouble(c2.A), ColorOperations.ByteToDouble(c3.A), weights); r = WeightedSum(ColorOperations.ByteToDouble(c1.R), ColorOperations.ByteToDouble(c2.R), ColorOperations.ByteToDouble(c3.R), weights); g = WeightedSum(ColorOperations.ByteToDouble(c1.G), ColorOperations.ByteToDouble(c2.G), ColorOperations.ByteToDouble(c3.G), weights); b = WeightedSum(ColorOperations.ByteToDouble(c1.B), ColorOperations.ByteToDouble(c2.B), ColorOperations.ByteToDouble(c3.B), weights); return(ColorOperations.ColorFromArgb(a, r, g, b)); }
/// <summary> /// Calculates the best possible move for the specified parameters. /// </summary> /// <param name="color">The initial player.</param> /// <param name="bitboard">The bitboard.</param> /// <param name="preferredTime">Time allocated for AI.</param> /// <returns>The result of AI calculating.</returns> public AIResult Calculate(Color color, Bitboard bitboard, float preferredTime) { var result = new AIResult(); var colorSign = ColorOperations.ToSign(color); var stopwatch = new Stopwatch(); int estimatedTimeForNextIteration; result.Color = color; result.PreferredTime = preferredTime; if (bitboard.ReversibleMoves == 0 && preferredTime != 0) { _transpositionTable.Clear(); } stopwatch.Start(); do { result.Depth++; var stats = new AIStats(); result.Score = colorSign * _regularSearch.Do(color, new Bitboard(bitboard), result.Depth, AIConstants.InitialAlphaValue, AIConstants.InitialBetaValue, stats); result.PVNodes = GetPVNodes(bitboard, color); result.Stats = stats; result.Ticks = stopwatch.Elapsed.Ticks; OnThinkingOutput?.Invoke(this, new ThinkingOutputEventArgs(result)); estimatedTimeForNextIteration = (int)stopwatch.Elapsed.TotalMilliseconds * result.Stats.BranchingFactor; }while (estimatedTimeForNextIteration < preferredTime * 1000 && result.Depth < 12 && Math.Abs(result.Score) != AIConstants.MateValue); return(result); }
private static int GetPrincipalVariation(BoardState board, Move[] moves, int movesCount) { var entry = TranspositionTable.Get(board.Hash); if (entry.Flags == TranspositionTableEntryFlags.ExactScore && entry.IsKeyValid(board.Hash) && movesCount < SearchConstants.MaxDepth) { if (!board.IsMoveLegal(entry.BestMove)) { return(movesCount); } moves[movesCount] = entry.BestMove; board.MakeMove(entry.BestMove); var enemyColor = ColorOperations.Invert(board.ColorToMove); var king = board.Pieces[enemyColor][Piece.King]; var kingField = BitOperations.BitScan(king); if (board.IsFieldAttacked(enemyColor, (byte)kingField)) { board.UndoMove(entry.BestMove); return(movesCount); } movesCount = GetPrincipalVariation(board, moves, movesCount + 1); board.UndoMove(entry.BestMove); } return(movesCount); }
/// <summary> /// Does an AI move. /// </summary> private void MoveAI() { Task.Run(() => { var openingBookMove = _openingBook.GetMoveFromBook(_history); var enemyColor = ColorOperations.Invert(_currentColor); Move moveToApply = null; if (openingBookMove != null) { moveToApply = Bitboard.Moves.First(p => p.From == openingBookMove.From && p.To == openingBookMove.To); } else { var aiResult = _ai.Calculate(_currentColor, Bitboard, _preferredTime, _helperTasksCount); moveToApply = aiResult.PVNodes[0]; ConsoleManager.WriteLine(); ConsoleManager.WriteLine($"$w{_currentColor}:"); ConsoleManager.WriteLine($"$wBest move: $g{aiResult.PVNodes} $w(Score: $m{aiResult.Score}$w)"); ConsoleManager.WriteLine($"$wTotal nodes: $g{aiResult.Stats.TotalNodes} N $w(Depth: $m{aiResult.Depth}$w)"); ConsoleManager.WriteLine($"$wTime: $m{aiResult.Time} s"); ConsoleManager.WriteLine(); } CalculateBitboard(moveToApply, false); CheckIfGameHasEnded(Bitboard); _currentColor = enemyColor; _history.Add(moveToApply); }); }
public static int GetQuietMoves(BoardState boardState, Span <Move> moves, int offset) { var color = boardState.ColorToMove; var enemyColor = ColorOperations.Invert(color); var piece = boardState.Pieces[color][Piece.King]; if (piece == 0) { return(offset); } var from = BitOperations.BitScan(piece); var availableMoves = KingMovesGenerator.GetMoves(from) & ~boardState.OccupancySummary; while (availableMoves != 0) { var field = BitOperations.GetLsb(availableMoves); var fieldIndex = BitOperations.BitScan(field); availableMoves = BitOperations.PopLsb(availableMoves); moves[offset++] = new Move(from, fieldIndex, MoveFlags.Quiet); } return(offset); }
public HdrColor(Color color) { a = ColorOperations.ByteToDouble(color.A); r = ColorOperations.ByteToDouble(color.R); g = ColorOperations.ByteToDouble(color.G); b = ColorOperations.ByteToDouble(color.B); }
/// <summary> /// Calculates en passant move. /// </summary> /// <param name="bitboard">The bitboard.</param> public override void CalculateMove(Bitboard bitboard) { var from = BitPositionConverter.ToULong(From); var to = BitPositionConverter.ToULong(To); var enemyColor = ColorOperations.Invert(Color); RemoveEnPassantPiece(bitboard, enemyColor, to); CalculatePieceMove(bitboard, from, to); }
public int Do(Color color, Bitboard bitboard, int alpha, int beta, AIStats stats) { var enemyColor = ColorOperations.Invert(color); var colorSign = ColorOperations.ToSign(color); stats.QuiescenceTotalNodes++; var whiteGeneratorMode = GetGeneratorMode(color, Color.White); var blackGeneratorMode = GetGeneratorMode(color, Color.Black); bitboard.Calculate(whiteGeneratorMode, blackGeneratorMode, true); if (bitboard.IsCheck(enemyColor)) { stats.QuiescenceEndNodes++; return(AIConstants.MateValue); } var evaluation = colorSign * bitboard.GetEvaluation(); if (evaluation >= beta) { stats.QuiescenceEndNodes++; return(beta); } if (evaluation > alpha) { alpha = evaluation; } var sortedMoves = SortMoves(color, bitboard, bitboard.Moves); foreach (var move in sortedMoves) { var bitboardAfterMove = bitboard.Move(move); var nodeValue = -Do(enemyColor, bitboardAfterMove, -beta, -alpha, stats); if (nodeValue >= beta) { return(beta); } if (nodeValue > alpha) { alpha = nodeValue; } } if (!sortedMoves.Any()) { stats.QuiescenceEndNodes++; } return(alpha); }
public override Color IluminateDiffuse(Point3D modelPosition, Vector3D normal) { // Start with no additional error lastIlluminationError = emptyColor; double diffuseContribution = GetDiffuseContribution(normal, -direction); Color diffuseLightColor = ColorOperations.ScaleOpaque(lightColor, diffuseContribution); return(diffuseLightColor); }
/// <summary> /// Produce a Difference image from a screen capture and a RenderBuffer. For every pixel, if it is an exact match or /// if the difference is within the provided tolerance, the pixel is marked as black. Otherwise the diff value is used. /// If the captured image is smaller than the expected image, throw an exception and refuse to compare them. /// Otherwise, compare the expected image with the matching region (the upper left corner) of the rendered image. /// We'll do the comparison by x,y coordinates and not pointer math (ie: y*width +x) to ensure correct matching. /// </summary> /// <returns>A new Render buffer with the Diff image on the framebuffer and a color coded image on the tbuffer.</returns> public static RenderBuffer ComputeDifference(Color[,] captured, RenderBuffer expected) { if (expected.Width > captured.GetLength(0) || expected.Height > captured.GetLength(1)) { throw new ApplicationException(exceptionCapturedRenderedEqual); } RenderBuffer result = new RenderBuffer(expected.Width, expected.Height); // We want to write to this directly, set z-test to always write ... result.DepthTestFunction = DepthTestFunction.Always; // We want to ignore any potential z-tolerance as well ... for (int y = 0; y < result.Height; y++) { for (int x = 0; x < result.Width; x++) { // Ignore alpha differences. Color diff = ColorOperations.AbsoluteDifference(expected.FrameBuffer[x, y], captured[x, y]); diff.A = 0xff; result.FrameBuffer[x, y] = diff; // Make perfect matches black if (ColorOperations.AreWithinTolerance(captured[x, y], expected.FrameBuffer[x, y], Colors.Black)) { result.ToleranceBuffer[x, y] = Colors.Black; result.FrameBuffer[x, y] = Colors.Black; } // Treat within tolerance as separate case else if (ColorOperations.AreWithinTolerance(captured[x, y], expected.FrameBuffer[x, y], expected.ToleranceBuffer[x, y])) { result.ToleranceBuffer[x, y] = codedColor[0]; result.FrameBuffer[x, y] = Colors.Black; } // Otherwise do color coding else { for (int i = 1; i < codedColor.Length; i++) { if (ColorOperations.AreWithinTolerance( captured[x, y], expected.FrameBuffer[x, y], ColorOperations.Add(toleranceThreshold[i], expected.ToleranceBuffer[x, y]))) { result.ToleranceBuffer[x, y] = codedColor[i]; break; } } } } } return(result); }
public override Color IluminateSpecular(Point3D modelPosition, Vector3D normal, double specularPower) { // Start with no additional error lastIlluminationError = emptyColor; Vector3D view = Const.p0 - modelPosition; double specularContribution = GetSpecularContribution(view, normal, -direction, specularPower); Color specularLightColor = ColorOperations.ScaleOpaque(lightColor, specularContribution); return(specularLightColor); }
/// <summary> /// The event handler for OnThinkingOutput. /// </summary> /// <param name="sender">The event sender.</param> /// <param name="e">The event arguments.</param> private void GameSession_OnThinkingOutput(object sender, ThinkingOutputEventArgs e) { if (_thinkingOutputEnabled) { var depth = e.AIResult.Depth; var score = ColorOperations.ToSign(e.AIResult.Color) * e.AIResult.Score; var time = (int)(e.AIResult.Time * 100); var totalNodes = e.AIResult.Stats.TotalNodes; SendData($"{depth} {score} {time} {totalNodes} {e.AIResult.PVNodes}"); } }
/// <summary> /// Checks if king with the specified color is checked. /// </summary> /// <param name="color">The king color.</param> /// <returns>True if king with specified color is checked, otherwise false.</returns> public bool IsCheck(Color color) { if (!_calculated) { throw new BitboardNotCalculatedException(); } var enemyColor = ColorOperations.Invert(color); var king = Pieces[FastArray.GetPieceIndex(color, PieceType.King)]; return((AttacksSummary[(int)enemyColor] & king) != 0); }
/// <summary> /// Initializes a new instance of the <see cref="Bitboard"/> class. /// </summary> /// <param name="bitboard">The previous bitboard.</param> /// <param name="move">The move to apply.</param> public Bitboard(Bitboard bitboard, Move move) : this(bitboard) { IncrementalZobrist.ClearEnPassant(ColorOperations.Invert(move.Color), this); EnPassant[(int)ColorOperations.Invert(move.Color)] = 0; ReversibleMoves++; move.Do(this); CalculateGamePhase(); UpdateHistory(); }
private static TextureFilter RenderBrushToTextureFilter(SolidColorBrush brush) { // Account for Opacity Color color = brush.Color; color = ColorOperations.Blend( color, Color.FromArgb(0, color.R, color.G, color.B), Math.Max(Math.Min(brush.Opacity, 1.0), 0.0)); // We don't want to rely on RenderTargetBitmap for SolidColorBrush return(new SolidColorTextureFilter(color)); }
public void UndoNullMove() { NullMoves--; ColorToMove = ColorOperations.Invert(ColorToMove); Hash = _hashes.Pop(); EnPassant = _enPassants.Pop(); if (ColorToMove == Color.White) { MovesCount--; } }
/// <summary> /// Constructor that takes a background color. /// </summary> /// <param name="width">Buffer width, in pixels.</param> /// <param name="height">Buffer height, in pixels.</param> /// <param name="backgroundColor">Color for lowest blend layer. Must not be premultiplied.</param> public RenderBuffer(int width, int height, Color backgroundColor) : this(width, height) { Color background = ColorOperations.PreMultiplyColor(backgroundColor); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { frameBuffer[x, y] = background; } } }
public static int GetLoudMoves(BoardState boardState, Span <Move> moves, int offset) { var color = boardState.ColorToMove; var enemyColor = ColorOperations.Invert(color); var piece = boardState.Pieces[color][Piece.King]; if (piece == 0) { return(offset); } var from = BitOperations.BitScan(piece); var availableMoves = KingMovesGenerator.GetMoves(from) & boardState.Occupancy[enemyColor]; while (availableMoves != 0) { var field = BitOperations.GetLsb(availableMoves); var fieldIndex = BitOperations.BitScan(field); availableMoves = BitOperations.PopLsb(availableMoves); moves[offset++] = new Move(from, fieldIndex, MoveFlags.Capture); } if (color == Color.White) { if (IsWhiteKingCastlingAvailable(boardState, color)) { moves[offset++] = new Move(3, 1, MoveFlags.KingCastle); } if (IsWhiteQueenCastlingAvailable(boardState, color)) { moves[offset++] = new Move(3, 5, MoveFlags.QueenCastle); } } else { if (IsBlackKingCastlingAvailable(boardState, color)) { moves[offset++] = new Move(59, 57, MoveFlags.KingCastle); } if (IsBlackQueenCastlingAvailable(boardState, color)) { moves[offset++] = new Move(59, 61, MoveFlags.QueenCastle); } } return(offset); }