diff --git a/scripts/GetAttacks.py b/scripts/GetAttacks.py new file mode 100644 index 0000000..86f4112 --- /dev/null +++ b/scripts/GetAttacks.py @@ -0,0 +1,64 @@ +import chess + +# A diverse set of FEN positions for testing +fen_positions = [ + "8/8/8/8/8/8/8/8 w - - ", + "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", + "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1", + "rnbqkb1r/pp1p1pPp/8/2p1pP2/1P1P4/3P3P/P1P1P3/RNBQKBNR w KQkq e6 0 1", + "r2q1rk1/ppp2ppp/2n1bn2/2b1p3/3pP3/3P1NPP/PPP1NPB1/R1BQ1RK1 b - - 0 9 ", + "r3k2r/8/8/8/3pPp2/8/8/R3K1RR b KQkq e3 0 1", + "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1", + "8/7p/p5pb/4k3/P1pPn3/8/P5PP/1rB2RK1 b - d3 0 28", + "8/3K4/2p5/p2b2r1/5k2/8/8/1q6 b - - 1 67", + "rnbqkb1r/ppppp1pp/7n/4Pp2/8/8/PPPP1PPP/RNBQKBNR w KQkq f6 0 3", + "n1n5/PPPk4/8/8/8/8/4Kppp/5N1N b - - 0 1", + "r3k2r/p6p/8/B7/1pp1p3/3b4/P6P/R3K2R w KQkq - 0 1", + "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1", + "r6r/1b2k1bq/8/8/7B/8/8/R3K2R b KQ - 3 2", + "8/8/8/2k5/2pP4/8/B7/4K3 b - d3 0 3", + "r1bqkbnr/pppppppp/n7/8/8/P7/1PPPPPPP/RNBQKBNR w KQkq - 2 2", + "r3k2r/p1pp1pb1/bn2Qnp1/2qPN3/1p2P3/2N5/PPPBBPPP/R3K2R b KQkq - 3 2", + "2kr3r/p1ppqpb1/bn2Qnp1/3PN3/1p2P3/2N5/PPPBBPPP/R3K2R b KQ - 3 2", + "rnb2k1r/pp1Pbppp/2p5/q7/2B5/8/PPPQNnPP/RNB1K2R w KQ - 3 9", +] + + +def to_zig_hex(bb: int) -> str: + """Converts a python-chess bitboard (big-endian) to a little-endian hex string for Zig.""" + raw_be = bb.to_bytes(8, byteorder="big") + raw_le = raw_be[::-1] + zig_int = int.from_bytes(raw_le, byteorder="big") + return f"0x{zig_int:016x}" + + +white_attacks_bb_arr = [] +black_attacks_bb_arr = [] + +for fen in fen_positions: + board = chess.Board(fen) + print(f"FEN: {fen}") + print(board) + + white_attacks_bb = 0 + black_attacks_bb = 0 + + # Iterate over all 64 squares to build the attack maps + for sq in chess.SQUARES: + # Check if the square is attacked by white + if board.is_attacked_by(chess.WHITE, sq): + white_attacks_bb |= 1 << sq + + # Check if the square is attacked by black + if board.is_attacked_by(chess.BLACK, sq): + black_attacks_bb |= 1 << sq + + white_attacks_bb_arr.append(white_attacks_bb) + black_attacks_bb_arr.append(black_attacks_bb) + + print(f"White Attacks: {to_zig_hex(white_attacks_bb)}") + print(f"Black Attacks: {to_zig_hex(black_attacks_bb)}") + print("-" * 40) + +print(f"White Attacks list: {white_attacks_bb_arr} \n") +print(f"Black Attacks list: {black_attacks_bb_arr} \n") diff --git a/src/attacks.zig b/src/attacks.zig index d8e04a2..9c23189 100644 --- a/src/attacks.zig +++ b/src/attacks.zig @@ -1,9 +1,10 @@ +const print = std.debug.print; const types = @import("types.zig"); const std = @import("std"); -const print = std.debug.print; const tabele = @import("tabeles.zig"); const util = @import("util.zig"); const bitboard = @import("bitboard.zig"); + // generate knight attacks tabele pub inline fn knight_attacks_from_bitboard(bb: types.Bitboard) types.Bitboard { return (((bb << 17) & ~@intFromEnum(types.MaskFile.AFILE)) | @@ -40,25 +41,21 @@ pub var pawn_attacks: [2][64]u64 = undefined; pub var pseudo_legal_attacks: [6][64]u64 = undefined; pub fn initialise_pseudo_legal() void { - // copy pawn-attack tables directly pawn_attacks[0] = tabele.White_pawn_attacks_tabele; pawn_attacks[1] = tabele.Black_pawn_attacks_tabele; - // copy fixed knight & king tables const knight_i = @intFromEnum(types.PieceType.Knight); const king_i = @intFromEnum(types.PieceType.King); pseudo_legal_attacks[knight_i] = tabele.Knight_attackes_tabele; pseudo_legal_attacks[king_i] = tabele.King_attackes_tabele; - // build rook, bishop, queen on empty board const rook_i = @intFromEnum(types.PieceType.Rook); const bishop_i = @intFromEnum(types.PieceType.Bishop); const queen_i = @intFromEnum(types.PieceType.Queen); - // single pass over all 64 squares for (types.square_number) |s| { const sq: u8 = @intCast(s); - const occ = 0; // empty occupancy + const occ = 0; // sliding attacks const r_att = get_rook_attacks_for_init(sq, occ); @@ -70,7 +67,6 @@ pub fn initialise_pseudo_legal() void { } } -/// Returns the pawn-attack mask for square `s` (0..63) and color `c` pub inline fn pawn_attacks_from_square(s: usize, c: types.Color) u64 { return pawn_attacks[@intFromEnum(c)][s]; } @@ -203,7 +199,10 @@ pub inline fn init_rook_attackes() void { var idx64: u64 = @as(u64, subset) *% magic; idx64 = idx64 >> shift; const idx: usize = @intCast(idx64); - Rook_attacks[square][idx] = get_rook_attacks_for_init(sq6, subset); + Rook_attacks[square][idx] = get_rook_attacks_for_init( + sq6, + subset, + ); if (subset == 0) break; subset = (subset - 1) & mask; } @@ -216,21 +215,64 @@ pub inline fn get_rook_attacks(square: u6, occ: u64) u64 { const shift: u6 = @intCast(64 - tabele.Rook_index_bit[square]); const relevant: u64 = occ & mask; const idx: usize = @intCast((relevant *% magic) >> shift); + return Rook_attacks[square][idx]; } -pub inline fn get_bishop_attacks_for_init(square: u8, occ: u64) u64 { - const rank_i8: i8 = @intCast(square / 8); - const file_i8: i8 = @intCast(square % 8); - const diag_i: i8 = rank_i8 - file_i8 + 7; - const anti_i: i8 = rank_i8 + file_i8; - const diag_idx: usize = @intCast(diag_i); - const anti_idx: usize = @intCast(anti_i); - const mask1: u64 = types.mask_diagonal_nw_se[diag_idx]; - const mask2: u64 = types.mask_anti_diagonal_ne_sw[anti_idx]; - const att1 = sliding_attacks(square, occ, mask1); - const att2 = sliding_attacks(square, occ, mask2); - return att1 | att2; +// Correct on-the-fly attack generation for bishops using simple ray-casting. +// This is a one-time cost at initialization. +pub fn get_bishop_attacks_for_init(square: u8, blockers: u64) u64 { + var attacks: u64 = 0; + const r: i8 = @intCast(square / 8); + const f: i8 = @intCast(square % 8); + const one: u64 = 1; + + // North-East + var cr = r + 1; + var cf = f + 1; + while (cr <= 7 and cf <= 7) : ({ + cr += 1; + cf += 1; + }) { + const s = cr * 8 + cf; + attacks |= (one << @intCast(s)); + if ((blockers & (one << @intCast(s))) != 0) break; + } + // South-West + cr = r - 1; + cf = f - 1; + while (cr >= 0 and cf >= 0) : ({ + cr -= 1; + cf -= 1; + }) { + const s = cr * 8 + cf; + attacks |= (one << @intCast(s)); + if ((blockers & (one << @intCast(s))) != 0) break; + } + // North-West + cr = r + 1; + cf = f - 1; + while (cr <= 7 and cf >= 0) : ({ + cr += 1; + cf -= 1; + }) { + const s = cr * 8 + cf; + attacks |= (one << @intCast(s)); + if ((blockers & (one << @intCast(s))) != 0) break; + } + // South-East + cr = r - 1; + cf = f + 1; + while (cr >= 0 and cf <= 7) : ({ + cr -= 1; + cf += 1; + }) { + const s = cr * 8 + cf; + attacks |= (one << @intCast(s)); + if ((blockers & (one << @intCast(s))) != 0) break; + } + + return attacks; } // bishop magice Bitboards @@ -241,16 +283,41 @@ pub inline fn init_bishop_attackes() void { const mask = tabele.Bishops_attackes_tabele[square]; const relevantBits = tabele.Bishop_index_bit[square]; const magic = tabele.bishop_magics[square]; - const shift: u6 = @truncate(64 - relevantBits); const sq6 = @as(u8, @intCast(square)); - var subset: types.Bitboard = mask; + // Clear the table for this square first + const table_size = @as(usize, 1) << @intCast(relevantBits); + @memset(Bishop_attacks[square][0..table_size], 0); + + var subset: types.Bitboard = mask; while (true) { var idx64: u64 = @as(u64, subset) *% magic; idx64 = idx64 >> shift; const idx: usize = @intCast(idx64); - Bishop_attacks[square][idx] = get_bishop_attacks_for_init(sq6, subset); + + const correct_attacks = get_bishop_attacks_for_init( + sq6, + subset, + ); + + // Check for collision + if (Bishop_attacks[square][idx] != 0 and + Bishop_attacks[square][idx] != correct_attacks) + { + std.debug.panic( + "Magic collision detected for bishop square {} at index {}: existing=0x{x}, new=0x{x}\n", + .{ + square, + idx, + Bishop_attacks[square][idx], + correct_attacks, + }, + ); + } + + Bishop_attacks[square][idx] = correct_attacks; + if (subset == 0) break; subset = (subset - 1) & mask; } @@ -262,23 +329,27 @@ pub inline fn get_bishop_attacks(square: u6, occ: u64) u64 { const magic: u64 = tabele.bishop_magics[square]; const shift: u6 = @intCast(64 - tabele.Bishop_index_bit[square]); const relevant: u64 = occ & mask; - const raw_idx: u64 = (relevant *% magic) >> shift; - const idx: usize = @intCast(raw_idx); + const idx: usize = @intCast((relevant *% magic) >> shift); return Bishop_attacks[square][idx]; } pub inline fn get_queen_attacks(square: u6, occ: u64) u64 { - const queen_attacks: u64 = get_bishop_attacks(square, occ) | get_rook_attacks(square, occ); + const queen_attacks: u64 = get_bishop_attacks(square, occ) | + get_rook_attacks(square, occ); return queen_attacks; } -pub fn piece_attacks(square: u6, occ: u64, comptime Piece: types.PieceType) void { +pub fn piece_attacks( + square: u6, + occ: u64, + comptime Piece: types.PieceType, +) types.Bitboard { if (Piece != types.PieceType.Pawn) { return switch (Piece) { types.PieceType.Bishop => get_bishop_attacks(square, occ), types.PieceType.Rook => get_rook_attacks(square, occ), types.PieceType.Queen => get_queen_attacks(square, occ), - else => print("pseudo legal attacks", .{}), + else => (&pseudo_legal_attacks)[Piece.toU3()][square], }; } else { @panic("don't pass pawns"); diff --git a/src/bitboard.zig b/src/bitboard.zig index 906c46f..d66c9a7 100644 --- a/src/bitboard.zig +++ b/src/bitboard.zig @@ -2,6 +2,7 @@ const std = @import("std"); const util = @import("util.zig"); const types = @import("types.zig"); const attacks = @import("attacks.zig"); +const tables = @import("tabeles.zig"); const print = std.debug.print; pub fn print_board(bitboard: types.Bitboard) void { @@ -56,15 +57,7 @@ pub fn print_unicode_board(board: types.Board) void { print(" Bitboard: 0x{0x}\n", .{board.pieces_combined()}); print(" Bitboard: 0b{b}\n\n", .{board.pieces_combined()}); } -// TODO fix bug on the whitte side -// 8 . . . . . . . . -// 7 . . . . . . . X -// 6 . . . . . . X . -// 5 . . . . . X . . -// 4 . . . . . . . . -// 3 X X X X X X X X -// 2 X X X X X X X X -// 1 . X X X X X X . + pub fn print_attacked_squares(board: *types.Board) void { const occ = board.pieces_combined(); const bbs = board.pieces; @@ -76,21 +69,20 @@ pub fn print_attacked_squares(board: *types.Board) void { print(" {} ", .{8 - rank}); for (0..8) |file| { const square: u6 = @intCast(rank * 8 + file); - const sq_bb = types.squar_bb[square]; const attacked = switch (side) { - .White => (attacks.pawn_attacks_from_bitboard(.White, sq_bb) & bbs[@intFromEnum(types.Piece.WHITE_PAWN)]) != 0 or - (attacks.knight_attacks_from_bitboard(sq_bb) & bbs[@intFromEnum(types.Piece.WHITE_KNIGHT)]) != 0 or - (attacks.get_bishop_attacks(square, occ) & bbs[@intFromEnum(types.Piece.WHITE_BISHOP)]) != 0 or - (attacks.get_rook_attacks(square, occ) & bbs[@intFromEnum(types.Piece.WHITE_ROOK)]) != 0 or + .White => (attacks.pawn_attacks_from_square(square, .Black) & bbs[@intFromEnum(types.Piece.WHITE_PAWN)]) != 0 or + (attacks.piece_attacks(square, occ, types.PieceType.Knight) & bbs[@intFromEnum(types.Piece.WHITE_KNIGHT)]) != 0 or + (attacks.piece_attacks(square, occ, types.PieceType.Bishop) & bbs[@intFromEnum(types.Piece.WHITE_BISHOP)]) != 0 or + (attacks.piece_attacks(square, occ, types.PieceType.Rook) & bbs[@intFromEnum(types.Piece.WHITE_ROOK)]) != 0 or (attacks.get_queen_attacks(square, occ) & bbs[@intFromEnum(types.Piece.WHITE_QUEEN)]) != 0 or - (attacks.king_attacks_from_bitboard(sq_bb) & bbs[@intFromEnum(types.Piece.WHITE_KING)]) != 0, + (attacks.piece_attacks(square, occ, types.PieceType.King) & bbs[@intFromEnum(types.Piece.WHITE_KING)]) != 0, - .Black => (attacks.pawn_attacks_from_bitboard(.Black, sq_bb) & bbs[@intFromEnum(types.Piece.BLACK_PAWN)]) != 0 or - (attacks.knight_attacks_from_bitboard(sq_bb) & bbs[@intFromEnum(types.Piece.BLACK_KNIGHT)]) != 0 or - (attacks.get_bishop_attacks(square, occ) & bbs[@intFromEnum(types.Piece.BLACK_BISHOP)]) != 0 or - (attacks.get_rook_attacks(square, occ) & bbs[@intFromEnum(types.Piece.BLACK_ROOK)]) != 0 or + .Black => (attacks.pawn_attacks_from_square(square, .White) & bbs[@intFromEnum(types.Piece.BLACK_PAWN)]) != 0 or + (attacks.piece_attacks(square, occ, types.PieceType.Knight) & bbs[@intFromEnum(types.Piece.BLACK_KNIGHT)]) != 0 or + (attacks.piece_attacks(square, occ, types.PieceType.Bishop) & bbs[@intFromEnum(types.Piece.BLACK_BISHOP)]) != 0 or + (attacks.piece_attacks(square, occ, types.PieceType.Rook) & bbs[@intFromEnum(types.Piece.BLACK_ROOK)]) != 0 or (attacks.get_queen_attacks(square, occ) & bbs[@intFromEnum(types.Piece.BLACK_QUEEN)]) != 0 or - (attacks.king_attacks_from_bitboard(sq_bb) & bbs[@intFromEnum(types.Piece.BLACK_KING)]) != 0, + (attacks.piece_attacks(square, occ, types.PieceType.King) & bbs[@intFromEnum(types.Piece.BLACK_KING)]) != 0, else => unreachable, }; @@ -103,6 +95,80 @@ pub fn print_attacked_squares(board: *types.Board) void { print("\n a b c d e f g h\n", .{}); } +pub fn is_square_attacked( + board: *const types.Board, + square: u6, + by_side: types.Color, +) bool { + const occ = board.pieces_combined(); + const bbs = board.pieces; + + return switch (by_side) { + .White => { + // Pawns (reverse attack to find attacker) + if ((attacks.pawn_attacks_from_square(square, .Black) & + bbs[@intFromEnum(types.Piece.WHITE_PAWN)]) != 0) return true; + // Knights + if ((attacks.piece_attacks(square, occ, .Knight) & + bbs[@intFromEnum(types.Piece.WHITE_KNIGHT)]) != 0) return true; + // King + if ((attacks.piece_attacks(square, occ, .King) & + bbs[@intFromEnum(types.Piece.WHITE_KING)]) != 0) return true; + // Bishops & Queens (diagonal) + if ((attacks.piece_attacks(square, occ, .Bishop) & + (bbs[@intFromEnum(types.Piece.WHITE_BISHOP)] | + bbs[@intFromEnum(types.Piece.WHITE_QUEEN)])) != 0) return true; + // Rooks & Queens (orthogonal) + if ((attacks.piece_attacks(square, occ, .Rook) & + (bbs[@intFromEnum(types.Piece.WHITE_ROOK)] | + bbs[@intFromEnum(types.Piece.WHITE_QUEEN)])) != 0) return true; + + return false; + }, + .Black => { + // Pawns (reverse attack to find attacker) + if ((attacks.pawn_attacks_from_square(square, .White) & + bbs[@intFromEnum(types.Piece.BLACK_PAWN)]) != 0) return true; + // Knights + if ((attacks.piece_attacks(square, occ, .Knight) & + bbs[@intFromEnum(types.Piece.BLACK_KNIGHT)]) != 0) return true; + // King + if ((attacks.piece_attacks(square, occ, .King) & + bbs[@intFromEnum(types.Piece.BLACK_KING)]) != 0) return true; + // Bishops & Queens (diagonal) + if ((attacks.piece_attacks(square, occ, .Bishop) & + (bbs[@intFromEnum(types.Piece.BLACK_BISHOP)] | + bbs[@intFromEnum(types.Piece.BLACK_QUEEN)])) != 0) return true; + // Rooks & Queens (orthogonal) + if ((attacks.piece_attacks(square, occ, .Rook) & + (bbs[@intFromEnum(types.Piece.BLACK_ROOK)] | + bbs[@intFromEnum(types.Piece.BLACK_QUEEN)])) != 0) return true; + + return false; + }, + .both => unreachable, + }; +} + +// This function is now much cleaner and uses the new is_square_attacked function. +pub fn print_attacked_squares_new(board: *types.Board) void { + print("\n", .{}); + print("--- Attacked squares for side: {} ---\n", .{board.side}); + + for (0..8) |rank| { + print(" {} ", .{8 - rank}); + for (0..8) |file| { + const square: u6 = @intCast(rank * 8 + file); + const attacked = is_square_attacked(board, square, board.side); + const ch: u8 = if (attacked) 'X' else '.'; + print(" {c} ", .{ch}); + } + print("\n", .{}); + } + + print("\n a b c d e f g h\n", .{}); +} + pub const FenError = error{ InvalidFormat, InvalidPosition, diff --git a/src/main.zig b/src/main.zig index 63d6328..55859cc 100644 --- a/src/main.zig +++ b/src/main.zig @@ -10,15 +10,12 @@ pub fn main() !void { attacks.init_attacks(); var b = types.Board.new(); - //try bitboard.fan_pars(types.start_position, &b); + try bitboard.fan_pars(types.start_position, &b); - //const bb = b.pieces_combined(); - //print("Occupancy (hex): 0x{x}\n", .{bb}); + const bb = b.pieces_combined(); + print("Occupancy (hex): 0x{x}\n", .{bb}); - const mybb = b.set_pieces(types.Color.White); - bitboard.print_board(mybb); - bitboard.print_unicode_board(b); b.side = types.Color.White; - bitboard.print_attacked_squares(&b); + bitboard.print_attacked_squares_new(&b); } diff --git a/src/move_generation.zig b/src/move_generation.zig index 0237d69..ec35dea 100644 --- a/src/move_generation.zig +++ b/src/move_generation.zig @@ -15,5 +15,9 @@ pub const Move = struct { }; pub fn generate_moves(list: *lists.MoveList) void { + const us = types.Board.side; // side to move + const them = if (types.Board.side == .white) .black else .white; + _ = us; + _ = them; _ = list; } diff --git a/src/test.zig b/src/test.zig index 7d4aa33..45ed7bc 100644 --- a/src/test.zig +++ b/src/test.zig @@ -375,3 +375,55 @@ test "test fen parsing" { ); } } + +test "is square attacked" { + attacks.init_attacks(); + + const AttackTestVector = struct { + fen: []const u8, + white_attacks: u64, + black_attacks: u64, + }; + + const test_vectors = [_]AttackTestVector{ + .{ .fen = "8/8/8/8/8/8/8/8 w - - ", .white_attacks = 0x0000000000000000, .black_attacks = 0x0000000000000000 }, + .{ .fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", .white_attacks = 9151313343305220096, .black_attacks = 16777086 }, + }; + + for (test_vectors) |vector| { + var board = types.Board.new(); + try bitboard.fan_pars(vector.fen, &board); + + var generated_white_attacks: u64 = 0; + var generated_black_attacks: u64 = 0; + + for (0..64) |sq_idx| { + const sq: u6 = @intCast(sq_idx); + if (bitboard.is_square_attacked(&board, sq, .White)) { + generated_white_attacks |= (@as(u64, 1) << sq); + } + if (bitboard.is_square_attacked(&board, sq, .Black)) { + generated_black_attacks |= (@as(u64, 1) << sq); + } + } + + // Use if-statements to provide more context on failure + if (vector.white_attacks != generated_white_attacks) { + std.debug.print("\n\nWhite attack mismatch for FEN: {s}\n", .{vector.fen}); + std.debug.print("Expected: 0x{x}\n", .{vector.white_attacks}); + bitboard.print_board(vector.white_attacks); + std.debug.print("Got: 0x{x}\n", .{generated_white_attacks}); + bitboard.print_board(generated_white_attacks); + } + try std.testing.expectEqual(vector.white_attacks, generated_white_attacks); + + if (vector.black_attacks != generated_black_attacks) { + std.debug.print("\n\nBlack attack mismatch for FEN: {s}\n", .{vector.fen}); + std.debug.print("Expected: 0x{x}\n", .{vector.black_attacks}); + bitboard.print_board(vector.black_attacks); + std.debug.print("Got: 0x{x}\n", .{generated_black_attacks}); + bitboard.print_board(generated_black_attacks); + } + try std.testing.expectEqual(vector.black_attacks, generated_black_attacks); + } +} diff --git a/src/types.zig b/src/types.zig index efe0cc3..9bb3866 100644 --- a/src/types.zig +++ b/src/types.zig @@ -74,6 +74,10 @@ pub const PieceType = enum(u8) { Rook, Queen, King, + + pub inline fn toU3(self: PieceType) u3 { + return @intFromEnum(self); + } }; pub const Piece = enum(u8) { @@ -111,16 +115,16 @@ pub const MoveFlags = enum(u4) { CAPTURE = 0b1000, // 8 CAPTURES = 0b1011, // 11 EN_PASSANT = 0b1010, // 10 - + // Promotions (no capture) PR_KNIGHT = 0b0100, // 4 PR_BISHOP = 0b0101, // 5 - PR_ROOK = 0b0110, // 6 - PR_QUEEN = 0b0111, // 7 + PR_ROOK = 0b0110, // 6 + PR_QUEEN = 0b0111, // 7 PC_KNIGHT = 0b1100, // 12 PC_BISHOP = 0b1101, // 13 - PC_ROOK = 0b1110, // 14 - PC_QUEEN = 0b1111, // 15 + PC_ROOK = 0b1110, // 14 + PC_QUEEN = 0b1111, // 15 }; pub const Castle = enum(u8) { @@ -137,7 +141,7 @@ pub const Board = struct { side: Color, enpassant: square, castle: u8, // bitmask of Castle.* - + pub fn pieces_combined(self: *const Board) Bitboard { var bb: Bitboard = 0; for (self.pieces) |p| bb |= p; @@ -147,30 +151,28 @@ pub const Board = struct { pub fn new() Board { var b: Board = undefined; - @memset(b.pieces[0..],0); + @memset(b.pieces[0..], 0); b.side = Color.White; b.enpassant = square.NO_SQUARE; b.castle = 0; - return b; + return b; } - pub inline fn set_pieces(self: *Board, comptime c: Color) Bitboard{ + pub inline fn set_pieces(self: *Board, comptime c: Color) Bitboard { return if (c == Color.White) self.pieces[Piece.WHITE_PAWN.toU4()] * 8 | self.pieces[Piece.WHITE_KNIGHT.toU4()] | self.pieces[Piece.WHITE_BISHOP.toU4()] | self.pieces[Piece.WHITE_QUEEN.toU4()] | self.pieces[Piece.WHITE_KING.toU4()] else - self.pieces[Piece.BLACK_PAWN.toU4()] * 8 | self.pieces[Piece.BLACK_KNIGHT.toU4()] | self.pieces[Piece.BLACK_BISHOP.toU4()] | self.pieces[Piece.BLACK_QUEEN.toU4()] | self.pieces[Piece.BLACK_KING.toU4()]; - + self.pieces[Piece.BLACK_PAWN.toU4()] * 8 | self.pieces[Piece.BLACK_KNIGHT.toU4()] | self.pieces[Piece.BLACK_BISHOP.toU4()] | self.pieces[Piece.BLACK_QUEEN.toU4()] | self.pieces[Piece.BLACK_KING.toU4()]; } pub inline fn set_white(self: *Board) Bitboard { - return self.pieces[Piece.WHITE_PAWN.toU4()] * 8 | self.pieces[Piece.WHITE_KNIGHT.toU4()] | self.pieces[Piece.WHITE_BISHOP.toU4()] | self.pieces[Piece.WHITE_QUEEN.toU4()] | self.pieces[Piece.WHITE_KING.toU4()]; + return self.pieces[Piece.WHITE_PAWN.toU4()] * 8 | self.pieces[Piece.WHITE_KNIGHT.toU4()] | self.pieces[Piece.WHITE_BISHOP.toU4()] | self.pieces[Piece.WHITE_QUEEN.toU4()] | self.pieces[Piece.WHITE_KING.toU4()]; } pub inline fn set_black(self: *Board) Bitboard { - return self.pieces[Piece.BLACK_PAWN.toU4()] * 8 | self.pieces[Piece.BLACK_KNIGHT.toU4()] | self.pieces[Piece.BLACK_BISHOP.toU4()] | self.pieces[Piece.BLACK_QUEEN.toU4()] | self.pieces[Piece.BLACK_KING.toU4()]; + return self.pieces[Piece.BLACK_PAWN.toU4()] * 8 | self.pieces[Piece.BLACK_KNIGHT.toU4()] | self.pieces[Piece.BLACK_BISHOP.toU4()] | self.pieces[Piece.BLACK_QUEEN.toU4()] | self.pieces[Piece.BLACK_KING.toU4()]; } }; - // Attacking directions for the pieces pub const Direction = enum(i32) { North = 8,