~macaptain/lkdo-chess

21e5e0dc3de477df4b250673eb89c4e94aa00c2d — Michael Captain 7 months ago 0bf3bc6
Add knight attacks with tests
3 files changed, 105 insertions(+), 9 deletions(-)

M src/attack.zig
M src/main.zig
M test/attack.zig
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));
}