M src/attack.zig => src/attack.zig +54 -9
@@ 1,21 1,25 @@
pub usingnamespace @import("board.zig");
const mask_not_a = 0xfefefefefefefefe;
+const mask_not_ab = 0xfcfcfcfcfcfcfcfc;
const mask_not_h = 0x7f7f7f7f7f7f7f7f;
+const mask_not_gh = 0x3f3f3f3f3f3f3f3f;
const pawn_attacks = initPawnAttacks();
fn initPawnAttacks() [2][64]u64 {
- var sq: u6 = 0;
- var attacks: [2][64]u64 = undefined;
- while (sq < 63) : (sq += 1) {
- attacks[0][sq] = maskPawnAttacks(Side.White, @intToEnum(Square, sq));
+ comptime {
+ var sq: u8 = 0;
+ var attacks: [2][64]u64 = undefined;
+ while (sq < 64) : (sq += 1) {
+ attacks[0][sq] = maskPawnAttacks(Side.White, @intToEnum(Square, sq));
+ }
+ sq = 0;
+ while (sq < 64) : (sq += 1) {
+ attacks[1][sq] = maskPawnAttacks(Side.Black, @intToEnum(Square, sq));
+ }
+ return attacks;
}
- sq = 0;
- while (sq < 63) : (sq += 1) {
- attacks[1][sq] = maskPawnAttacks(Side.Black, @intToEnum(Square, sq));
- }
- return attacks;
}
fn maskPawnAttacks(side: Side, pawn: Square) u64 {
@@ 29,3 33,44 @@ fn maskPawnAttacks(side: Side, pawn: Square) u64 {
pub fn pawnAttacks(side: Side, pawn: Square) u64 {
return pawn_attacks[@enumToInt(side)][@enumToInt(pawn)];
}
+
+const knight_attacks = initKnightAttacks();
+
+fn initKnightAttacks() [64]u64 {
+ comptime {
+ var sq: u8 = 0;
+ var attacks: [64]u64 = undefined;
+ while (sq < 64) : (sq += 1) {
+ attacks[sq] = maskKnightAttacks(@intToEnum(Square, sq));
+ }
+ return attacks;
+ }
+}
+
+fn maskKnightAttacks(knight: Square) u64 {
+ const bitboard = bitboardFromSquare(knight);
+ // attacks considered clockwise
+ var attacks = bitboard >> 15 & mask_not_a;
+ attacks |= bitboard >> 6 & mask_not_ab;
+ attacks |= bitboard << 10 & mask_not_ab;
+ attacks |= bitboard << 17 & mask_not_a;
+ attacks |= bitboard << 15 & mask_not_h;
+ attacks |= bitboard << 6 & mask_not_gh;
+ attacks |= bitboard >> 10 & mask_not_gh;
+ attacks |= bitboard >> 17 & mask_not_h;
+ return attacks;
+}
+
+pub fn knightAttacks(knight: Square) u64 {
+ return knight_attacks[@enumToInt(knight)];
+}
+
+const king_attacks = initKingAttacks();
+
+fn initKingAttacks() [64]u64 {
+ return 0;
+}
+
+pub fn kingAttacks(king: Square) u64 {
+ return king_attacks[@enumToInt(king)];
+}
M src/main.zig => src/main.zig +17 -0
@@ 24,6 24,23 @@ fn uciLoop() !void {
}
}
+/// Helper function for getting the value of a specific bitboard.
+fn bitboardBuilder() void {
+ var bitboard: u64 = 0;
+ var rank: u6 = 0;
+ while (rank < 8) : (rank += 1) {
+ var file: u6 = 0;
+ while (file < 8) : (file += 1) {
+ const square = 8 * rank + file;
+ if (file != 6 and file != 7) {
+ bitboard |= @as(u64, 1) << square;
+ }
+ }
+ }
+ board.printBitboard(bitboard);
+}
+
pub fn main() !void {
//uciLoop();
+ //bitboardBuilder();
}
M test/attack.zig => test/attack.zig +34 -0
@@ 60,3 60,37 @@ test "black pawn on 1st rank attacks nothing" {
const actual = pawnAttacks(side, pawn);
expectEqual(expected, actual);
}
+
+test "knight in center attacks all 8 squares" {
+ const knight = Square.e4;
+ const expected_attacked_squares = [8]Square{
+ Square.f6,
+ Square.g5,
+ Square.g3,
+ Square.f2,
+ Square.d2,
+ Square.c3,
+ Square.c5,
+ Square.d6,
+ };
+ const expected = bitboardFromSquares(expected_attacked_squares[0..]);
+ const actual = knightAttacks(knight);
+ expectEqual(expected, actual);
+}
+
+test "knights in corners attack only 2 squares" {
+ const knight_a8 = Square.a8;
+ const knight_h8 = Square.h8;
+ const knight_h1 = Square.h1;
+ const knight_a1 = Square.a1;
+
+ const expected_a8 = [2]Square{ Square.c7, Square.b6 };
+ const expected_h8 = [2]Square{ Square.g6, Square.f7 };
+ const expected_h1 = [2]Square{ Square.f2, Square.g3 };
+ const expected_a1 = [2]Square{ Square.b3, Square.c2 };
+
+ expectEqual(bitboardFromSquares(expected_a8[0..]), knightAttacks(knight_a8));
+ expectEqual(bitboardFromSquares(expected_h8[0..]), knightAttacks(knight_h8));
+ expectEqual(bitboardFromSquares(expected_h1[0..]), knightAttacks(knight_h1));
+ expectEqual(bitboardFromSquares(expected_a1[0..]), knightAttacks(knight_a1));
+}