Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
kurt1288 committed Oct 2, 2024
2 parents 10b087b + 5ed84f6 commit 40586d4
Show file tree
Hide file tree
Showing 17 changed files with 1,058 additions and 471 deletions.
20 changes: 20 additions & 0 deletions Attacks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,26 @@ static ulong GenerateRookAttacks(int index, ulong occupied)
}
#endif

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong PawnAnyAttacks(ulong pawns, Color color)
{
return color == Color.White ?
((pawns >> 7) & ~FILE_MASKS[(int)File.A]) | ((pawns >> 9) & ~FILE_MASKS[(int)File.H])
: ((pawns << 7) & ~FILE_MASKS[(int)File.H]) | ((pawns << 9) & ~FILE_MASKS[(int)File.A]);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong WhitePawnAttacks(ulong pawns)
{
return ((pawns >> 7) & ~FILE_MASKS[(int)File.A]) | ((pawns >> 9) & ~FILE_MASKS[(int)File.H]);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong BlackPawnAttacks(ulong pawns)
{
return ((pawns << 7) & ~FILE_MASKS[(int)File.H]) | ((pawns << 9) & ~FILE_MASKS[(int)File.A]);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong GetBishopAttacks(int square, ulong occupied)
{
Expand Down
12 changes: 12 additions & 0 deletions Bitboard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ public int CountBits()
return BitOperations.PopCount(Value);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ulong RightShift()
{
return (Value & ~Constants.FILE_MASKS[(int)File.H]) << 1;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int LSB(ulong value)
{
return BitOperations.TrailingZeroCount(value);
}

public static Bitboard operator &(Bitboard a, ulong b) => new(a.Value & b);
public static Bitboard operator &(Bitboard a, Bitboard b) => new(a.Value & b.Value);
public static Bitboard operator |(Bitboard a, Bitboard b) => new(a.Value | b.Value);
Expand Down
182 changes: 166 additions & 16 deletions Board.cs
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,16 @@ public bool IsAttacked(int square, int color)
return false;
}

public ulong AttackersTo(int square, ulong occupied)
{
return (PawnAttacks[(int)Color.Black][square] & PieceBB[(int)PieceType.Pawn].Value & ColorBB[(int)Color.White].Value)
| (PawnAttacks[(int)Color.White][square] & PieceBB[(int)PieceType.Pawn].Value & ColorBB[(int)Color.Black].Value)
| (KnightAttacks[square] & PieceBB[(int)PieceType.Knight].Value)
| (GetBishopAttacks(square, occupied) & (PieceBB[(int)PieceType.Bishop].Value | PieceBB[(int)PieceType.Queen].Value))
| (GetRookAttacks(square, occupied) & (PieceBB[(int)PieceType.Rook].Value | PieceBB[(int)PieceType.Queen].Value))
| (KingAttacks[square] & PieceBB[(int)PieceType.King].Value);
}

// Determines if there is a draw by insufficient material
public bool IsDrawn()
{
Expand Down Expand Up @@ -667,52 +677,192 @@ public bool IsWon()
return false;
}

public bool MoveIsValid(Move move)
public bool IsPseudoLegal(Move move)
{
if (move == 0)
// Null move?
// No piece on the from square?
// Piece on the from square isn't the correct color?
if (move == 0 || Mailbox[move.From].Type == PieceType.Null || Mailbox[move.From].Color != SideToMove)
{
return false;
}

Piece piece = Mailbox[move.From];
int up = (piece.Color == Color.White) ? -8 : 8;

// there's no piece to move?
if (piece.Type == PieceType.Null)
// moving an opponent's piece?
// trying to capture a king
if (piece.Type == PieceType.Null || piece.Color != SideToMove || Mailbox[move.To].Type == PieceType.King)
{
return false;
}

// moving an opponent's piece?
if (piece.Color != SideToMove)
// trying to capture our own piece in a non-castle move?
if (Mailbox[move.To].Type != PieceType.Null && Mailbox[move.To].Color == SideToMove && !move.IsCastle())
{
return false;
}

// capturing our own piece?
if (Mailbox[move.To].Color == SideToMove)
if (piece.Type == PieceType.Pawn)
{
return false;
if (move.Flag == MoveFlag.EPCapture && En_Passant != Square.Null && Mailbox[move.To - up].Type == PieceType.Pawn && Mailbox[move.To - up].Color != piece.Color)
{
return true;
}

// moving backwards
if (piece.Color == Color.White ? (move.To >> 3) > (move.From >> 3) : (move.To >> 3) < (move.From >> 3))
{
return false;
}

// move to backrank that isn't a promotion
if (!move.HasType(MoveType.Promotion) && (move.To >> 3) == (piece.Color == Color.White ? (int)Rank.Rank_1 : (int)Rank.Rank_8))
{
return false;
}

if (move.HasType(MoveType.Capture))
{
return Mailbox[move.To].Type != PieceType.Null && (PawnAttacks[(int)piece.Color][move.From] & SquareBB[move.To]) != 0;
}

// Non-captures should remain on the same file
if ((move.From & 7) != (move.To & 7))
{
return false;
}

// double push
if ((move.From ^ move.To) == 16)
{
// Can't double push from a non-starting rank
if (move.From >> 3 != (piece.Color == Color.White ? (int)Rank.Rank_7 : (int)Rank.Rank_2) || move.Flag != MoveFlag.DoublePawnPush)
{
return false;
}

return Mailbox[move.To].Type == PieceType.Null && Mailbox[move.To - up].Type == PieceType.Null;
}
// single push or attack
else
{
// Can't push a pawn more than 1 rank at this point
if (Math.Abs((move.From >> 3) - (move.To >> 3)) > 1)
{
return false;
}

return Mailbox[move.To].Type == PieceType.Null;
}
}

// sliding piece trying to slide through pieces?
if (piece.Type == PieceType.Bishop || piece.Type == PieceType.Rook || piece.Type == PieceType.Queen)
if (move.IsCastle())
{
if ((BetweenBB[move.From][move.To] & (ColorBB[(int)Color.White].Value | ColorBB[(int)Color.Black].Value)) != 0)
if (piece.Type != PieceType.King)
{
return false;
}

int homeRank = piece.Color == Color.White ? 7 : 0;

if (move.To >> 3 != homeRank || move.From >> 3 != homeRank)
{
return false;
}

if (move.Flag == MoveFlag.KingCastle)
{
// no castle square
if (piece.Color == Color.White ? (CastleSquares & SquareBB[(int)Square.H1]) == 0 : (CastleSquares & SquareBB[(int)Square.H8]) == 0)
{
return false;
}

ulong path = piece.Color == Color.White ? BetweenBB[move.From][(int)Square.H1] : BetweenBB[move.From][(int)Square.H8];

#if DEBUG
MoveList castleMoves = new();
MoveGen.GenerateCastling(castleMoves, this);
bool foundCastle = false;
for (int i = 0; i < castleMoves.Count; i++)
{
if (castleMoves[i] == move)
{
foundCastle = true;
}
}

Debug.Assert(foundCastle == ((path & (ColorBB[(int)Color.White].Value | ColorBB[(int)Color.Black].Value)) == 0));
#endif

// true if path between is empty, otherwise false
return (path & (ColorBB[(int)Color.White].Value | ColorBB[(int)Color.Black].Value)) == 0;
}
else
{
// no castle square
if (piece.Color == Color.White ? (CastleSquares & SquareBB[(int)Square.A1]) == 0 : (CastleSquares & SquareBB[(int)Square.A8]) == 0)
{
return false;
}

ulong path = piece.Color == Color.White ? BetweenBB[move.From][(int)Square.A1] : BetweenBB[move.From][(int)Square.A8];

#if DEBUG
MoveList castleMoves = new();
MoveGen.GenerateCastling(castleMoves, this);
bool foundCastle = false;
for (int i = 0; i < castleMoves.Count; i++)
{
if (castleMoves[i] == move)
{
foundCastle = true;
}
}

Debug.Assert(foundCastle == ((path & (ColorBB[(int)Color.White].Value | ColorBB[(int)Color.Black].Value)) == 0));
#endif

// true if path between is empty, otherwise false
return (path & (ColorBB[(int)Color.White].Value | ColorBB[(int)Color.Black].Value)) == 0;
}
}

MoveList moves = MoveGen.GenerateAll(this);
for (int i = 0; i < moves.Count; i++)
// At this point, pawn moves, quiet moves to an occupied space, and capture moves to an unoccupied space are all invalid
if (move.HasType(MoveType.Promotion) || move.Flag == MoveFlag.DoublePawnPush || move.Flag == MoveFlag.EPCapture
|| (move.Flag == MoveFlag.Quiet && Mailbox[move.To].Type != PieceType.Null)
|| (move.Flag == MoveFlag.Capture && Mailbox[move.To].Type == PieceType.Null))
{
if (moves[i] == move)
return false;
}

Bitboard moves = Mailbox[move.From].Type switch
{
PieceType.Knight => new(KnightAttacks[move.From]),
PieceType.Bishop => new(GetBishopAttacks(move.From, ColorBB[(int)Color.White].Value | ColorBB[(int)Color.Black].Value)),
PieceType.Rook => new(GetRookAttacks(move.From, ColorBB[(int)Color.White].Value | ColorBB[(int)Color.Black].Value)),
PieceType.Queen => new(GetQueenAttacks(move.From, ColorBB[(int)Color.White].Value | ColorBB[(int)Color.Black].Value)),
PieceType.King => new(KingAttacks[move.From]),
_ => throw new Exception($"Unable to get attacks for piece {Mailbox[move.From].Type}"),
};

#if DEBUG
MoveList moveGen = MoveGen.GenerateAll(this);
bool found = false;
for (int i = 0; i < moveGen.Count; i++)
{
if (moveGen[i] == move)
{
return true;
found = true;
}
}

return false;
Debug.Assert(found == ((moves.Value & SquareBB[move.To]) != 0));
#endif

return (moves.Value & SquareBB[move.To]) != 0;
}

private int VerifyPhase()
Expand Down
2 changes: 2 additions & 0 deletions Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public static class Constants

public readonly static int[][] LMR_Reductions = new int[MAX_PLY][];

public readonly static int[] SEE_VALUES = [100, 325, 350, 500, 1000, 0, 0];

public readonly static ImmutableArray<ulong> FILE_MASKS = ImmutableArray.Create<ulong>(
0x101010101010101,
0x202020202020202,
Expand Down
16 changes: 8 additions & 8 deletions Datagen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ private static void GeneratePositions(Board board, TimeManager timeManager, Tran
CancellationTokenSource cts = new(TimeSpan.FromMinutes(4)); // This should spend, at most, 4 minutes on a single game
timeManager.MaxDepth = 8;
SearchInfo info = new();
Search search = new(board, timeManager, table, info);
ThreadManager searchManager = new(1, ref table);

while (true)
{
Expand All @@ -183,7 +183,7 @@ private static void GeneratePositions(Board board, TimeManager timeManager, Tran

// Do a quick search of the position, and if the score is too large (for either side), discard the position entirely
timeManager.Restart();
search.Run();
searchManager.StartSearches(timeManager, board);
timeManager.Stop();

// Get a new position if this one is too lopsided
Expand All @@ -206,7 +206,7 @@ private static void GeneratePositions(Board board, TimeManager timeManager, Tran
}

timeManager.Restart();
search.Run();
searchManager.StartSearches(timeManager, board);
timeManager.Stop();
Move bestMove = info.GetBestMove();

Expand Down Expand Up @@ -251,11 +251,11 @@ private static void GeneratePositions(Board board, TimeManager timeManager, Tran
}

// Adjudicate draws
if ((board.Fullmoves > 40 && board.Halfmoves > 5 && (info.Score is >= -20 and <= 20)) || board.Halfmoves >= 100 || search.IsDraw())
{
positions.WDL = 0.5;
break;
}
//if ((board.Fullmoves > 40 && board.Halfmoves > 5 && (info.Score is >= -20 and <= 20)) || board.Halfmoves >= 100 || search.IsDraw())
//{
// positions.WDL = 0.5;
// break;
//}
}
}

Expand Down
Loading

0 comments on commit 40586d4

Please sign in to comment.