TDHJSFFSJZBEZFMDHPLRSVB6CIVJ7AWGGNIC3WUCADQLQSIQKXDAC }fn setOccupancy(index: usize, bits_in_mask: Chess.BoardType, attack_mask: Chess.BoardType) Chess.BoardType {var occupancy: Chess.BitBoard = .{};var attack: Chess.BitBoard = .{ .board = attack_mask };var count: u6 = 0;while (count < bits_in_mask) : (count += 1) {const square = @ctz(attack.board);attack.pop(@intToEnum(Chess.Square, square));if (index & @as(Chess.BoardType, 1) << count != 0) {occupancy.set(@intToEnum(Chess.Square, square));}}return occupancy.board;}test "occupancy bits" {const attack_mask = genSteps(.a1, .rook, .white);var occupancy: Chess.BitBoard = .{};occupancy.board = setOccupancy(4095, @popCount(attack_mask), attack_mask);var expected: Chess.BitBoard = .{};expected.setSlice(&[_]Chess.Square{ .a2, .a3, .a4, .a5, .a6, .a7, .b1, .c1, .d1, .e1, .f1, .g1 });try std.testing.expectEqual(expected, occupancy);}fn genRelevantOccupancy(piece: Chess.Pieces) [@typeInfo(Chess.Square).Enum.fields.len]u4 {var ret: [64]u4 = [_]u4{0} ** 64;for (std.enums.values(Chess.Square)) |square| {const count = @popCount(genSteps(square, piece, .white));ret[@enumToInt(square)] = @intCast(u4, count);}return ret;}test "genRelevantOccupancy" {{ // bishopconst bishop = genRelevantOccupancy(.bishop);// zig fmt: offconst expected = [64]u4{6, 5, 5, 5, 5, 5, 5, 6,5, 5, 5, 5, 5, 5, 5, 5,5, 5, 7, 7, 7, 7, 5, 5,5, 5, 7, 9, 9, 7, 5, 5,5, 5, 7, 9, 9, 7, 5, 5,5, 5, 7, 7, 7, 7, 5, 5,5, 5, 5, 5, 5, 5, 5, 5,6, 5, 5, 5, 5, 5, 5, 6,};// zig fmt: ontry std.testing.expectEqualSlices(u4, &expected, &bishop);}{ // rookconst rook = genRelevantOccupancy(.rook);// zig fmt: offconst expected = [64]u4{12, 11, 11, 11, 11, 11, 11, 12,11, 10, 10, 10, 10, 10, 10, 11,11, 10, 10, 10, 10, 10, 10, 11,11, 10, 10, 10, 10, 10, 10, 11,11, 10, 10, 10, 10, 10, 10, 11,11, 10, 10, 10, 10, 10, 10, 11,11, 10, 10, 10, 10, 10, 10, 11,12, 11, 11, 11, 11, 11, 11, 12,};// zig fmt: ontry std.testing.expectEqualSlices(u4, &expected, &rook);}
fn findMagicNumber(square: Chess.Square, relevant: u4, piece: Chess.Pieces) Chess.BoardType {// TODO: piece+square defines the relevant bits// TODO: this is for rooks, bishop needs lessvar occupancies: [4096]Chess.BoardType = undefined;var attacks: [4096]Chess.BoardType = undefined;var used: [4096]Chess.BoardType = undefined;// attack mask for a current piececonst attack_mask = genSteps(square, piece, .white);const occupancy_idx = @as(Chess.BoardType, 1) << relevant;var bb = Chess.BitBoard{};var idx: usize = 0;while (idx < occupancy_idx) : (idx += 1) {occupancies[idx] = setOccupancy(idx, relevant, attack_mask);bb.board = occupancies[idx]; // FIXME UGLYattacks[idx] = bb.riderBlocker(square, piece);}// test the generated numbervar loop: usize = 0;while (loop < 100_000_000) : (loop += 1) {const magic = randLowZero();// skip inappropriate numbers FIXME: uglyvar tmp1: Chess.BoardType = undefined;_ = @mulWithOverflow(Chess.BoardType, attack_mask, magic, &tmp1);if (@popCount(tmp1 & 0xFF00000000000000) < 6) continue;used = [_]Chess.BoardType{0} ** 4096;var index: usize = 0;var fail: bool = false;while (!fail and index < occupancy_idx) : (index += 1) {var tmp2: Chess.BoardType = undefined; // FIXME: ugly_ = @mulWithOverflow(Chess.BoardType, occupancies[index], magic, &tmp2);var magic_index: usize = @intCast(usize, tmp2 >> @intCast(u6, @as(u7, 64) - relevant));if (used[magic_index] == 0) {// magic index worksused[magic_index] = attacks[index];} else if (used[magic_index] != attacks[index]) {// magic index does not workfail = true;}}if (!fail) {return magic;}}unreachable;}fn randLowZero() u64 {return rand() & rand() & rand();}var random_state: u32 = 1804289383;fn rand32() u32 {var number = random_state;// XOR shift algorithmnumber ^= number << 13;number ^= number >> 17;number ^= number << 5;// update random number staterandom_state = number;// return random numberreturn number;}fn rand() u64 {const r1 = @intCast(u64, rand32()) & 0xFFFF;const r2 = @intCast(u64, rand32()) & 0xFFFF;const r3 = @intCast(u64, rand32()) & 0xFFFF;const r4 = @intCast(u64, rand32()) & 0xFFFF;return r1 | (r2 << 16) | (r3 << 32) | (r4 << 48);}test "MagicNumbers" {var bishop_magic: [64]Chess.BoardType = undefined;var rook_magic: [64]Chess.BoardType = undefined;for (std.enums.values(Chess.Square)) |square, idx| {bishop_magic[idx] = findMagicNumber(square,genRelevantOccupancy(.bishop)[square.int()],.bishop,);rook_magic[idx] = findMagicNumber(square,genRelevantOccupancy(.rook)[square.int()],.rook,);}// std.debug.print("{any}\n{any}\n", .{ bishop_magic, rook_magic });}
}}fn setOccupancy(index: usize, attack_mask: BoardType) BoardType {var occupancy: BitBoard = .{};var attack: BitBoard = .{ .board = attack_mask };var count: u6 = 0;while (count < @popCount(attack_mask)) : (count += 1) {const square = @ctz(attack.board);attack.pop(@intToEnum(Square, square));if (index & @as(BoardType, 1) << count != 0) {occupancy.set(@intToEnum(Square, square));}}return occupancy.board;}test "occupancy bits" {const attack_mask = Attacks.genSteps(.a1, .rook, .white);var occupancy: BitBoard = .{};occupancy.board = setOccupancy(4095, attack_mask);var expected: BitBoard = .{};expected.setSlice(&[_]Square{ .a2, .a3, .a4, .a5, .a6, .a7, .b1, .c1, .d1, .e1, .f1, .g1 });try std.testing.expectEqual(expected, occupancy);}fn genRelevantOccupancy(piece: Pieces) [@typeInfo(Square).Enum.fields.len]BoardType {var ret: [64]BoardType = [_]BoardType{0} ** 64;for (std.enums.values(Square)) |square| {ret[@enumToInt(square)] = @popCount(Attacks.genSteps(square, piece, .white));}return ret;}test "genRelevantOccupancy" {{ // bishopconst bishop = genRelevantOccupancy(.bishop);// zig fmt: offconst expected = [64]BoardType{6, 5, 5, 5, 5, 5, 5, 6,5, 5, 5, 5, 5, 5, 5, 5,5, 5, 7, 7, 7, 7, 5, 5,5, 5, 7, 9, 9, 7, 5, 5,5, 5, 7, 9, 9, 7, 5, 5,5, 5, 7, 7, 7, 7, 5, 5,5, 5, 5, 5, 5, 5, 5, 5,6, 5, 5, 5, 5, 5, 5, 6,};// zig fmt: ontry std.testing.expectEqualSlices(BoardType, &expected, &bishop);
// zig fmt: offconst expected = [64]BoardType{12, 11, 11, 11, 11, 11, 11, 12,11, 10, 10, 10, 10, 10, 10, 11,11, 10, 10, 10, 10, 10, 10, 11,11, 10, 10, 10, 10, 10, 10, 11,11, 10, 10, 10, 10, 10, 10, 11,11, 10, 10, 10, 10, 10, 10, 11,11, 10, 10, 10, 10, 10, 10, 11,12, 11, 11, 11, 11, 11, 11, 12,};// zig fmt: on
bb.board = 0;bb.setSlice(&[_]Square{ .b8, .c8, .d8, .e8, .f8, .g8, .h7, .h6, .h5, .h4, .h3, .h2, .h1 });