From 1f47545e80be4e923da8b678449951101f1565d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Hallstr=C3=B6m?= Date: Fri, 6 Jun 2025 00:47:21 +0200 Subject: [PATCH 1/4] take1, crashes unfortunately --- .gitignore | 1 + build.zig | 54 +++++++++------- src/chess/perft.zig | 12 ++-- src/chess/position.zig | 135 +++++++++++++++++++-------------------- src/chess/tables.zig | 92 +++++++++++++------------- src/chess/types.zig | 86 ++++++++++++------------- src/chess/utils.zig | 6 +- src/engine/datagen.zig | 36 +++++------ src/engine/hce.zig | 72 ++++++++++----------- src/engine/interface.zig | 55 ++++++++-------- src/engine/movepick.zig | 12 ++-- src/engine/nnue.zig | 10 +-- src/engine/search.zig | 123 ++++++++++++++++++----------------- src/engine/see.zig | 32 +++++----- src/engine/tt.zig | 12 ++-- src/engine/weights.zig | 2 +- src/main.zig | 2 +- src/tests.zig | 2 +- 18 files changed, 375 insertions(+), 369 deletions(-) diff --git a/.gitignore b/.gitignore index b3e9017..6e2702a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ **/zig-cache +**/.zig-cache **/zig-out **/artifacts .DS_Store diff --git a/build.zig b/build.zig index 473e294..6f01e9c 100644 --- a/build.zig +++ b/build.zig @@ -6,7 +6,7 @@ const std = @import("std"); pub const DateTime = struct { day: u8, month: u8, year: u16, hour: u8, minute: u8, second: u8 }; pub fn timestamp2DateTime(timestamp: i64) DateTime { - const unixtime = @intCast(u64, timestamp); + const unixtime: u64 = @intCast(timestamp); const SECONDS_PER_DAY = 86400; const DAYS_IN_COMMON_YEAR = 365; const DAYS_IN_4_YEARS = 1461; @@ -15,19 +15,19 @@ pub fn timestamp2DateTime(timestamp: i64) DateTime { const DAYS_ON_1970_01_01 = 719468; var dayN: u64 = DAYS_ON_1970_01_01 + unixtime / SECONDS_PER_DAY; - var seconds_since_midnight: u64 = unixtime % SECONDS_PER_DAY; + const seconds_since_midnight: u64 = unixtime % SECONDS_PER_DAY; var temp: u64 = 0; temp = 4 * (dayN + DAYS_IN_100_YEARS + 1) / DAYS_IN_400_YEARS - 1; - var year = @intCast(u16, 100 * temp); + var year: u16 = @intCast(100 * temp); dayN -= DAYS_IN_100_YEARS * temp + temp / 4; temp = 4 * (dayN + DAYS_IN_COMMON_YEAR + 1) / DAYS_IN_4_YEARS - 1; - year += @intCast(u16, temp); + year += @intCast(temp); dayN -= DAYS_IN_COMMON_YEAR * temp + temp / 4; - var month = @intCast(u8, (5 * dayN + 2) / 153); - var day = @intCast(u8, dayN - (@intCast(u64, month) * 153 + 2) / 5 + 1); + var month: u8 = @intCast((5 * dayN + 2) / 153); + const day: u8 = @intCast(dayN - (@as(u64, month) * 153 + 2) / 5 + 1); month += 3; if (month > 12) { @@ -35,9 +35,9 @@ pub fn timestamp2DateTime(timestamp: i64) DateTime { year += 1; } - var hour = @intCast(u8, seconds_since_midnight / 3600); - var minute = @intCast(u8, seconds_since_midnight % 3600 / 60); - var second = @intCast(u8, seconds_since_midnight % 60); + const hour: u8 = @intCast(seconds_since_midnight / 3600); + const minute: u8 = @intCast(seconds_since_midnight % 3600 / 60); + const second: u8 = @intCast(seconds_since_midnight % 60); return DateTime{ .day = day, .month = month, .year = year, .hour = hour, .minute = minute, .second = second }; } @@ -47,7 +47,7 @@ fn dtToString(dt: DateTime, buf: []u8) []const u8 { return std.fmt.bufPrint(buf, "Compiled at {:0>4}-{:0>2}-{:0>2}-{:0>2}:{:0>2}", .{ dt.year, dt.month, dt.day, dt.hour, dt.minute }) catch unreachable; } -pub fn build(b: *std.build.Builder) void { +pub fn build(b: *std.Build) void { // Standard target options allows the person running `zig build` to choose // what target to build for. Here we do not override the defaults, which // means any target is allowed, and the default is native. Other options @@ -55,27 +55,35 @@ pub fn build(b: *std.build.Builder) void { const target = b.standardTargetOptions(.{}); const targetName = b.option([]const u8, "target-name", "Change the out name of the binary") orelse "Avalanche"; + const net_module = b.createModule( + .{ + .root_source_file = b.path("nets/bingshan.nnue"), + }, + ); // Standard release options allow the person running `zig build` to select // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. - const mode = b.standardReleaseOptions(); + const optimise = b.standardOptimizeOption(.{}); - const exe = b.addExecutable(targetName, "src/main.zig"); - exe.setTarget(target); - exe.setBuildMode(mode); + const exe = b.addExecutable(.{ + .name = targetName, + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimise, + }); + + exe.root_module.addImport("net", net_module); const build_options = b.addOptions(); - exe.addOptions("build_options", build_options); + exe.root_module.addOptions("build_options", build_options); + b.installArtifact(exe); var buf: [64]u8 = undefined; build_options.addOption([]const u8, "version", dtToString(timestamp2DateTime(std.time.timestamp()), &buf)); // build_options.addOption([]const u8, "version", "2.2.0"); - exe.use_stage1 = true; - exe.linkLibC(); - exe.install(); - const run_cmd = exe.run(); + const run_cmd = b.addRunArtifact(exe); run_cmd.step.dependOn(b.getInstallStep()); if (b.args) |args| { run_cmd.addArgs(args); @@ -84,9 +92,11 @@ pub fn build(b: *std.build.Builder) void { const run_step = b.step("run", "Run the app"); run_step.dependOn(&run_cmd.step); - const exe_tests = b.addTest("src/tests.zig"); - exe_tests.setTarget(target); - exe_tests.setBuildMode(mode); + const exe_tests = b.addTest(.{ + .root_source_file = b.path("src/tests.zig"), + .target = target, + .optimize = optimise, + }); const test_step = b.step("test", "Run unit tests"); test_step.dependOn(&exe_tests.step); diff --git a/src/chess/perft.zig b/src/chess/perft.zig index d4c7504..2c13dae 100644 --- a/src/chess/perft.zig +++ b/src/chess/perft.zig @@ -10,14 +10,14 @@ pub fn perft(comptime color: types.Color, pos: *position.Position, depth: u32) u } var nodes: usize = 0; - comptime var opp = if (color == types.Color.White) types.Color.Black else types.Color.White; + const opp = comptime if (color == types.Color.White) types.Color.Black else types.Color.White; var list = std.ArrayList(types.Move).initCapacity(std.heap.c_allocator, 48) catch unreachable; defer list.deinit(); pos.generate_legal_moves(color, &list); if (depth == 1) { - return @intCast(usize, list.items.len); + return @intCast(list.items.len); } for (list.items) |move| { @@ -32,7 +32,7 @@ pub fn perft(comptime color: types.Color, pos: *position.Position, depth: u32) u pub fn perft_div(comptime color: types.Color, pos: *position.Position, depth: u32) void { var nodes: usize = 0; var branch: usize = 0; - comptime var opp = if (color == types.Color.White) types.Color.Black else types.Color.White; + const opp = comptime if (color == types.Color.White) types.Color.Black else types.Color.White; var list = std.ArrayList(types.Move).initCapacity(std.heap.c_allocator, 48) catch unreachable; defer list.deinit(); @@ -66,11 +66,11 @@ pub fn perft_test(pos: *position.Position, depth: u32) void { nodes = perft(types.Color.Black, pos, depth); } - var elapsed = timer.read(); + const elapsed = timer.read(); std.debug.print("\n", .{}); std.debug.print("Nodes: {}\n", .{nodes}); - var mcs = @intToFloat(f64, elapsed) / 1000.0; + const mcs = @as(f64, @floatFromInt(elapsed)) / 1000.0; std.debug.print("Elapsed: {d:.2} microseconds (or {d:.6} seconds)\n", .{ mcs, mcs / 1000.0 / 1000.0 }); - var nps = @intToFloat(f64, nodes) / (@intToFloat(f64, elapsed) / 1000.0 / 1000.0 / 1000.0); + const nps = @as(f64, @floatFromInt(nodes)) / (@as(f64, @floatFromInt(elapsed)) / 1000.0 / 1000.0 / 1000.0); std.debug.print("NPS: {d:.2} nodes/s (or {d:.4} mn/s)\n", .{ nps, nps / 1000.0 / 1000.0 }); } diff --git a/src/chess/position.zig b/src/chess/position.zig index fcc297c..9a17cc7 100644 --- a/src/chess/position.zig +++ b/src/chess/position.zig @@ -67,7 +67,7 @@ pub const Position = struct { pub fn new() Position { var pos = Position{}; - std.mem.set(types.Piece, pos.mailbox[0..types.N_SQUARES], types.Piece.NO_PIECE); + @memset(pos.mailbox[0..types.N_SQUARES], types.Piece.NO_PIECE); pos.history[0] = UndoInfo.new(); pos.evaluator = hce.DynamicEvaluator{}; @@ -83,14 +83,14 @@ pub const Position = struct { std.debug.print("{s} {} ", .{ line, @divTrunc(i, 8) + 1 }); var j: i32 = 0; while (j < 8) : (j += 1) { - std.debug.print("| {c} ", .{types.PieceString[self.mailbox[@intCast(usize, i + j)].index()]}); + std.debug.print("| {c} ", .{types.PieceString[self.mailbox[@intCast(i + j)].index()]}); } std.debug.print("| {}\n", .{@divTrunc(i, 8) + 1}); } std.debug.print("{s}", .{line}); std.debug.print("{s}\n", .{letters}); - var s = if (self.turn == types.Color.White) "White" else "Black"; + const s = if (self.turn == types.Color.White) "White" else "Black"; std.debug.print("{s} to move\n", .{s}); std.debug.print("Hash: 0x{x}\n", .{self.hash}); @@ -98,21 +98,21 @@ pub const Position = struct { pub fn set_fen(self: *Position, fen: []const u8) void { self.* = Position.new(); - var sq: i32 = @intCast(i32, @enumToInt(types.Square.a8)); - var tokens = std.mem.tokenize(u8, fen, " "); - var bd = tokens.next().?; + var sq: i32 = @intCast(@intFromEnum(types.Square.a8)); + var tokens = std.mem.tokenizeScalar(u8, fen, ' '); + const bd = tokens.next().?; for (bd) |ch| { if (std.ascii.isDigit(ch)) { - sq += @intCast(i32, ch - '0') * @enumToInt(types.Direction.East); + sq += @as(i32, @intCast(ch - '0')) * @intFromEnum(types.Direction.East); } else if (ch == '/') { - sq += @enumToInt(types.Direction.South) * 2; + sq += @intFromEnum(types.Direction.South) * 2; } else { - self.add_piece(@intToEnum(types.Piece, utils.first_index(u8, types.PieceString[0..], ch).?), @intToEnum(types.Square, sq)); + self.add_piece(@enumFromInt(utils.first_index(u8, types.PieceString[0..], ch).?), @enumFromInt(sq)); sq += 1; } } - var turn = tokens.next().?; + const turn = tokens.next().?; if (std.mem.eql(u8, turn, "w")) { self.turn = types.Color.White; } else { @@ -121,7 +121,7 @@ pub const Position = struct { } self.history[self.game_ply].entry = types.AllCastlingMask; - var castle = tokens.next().?; + const castle = tokens.next().?; for (castle) |ch| { switch (ch) { 'K' => { @@ -140,11 +140,11 @@ pub const Position = struct { } } - var ep = tokens.next().?; + const ep = tokens.next().?; if (ep.len == 2) { - for (types.SquareToString) |sq_str, i| { + for (types.SquareToString, 0..) |sq_str, i| { if (std.mem.eql(u8, ep, sq_str)) { - self.history[self.game_ply].ep_sq = @intToEnum(types.Square, i); + self.history[self.game_ply].ep_sq = @enumFromInt(i); self.hash ^= zobrist.EnPassantHash[types.file_plain(i)]; break; } @@ -164,7 +164,7 @@ pub const Position = struct { var empty_count: u8 = 0; var j: i32 = 0; while (j < 8) : (j += 1) { - const idx = @intCast(usize, i + j); + const idx: usize = @intCast(i + j); if (self.mailbox[idx] == types.Piece.NO_PIECE) { empty_count += 1; @@ -316,9 +316,9 @@ pub const Position = struct { } pub inline fn in_check(self: Position, comptime color: types.Color) bool { - comptime var king: types.Piece = types.Piece.new_comptime(color, types.PieceType.King); - comptime var opp = if (color == types.Color.White) types.Color.Black else types.Color.White; - return self.attackers_from(opp, @intToEnum(types.Square, types.lsb(self.piece_bitboards[king.index()])), self.all_pieces(types.Color.White) | self.all_pieces(types.Color.Black)) != 0; + const king: types.Piece = comptime types.Piece.new_comptime(color, types.PieceType.King); + const opp = comptime if (color == types.Color.White) types.Color.Black else types.Color.White; + return self.attackers_from(opp, @enumFromInt(types.lsb(self.piece_bitboards[king.index()])), self.all_pieces(types.Color.White) | self.all_pieces(types.Color.Black)) != 0; } pub inline fn has_non_pawns(self: Position) bool { @@ -337,10 +337,10 @@ pub const Position = struct { self.game_ply += 1; self.history[self.game_ply] = UndoInfo.from(self.history[self.game_ply - 1]); - var flags = move.get_flags(); + const flags = move.get_flags(); self.history[self.game_ply].entry |= types.SquareIndexBB[move.to] | types.SquareIndexBB[move.from]; - var pt = self.mailbox[move.from].piece_type(); + const pt = self.mailbox[move.from].piece_type(); if (pt == types.PieceType.Pawn or move.is_capture()) { self.history[self.game_ply].fifty = 0; } @@ -378,7 +378,7 @@ pub const Position = struct { self.remove_piece(move.get_to().add(types.Direction.South.relative_dir(color))); }, else => { - var index = @enumToInt(flags); + const index = @intFromEnum(flags); switch (index) { types.PR_KNIGHT => { self.remove_piece(move.get_from()); @@ -422,8 +422,7 @@ pub const Position = struct { }, else => { if (flags == types.MoveFlags.CAPTURE) { - var c = self.mailbox[move.to]; - self.history[self.game_ply].captured = c; + self.history[self.game_ply].captured = self.mailbox[move.to]; self.move_piece(move.get_from(), move.get_to()); } }, @@ -433,8 +432,8 @@ pub const Position = struct { } pub fn undo_move(self: *Position, comptime color: types.Color, move: types.Move) void { - var flags = move.get_flags(); - comptime var opp = if (color == types.Color.White) types.Color.Black else types.Color.White; + const flags = move.get_flags(); + const opp = comptime if (color == types.Color.White) types.Color.Black else types.Color.White; switch (flags) { types.MoveFlags.QUIET => { @@ -467,7 +466,7 @@ pub const Position = struct { self.add_piece(types.Piece.new_comptime(opp, types.PieceType.Pawn), move.get_to().add(types.Direction.South.relative_dir(color))); }, else => { - var index = @enumToInt(flags); + const index = @intFromEnum(flags); switch (index) { types.PR_KNIGHT, types.PR_BISHOP, types.PR_ROOK, types.PR_QUEEN => { self.remove_piece(move.get_to()); @@ -516,14 +515,14 @@ pub const Position = struct { // Generate all LEGAL moves pub fn generate_legal_moves(self: *Position, comptime color: types.Color, list: *std.ArrayList(types.Move)) void { - comptime var opp = if (color == types.Color.White) types.Color.Black else types.Color.White; + const opp = comptime if (color == types.Color.White) types.Color.Black else types.Color.White; const us_bb = self.all_pieces(color); const them_bb = self.all_pieces(opp); const all_bb = us_bb | them_bb; - const our_king = @intToEnum(types.Square, types.lsb(self.piece_bitboards[types.Piece.new_comptime(color, types.PieceType.King).index()])); - const their_king = @intToEnum(types.Square, types.lsb(self.piece_bitboards[types.Piece.new_comptime(opp, types.PieceType.King).index()])); + const our_king: types.Square = @enumFromInt(types.lsb(self.piece_bitboards[types.Piece.new_comptime(color, types.PieceType.King).index()])); + const their_king: types.Square = @enumFromInt(types.lsb(self.piece_bitboards[types.Piece.new_comptime(opp, types.PieceType.King).index()])); const our_diag_sliders = self.diagonal_sliders(color); const their_diag_sliders = self.diagonal_sliders(opp); @@ -535,10 +534,10 @@ pub const Position = struct { var b2: types.Bitboard = 0; var b3: types.Bitboard = 0; - comptime var rel_north = if (color == types.Color.White) types.Direction.North else types.Direction.South; - comptime var rel_south = if (color == types.Color.White) types.Direction.South else types.Direction.North; - comptime var rel_northwest = if (color == types.Color.White) types.Direction.NorthWest else types.Direction.SouthEast; - comptime var rel_northeast = if (color == types.Color.White) types.Direction.NorthEast else types.Direction.SouthWest; + const rel_north = comptime if (color == types.Color.White) types.Direction.North else types.Direction.South; + const rel_south = comptime if (color == types.Color.White) types.Direction.South else types.Direction.North; + const rel_northwest = comptime if (color == types.Color.White) types.Direction.NorthWest else types.Direction.SouthEast; + const rel_northeast = comptime if (color == types.Color.White) types.Direction.NorthEast else types.Direction.SouthWest; // Squares King cannot go to var danger: types.Bitboard = 0; @@ -603,7 +602,7 @@ pub const Position = struct { 1 => { // Single check: Move, capture, or block - var checker_sq = @intToEnum(types.Square, types.lsb(self.checkers)); + const checker_sq: types.Square = @enumFromInt(types.lsb(self.checkers)); switch (self.mailbox[checker_sq.index()]) { types.Piece.new_comptime(opp, types.PieceType.Pawn) => { @@ -630,10 +629,10 @@ pub const Position = struct { while (b1 != 0) { var psq = types.pop_lsb(&b1); if (self.mailbox[psq.index()].piece_type() == types.PieceType.Pawn and (types.SquareIndexBB[psq.index()] & types.MaskRank[types.Rank.RANK7.relative_rank(color).index()]) != 0) { - list.append(types.Move.new_from_to_flag(psq, checker_sq, @intToEnum(types.MoveFlags, types.PC_QUEEN))) catch {}; - list.append(types.Move.new_from_to_flag(psq, checker_sq, @intToEnum(types.MoveFlags, types.PC_ROOK))) catch {}; - list.append(types.Move.new_from_to_flag(psq, checker_sq, @intToEnum(types.MoveFlags, types.PC_KNIGHT))) catch {}; - list.append(types.Move.new_from_to_flag(psq, checker_sq, @intToEnum(types.MoveFlags, types.PC_BISHOP))) catch {}; + list.append(types.Move.new_from_to_flag(psq, checker_sq, @enumFromInt(types.PC_QUEEN))) catch {}; + list.append(types.Move.new_from_to_flag(psq, checker_sq, @enumFromInt(types.PC_ROOK))) catch {}; + list.append(types.Move.new_from_to_flag(psq, checker_sq, @enumFromInt(types.PC_KNIGHT))) catch {}; + list.append(types.Move.new_from_to_flag(psq, checker_sq, @enumFromInt(types.PC_BISHOP))) catch {}; } else { list.append(types.Move.new_from_to_flag(psq, checker_sq, types.MoveFlags.CAPTURE)) catch {}; } @@ -673,7 +672,7 @@ pub const Position = struct { // Diagonal pin? OK b1 = b2 & self.pinned & tables.LineOf[ep.index()][our_king.index()]; if (b1 != 0) { - list.append(types.Move.new_from_to_flag(@intToEnum(types.Square, types.lsb(b1)), ep, types.MoveFlags.EN_PASSANT)) catch {}; + list.append(types.Move.new_from_to_flag(@enumFromInt(types.lsb(b1)), ep, types.MoveFlags.EN_PASSANT)) catch {}; } } @@ -682,7 +681,7 @@ pub const Position = struct { // 1. The king and the rook have both not moved // 2. No piece is attacking between the the rook and the king // 3. The king is not in check - var entry = self.history[self.game_ply].entry; + const entry = self.history[self.game_ply].entry; if (0 == ((entry & types.get_oo_mask(color)) | ((all_bb | danger) & types.get_oo_blocker_mask(color)))) { if (color == types.Color.White) { list.append(types.Move.new_from_to_flag(types.Square.e1, types.Square.g1, types.MoveFlags.OO)) catch {}; @@ -803,10 +802,10 @@ pub const Position = struct { while (b2 != 0) { sq = types.pop_lsb(&b2); - list.append(types.Move.new_from_to_flag(sq.sub(rel_north), sq, @intToEnum(types.MoveFlags, types.PR_QUEEN))) catch {}; - list.append(types.Move.new_from_to_flag(sq.sub(rel_north), sq, @intToEnum(types.MoveFlags, types.PR_ROOK))) catch {}; - list.append(types.Move.new_from_to_flag(sq.sub(rel_north), sq, @intToEnum(types.MoveFlags, types.PR_KNIGHT))) catch {}; - list.append(types.Move.new_from_to_flag(sq.sub(rel_north), sq, @intToEnum(types.MoveFlags, types.PR_BISHOP))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_north), sq, @enumFromInt(types.PR_QUEEN))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_north), sq, @enumFromInt(types.PR_ROOK))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_north), sq, @enumFromInt(types.PR_KNIGHT))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_north), sq, @enumFromInt(types.PR_BISHOP))) catch {}; } // Promotion Captures @@ -816,19 +815,19 @@ pub const Position = struct { while (b2 != 0) { sq = types.pop_lsb(&b2); - list.append(types.Move.new_from_to_flag(sq.sub(rel_northwest), sq, @intToEnum(types.MoveFlags, types.PC_QUEEN))) catch {}; - list.append(types.Move.new_from_to_flag(sq.sub(rel_northwest), sq, @intToEnum(types.MoveFlags, types.PC_ROOK))) catch {}; - list.append(types.Move.new_from_to_flag(sq.sub(rel_northwest), sq, @intToEnum(types.MoveFlags, types.PC_KNIGHT))) catch {}; - list.append(types.Move.new_from_to_flag(sq.sub(rel_northwest), sq, @intToEnum(types.MoveFlags, types.PC_BISHOP))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_northwest), sq, @enumFromInt(types.PC_QUEEN))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_northwest), sq, @enumFromInt(types.PC_ROOK))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_northwest), sq, @enumFromInt(types.PC_KNIGHT))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_northwest), sq, @enumFromInt(types.PC_BISHOP))) catch {}; } while (b3 != 0) { sq = types.pop_lsb(&b3); - list.append(types.Move.new_from_to_flag(sq.sub(rel_northeast), sq, @intToEnum(types.MoveFlags, types.PC_QUEEN))) catch {}; - list.append(types.Move.new_from_to_flag(sq.sub(rel_northeast), sq, @intToEnum(types.MoveFlags, types.PC_ROOK))) catch {}; - list.append(types.Move.new_from_to_flag(sq.sub(rel_northeast), sq, @intToEnum(types.MoveFlags, types.PC_KNIGHT))) catch {}; - list.append(types.Move.new_from_to_flag(sq.sub(rel_northeast), sq, @intToEnum(types.MoveFlags, types.PC_BISHOP))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_northeast), sq, @enumFromInt(types.PC_QUEEN))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_northeast), sq, @enumFromInt(types.PC_ROOK))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_northeast), sq, @enumFromInt(types.PC_KNIGHT))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_northeast), sq, @enumFromInt(types.PC_BISHOP))) catch {}; } } @@ -838,14 +837,14 @@ pub const Position = struct { // Generate all CAPTURE moves pub fn generate_q_moves(self: *Position, comptime color: types.Color, list: *std.ArrayList(types.Move)) void { - comptime var opp = if (color == types.Color.White) types.Color.Black else types.Color.White; + const opp = comptime if (color == types.Color.White) types.Color.Black else types.Color.White; const us_bb = self.all_pieces(color); const them_bb = self.all_pieces(opp); const all_bb = us_bb | them_bb; - const our_king = @intToEnum(types.Square, types.lsb(self.piece_bitboards[types.Piece.new_comptime(color, types.PieceType.King).index()])); - const their_king = @intToEnum(types.Square, types.lsb(self.piece_bitboards[types.Piece.new_comptime(opp, types.PieceType.King).index()])); + const our_king: types.Square = @enumFromInt(types.lsb(self.piece_bitboards[types.Piece.new_comptime(color, types.PieceType.King).index()])); + const their_king: types.Square = @enumFromInt(types.lsb(self.piece_bitboards[types.Piece.new_comptime(opp, types.PieceType.King).index()])); const our_diag_sliders = self.diagonal_sliders(color); const their_diag_sliders = self.diagonal_sliders(opp); @@ -857,9 +856,9 @@ pub const Position = struct { var b2: types.Bitboard = 0; var b3: types.Bitboard = 0; - comptime var rel_south = if (color == types.Color.White) types.Direction.South else types.Direction.North; - comptime var rel_northwest = if (color == types.Color.White) types.Direction.NorthWest else types.Direction.SouthEast; - comptime var rel_northeast = if (color == types.Color.White) types.Direction.NorthEast else types.Direction.SouthWest; + const rel_south = comptime if (color == types.Color.White) types.Direction.South else types.Direction.North; + const rel_northwest = comptime if (color == types.Color.White) types.Direction.NorthWest else types.Direction.SouthEast; + const rel_northeast = comptime if (color == types.Color.White) types.Direction.NorthEast else types.Direction.SouthWest; // Squares King cannot go to var danger: types.Bitboard = 0; @@ -923,7 +922,7 @@ pub const Position = struct { 1 => { // Single check: Move, capture, or block - var checker_sq = @intToEnum(types.Square, types.lsb(self.checkers)); + var checker_sq: types.Square = @enumFromInt(types.lsb(self.checkers)); switch (self.mailbox[checker_sq.index()]) { types.Piece.new_comptime(opp, types.PieceType.Pawn) => { @@ -985,7 +984,7 @@ pub const Position = struct { // Diagonal pin? OK b1 = b2 & self.pinned & tables.LineOf[ep.index()][our_king.index()]; if (b1 != 0) { - list.append(types.Move.new_from_to_flag(@intToEnum(types.Square, types.lsb(b1)), ep, types.MoveFlags.EN_PASSANT)) catch {}; + list.append(types.Move.new_from_to_flag(@enumFromInt(types.lsb(b1)), ep, types.MoveFlags.EN_PASSANT)) catch {}; } } @@ -1067,19 +1066,19 @@ pub const Position = struct { while (b2 != 0) { sq = types.pop_lsb(&b2); - list.append(types.Move.new_from_to_flag(sq.sub(rel_northwest), sq, @intToEnum(types.MoveFlags, types.PC_QUEEN))) catch {}; - list.append(types.Move.new_from_to_flag(sq.sub(rel_northwest), sq, @intToEnum(types.MoveFlags, types.PC_ROOK))) catch {}; - list.append(types.Move.new_from_to_flag(sq.sub(rel_northwest), sq, @intToEnum(types.MoveFlags, types.PC_KNIGHT))) catch {}; - list.append(types.Move.new_from_to_flag(sq.sub(rel_northwest), sq, @intToEnum(types.MoveFlags, types.PC_BISHOP))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_northwest), sq, @enumFromInt(types.PC_QUEEN))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_northwest), sq, @enumFromInt(types.PC_ROOK))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_northwest), sq, @enumFromInt(types.PC_KNIGHT))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_northwest), sq, @enumFromInt(types.PC_BISHOP))) catch {}; } while (b3 != 0) { sq = types.pop_lsb(&b3); - list.append(types.Move.new_from_to_flag(sq.sub(rel_northeast), sq, @intToEnum(types.MoveFlags, types.PC_QUEEN))) catch {}; - list.append(types.Move.new_from_to_flag(sq.sub(rel_northeast), sq, @intToEnum(types.MoveFlags, types.PC_ROOK))) catch {}; - list.append(types.Move.new_from_to_flag(sq.sub(rel_northeast), sq, @intToEnum(types.MoveFlags, types.PC_KNIGHT))) catch {}; - list.append(types.Move.new_from_to_flag(sq.sub(rel_northeast), sq, @intToEnum(types.MoveFlags, types.PC_BISHOP))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_northeast), sq, @enumFromInt(types.PC_QUEEN))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_northeast), sq, @enumFromInt(types.PC_ROOK))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_northeast), sq, @enumFromInt(types.PC_KNIGHT))) catch {}; + list.append(types.Move.new_from_to_flag(sq.sub(rel_northeast), sq, @enumFromInt(types.PC_BISHOP))) catch {}; } } diff --git a/src/chess/tables.zig b/src/chess/tables.zig index 3101d8b..784798a 100644 --- a/src/chess/tables.zig +++ b/src/chess/tables.zig @@ -90,7 +90,7 @@ pub inline fn reverse_bitboard(b_: types.Bitboard) types.Bitboard { // Hyperbola Quintessence Algorithm pub inline fn sliding_attack(square_: types.Square, occ: types.Bitboard, mask: types.Bitboard) types.Bitboard { - var square = square_.index(); + const square = square_.index(); return (((mask & occ) -% types.SquareIndexBB[square] *% 2) ^ reverse_bitboard(reverse_bitboard(mask & occ) -% reverse_bitboard(types.SquareIndexBB[square]) *% 2)) & mask; } @@ -98,7 +98,7 @@ pub inline fn sliding_attack(square_: types.Square, occ: types.Bitboard, mask: t // ROOK MAGIC BITBOARDS inline fn get_rook_attacks_for_init(square: types.Square, occ: types.Bitboard) types.Bitboard { - return sliding_attack(square, occ, types.MaskFile[@enumToInt(square.file())]) | sliding_attack(square, occ, types.MaskRank[@enumToInt(square.rank())]); + return sliding_attack(square, occ, types.MaskFile[@intFromEnum(square.file())]) | sliding_attack(square, occ, types.MaskRank[@intFromEnum(square.rank())]); } var RookAttackMasks: [64]types.Bitboard = std.mem.zeroes([64]types.Bitboard); @@ -125,10 +125,10 @@ const RookMagics = [64]types.Bitboard{ }; pub fn init_rook_attacks() void { - var sq: usize = @enumToInt(types.Square.a1); + var sq: usize = @intFromEnum(types.Square.a1); - while (sq <= @enumToInt(types.Square.h8)) : (sq += 1) { - var edges = ((types.MaskRank[types.File.AFILE.index()] | types.MaskRank[types.File.HFILE.index()]) & ~types.MaskRank[types.rank_plain(sq)]) | + while (sq <= @intFromEnum(types.Square.h8)) : (sq += 1) { + const edges = ((types.MaskRank[types.File.AFILE.index()] | types.MaskRank[types.File.HFILE.index()]) & ~types.MaskRank[types.rank_plain(sq)]) | ((types.MaskFile[types.File.AFILE.index()] | types.MaskFile[types.File.HFILE.index()]) & ~types.MaskFile[types.file_plain(sq)]); RookAttackMasks[sq] = (types.MaskRank[types.rank_plain(sq)] ^ types.MaskFile[types.file_plain(sq)]) & ~edges; @@ -138,15 +138,15 @@ pub fn init_rook_attacks() void { var index: types.Bitboard = 0; index = index *% RookMagics[sq]; - index = index >> @intCast(u6, RookAttackShifts[sq]); - RookAttacks[sq][index] = get_rook_attacks_for_init(@intToEnum(types.Square, sq), subset); + index = index >> @intCast(RookAttackShifts[sq]); + RookAttacks[sq][index] = get_rook_attacks_for_init(@enumFromInt(sq), subset); subset = (subset -% RookAttackMasks[sq]) & RookAttackMasks[sq]; while (subset != 0) { index = subset; index = index *% RookMagics[sq]; - index = index >> @intCast(u6, RookAttackShifts[sq]); - RookAttacks[sq][index] = get_rook_attacks_for_init(@intToEnum(types.Square, sq), subset); + index = index >> @intCast(RookAttackShifts[sq]); + RookAttacks[sq][index] = get_rook_attacks_for_init(@enumFromInt(sq), subset); subset = (subset -% RookAttackMasks[sq]) & RookAttackMasks[sq]; } } @@ -154,19 +154,19 @@ pub fn init_rook_attacks() void { // Returns the bitboard for rook attacks pub inline fn get_rook_attacks(square: types.Square, occ: types.Bitboard) types.Bitboard { - return RookAttacks[square.index()][((occ & RookAttackMasks[square.index()]) *% RookMagics[square.index()]) >> @intCast(u6, RookAttackShifts[square.index()])]; + return RookAttacks[square.index()][((occ & RookAttackMasks[square.index()]) *% RookMagics[square.index()]) >> @intCast(RookAttackShifts[square.index()])]; } // Returns x-ray attacks, which is the attack when the first-layer blockers are removed. pub inline fn get_xray_rook_attacks(square: types.Square, occ: types.Bitboard, blockers: types.Bitboard) types.Bitboard { - var attacks = get_rook_attacks(square, occ); + const attacks = get_rook_attacks(square, occ); return attacks ^ get_rook_attacks(square, occ ^ (blockers & attacks)); } // BISHOP MAGIC BITBOARDS inline fn get_bishop_attacks_for_init(square: types.Square, occ: types.Bitboard) types.Bitboard { - return sliding_attack(square, occ, types.MaskDiagonal[@intCast(usize, square.diagonal())]) | sliding_attack(square, occ, types.MaskAntiDiagonal[@intCast(usize, square.anti_diagonal())]); + return sliding_attack(square, occ, types.MaskDiagonal[@intCast(square.diagonal())]) | sliding_attack(square, occ, types.MaskAntiDiagonal[@intCast(square.anti_diagonal())]); } var BishopAttackMasks: [64]types.Bitboard = std.mem.zeroes([64]types.Bitboard); @@ -193,10 +193,10 @@ const BishopMagics = [64]types.Bitboard{ }; pub fn init_bishop_attacks() void { - var sq: usize = @enumToInt(types.Square.a1); + var sq: usize = @intFromEnum(types.Square.a1); - while (sq <= @enumToInt(types.Square.h8)) : (sq += 1) { - var edges = ((types.MaskRank[types.File.AFILE.index()] | types.MaskRank[types.File.HFILE.index()]) & ~types.MaskRank[types.rank_plain(sq)]) | + while (sq <= @intFromEnum(types.Square.h8)) : (sq += 1) { + const edges = ((types.MaskRank[types.File.AFILE.index()] | types.MaskRank[types.File.HFILE.index()]) & ~types.MaskRank[types.rank_plain(sq)]) | ((types.MaskFile[types.File.AFILE.index()] | types.MaskFile[types.File.HFILE.index()]) & ~types.MaskFile[types.file_plain(sq)]); BishopAttackMasks[sq] = (types.MaskDiagonal[types.diagonal_plain(sq)] ^ types.MaskAntiDiagonal[types.anti_diagonal_plain(sq)]) & ~edges; @@ -206,15 +206,15 @@ pub fn init_bishop_attacks() void { var index: types.Bitboard = 0; index = index *% BishopMagics[sq]; - index = index >> @intCast(u6, BishopAttackShifts[sq]); - BishopAttacks[sq][index] = get_bishop_attacks_for_init(@intToEnum(types.Square, sq), subset); + index = index >> @intCast(BishopAttackShifts[sq]); + BishopAttacks[sq][index] = get_bishop_attacks_for_init(@enumFromInt(sq), subset); subset = (subset -% BishopAttackMasks[sq]) & BishopAttackMasks[sq]; while (subset != 0) { index = subset; index = index *% BishopMagics[sq]; - index = index >> @intCast(u6, BishopAttackShifts[sq]); - BishopAttacks[sq][index] = get_bishop_attacks_for_init(@intToEnum(types.Square, sq), subset); + index = index >> @intCast(BishopAttackShifts[sq]); + BishopAttacks[sq][index] = get_bishop_attacks_for_init(@enumFromInt(sq), subset); subset = (subset -% BishopAttackMasks[sq]) & BishopAttackMasks[sq]; } } @@ -222,12 +222,12 @@ pub fn init_bishop_attacks() void { // Returns the bitboard for bishop attacks pub inline fn get_bishop_attacks(square: types.Square, occ: types.Bitboard) types.Bitboard { - return BishopAttacks[square.index()][((occ & BishopAttackMasks[square.index()]) *% BishopMagics[square.index()]) >> @intCast(u6, BishopAttackShifts[square.index()])]; + return BishopAttacks[square.index()][((occ & BishopAttackMasks[square.index()]) *% BishopMagics[square.index()]) >> @intCast(BishopAttackShifts[square.index()])]; } // Returns x-ray attacks, which is the attack when the first-layer blockers are removed. pub inline fn get_xray_bishop_attacks(square: types.Square, occ: types.Bitboard, blockers: types.Bitboard) types.Bitboard { - var attacks = get_bishop_attacks(square, occ); + const attacks = get_bishop_attacks(square, occ); return attacks ^ get_bishop_attacks(square, occ ^ (blockers & attacks)); } @@ -237,17 +237,17 @@ pub inline fn get_xray_bishop_attacks(square: types.Square, occ: types.Bitboard, pub var SquaresBetween: [64][64]types.Bitboard = std.mem.zeroes([64][64]types.Bitboard); pub fn init_squares_between() void { - var sq1: usize = @enumToInt(types.Square.a1); + var sq1: usize = @intFromEnum(types.Square.a1); - while (sq1 <= @enumToInt(types.Square.h8)) : (sq1 += 1) { - var sq2: usize = @enumToInt(types.Square.a1); + while (sq1 <= @intFromEnum(types.Square.h8)) : (sq1 += 1) { + var sq2: usize = @intFromEnum(types.Square.a1); - while (sq2 <= @enumToInt(types.Square.h8)) : (sq2 += 1) { - var sqs = types.SquareIndexBB[sq1] | types.SquareIndexBB[sq2]; + while (sq2 <= @intFromEnum(types.Square.h8)) : (sq2 += 1) { + const sqs = types.SquareIndexBB[sq1] | types.SquareIndexBB[sq2]; if (types.file_plain(sq1) == types.file_plain(sq2) or types.rank_plain(sq1) == types.rank_plain(sq2)) { - SquaresBetween[sq1][sq2] = get_rook_attacks_for_init(@intToEnum(types.Square, sq1), sqs) & get_rook_attacks_for_init(@intToEnum(types.Square, sq2), sqs); + SquaresBetween[sq1][sq2] = get_rook_attacks_for_init(@enumFromInt(sq1), sqs) & get_rook_attacks_for_init(@enumFromInt(sq2), sqs); } else if (types.diagonal_plain(sq1) == types.diagonal_plain(sq2) or types.anti_diagonal_plain(sq1) == types.anti_diagonal_plain(sq2)) { - SquaresBetween[sq1][sq2] = get_bishop_attacks_for_init(@intToEnum(types.Square, sq1), sqs) & get_bishop_attacks_for_init(@intToEnum(types.Square, sq2), sqs); + SquaresBetween[sq1][sq2] = get_bishop_attacks_for_init(@enumFromInt(sq1), sqs) & get_bishop_attacks_for_init(@enumFromInt(sq2), sqs); } else { SquaresBetween[sq1][sq2] = 0; } @@ -261,16 +261,16 @@ pub fn init_squares_between() void { pub var LineOf: [64][64]types.Bitboard = std.mem.zeroes([64][64]types.Bitboard); pub fn init_line_between() void { - var sq1: usize = @enumToInt(types.Square.a1); + var sq1: usize = @intFromEnum(types.Square.a1); - while (sq1 <= @enumToInt(types.Square.h8)) : (sq1 += 1) { - var sq2: usize = @enumToInt(types.Square.a1); + while (sq1 <= @intFromEnum(types.Square.h8)) : (sq1 += 1) { + var sq2: usize = @intFromEnum(types.Square.a1); - while (sq2 <= @enumToInt(types.Square.h8)) : (sq2 += 1) { + while (sq2 <= @intFromEnum(types.Square.h8)) : (sq2 += 1) { if (types.file_plain(sq1) == types.file_plain(sq2) or types.rank_plain(sq1) == types.rank_plain(sq2)) { - LineOf[sq1][sq2] = get_rook_attacks_for_init(@intToEnum(types.Square, sq1), 0) & get_rook_attacks_for_init(@intToEnum(types.Square, sq2), 0) | types.SquareIndexBB[sq1] | types.SquareIndexBB[sq2]; + LineOf[sq1][sq2] = get_rook_attacks_for_init(@enumFromInt(sq1), 0) & get_rook_attacks_for_init(@enumFromInt(sq2), 0) | types.SquareIndexBB[sq1] | types.SquareIndexBB[sq2]; } else if (types.diagonal_plain(sq1) == types.diagonal_plain(sq2) or types.anti_diagonal_plain(sq1) == types.anti_diagonal_plain(sq2)) { - LineOf[sq1][sq2] = get_bishop_attacks_for_init(@intToEnum(types.Square, sq1), 0) & get_bishop_attacks_for_init(@intToEnum(types.Square, sq2), 0) | types.SquareIndexBB[sq1] | types.SquareIndexBB[sq2]; + LineOf[sq1][sq2] = get_bishop_attacks_for_init(@enumFromInt(sq1), 0) & get_bishop_attacks_for_init(@enumFromInt(sq2), 0) | types.SquareIndexBB[sq1] | types.SquareIndexBB[sq2]; } else { LineOf[sq1][sq2] = 0; } @@ -284,16 +284,16 @@ pub var PseudoLegalAttacks: [types.N_PT][64]types.Bitboard = std.mem.zeroes([typ pub var PawnAttacks: [types.N_COLORS][64]types.Bitboard = std.mem.zeroes([types.N_COLORS][64]types.Bitboard); pub fn init_pseudo_legal() void { - std.mem.copy(types.Bitboard, PawnAttacks[0][0..64], WhitePawnAttacks[0..64]); - std.mem.copy(types.Bitboard, PawnAttacks[1][0..64], BlackPawnAttacks[0..64]); - std.mem.copy(types.Bitboard, PseudoLegalAttacks[@enumToInt(types.PieceType.Knight)][0..64], KnightAttacks[0..64]); - std.mem.copy(types.Bitboard, PseudoLegalAttacks[@enumToInt(types.PieceType.King)][0..64], KingAttacks[0..64]); - var sq: usize = @enumToInt(types.Square.a1); - - while (sq <= @enumToInt(types.Square.h8)) : (sq += 1) { - PseudoLegalAttacks[@enumToInt(types.PieceType.Bishop)][sq] = get_bishop_attacks_for_init(@intToEnum(types.Square, sq), 0); - PseudoLegalAttacks[@enumToInt(types.PieceType.Rook)][sq] = get_rook_attacks_for_init(@intToEnum(types.Square, sq), 0); - PseudoLegalAttacks[@enumToInt(types.PieceType.Queen)][sq] = PseudoLegalAttacks[@enumToInt(types.PieceType.Bishop)][sq] | PseudoLegalAttacks[@enumToInt(types.PieceType.Rook)][sq]; + @memcpy(PawnAttacks[0][0..64], WhitePawnAttacks[0..64]); + @memcpy(PawnAttacks[1][0..64], BlackPawnAttacks[0..64]); + @memcpy(PseudoLegalAttacks[@intFromEnum(types.PieceType.Knight)][0..64], KnightAttacks[0..64]); + @memcpy(PseudoLegalAttacks[@intFromEnum(types.PieceType.King)][0..64], KingAttacks[0..64]); + var sq: usize = @intFromEnum(types.Square.a1); + + while (sq <= @intFromEnum(types.Square.h8)) : (sq += 1) { + PseudoLegalAttacks[@intFromEnum(types.PieceType.Bishop)][sq] = get_bishop_attacks_for_init(@enumFromInt(sq), 0); + PseudoLegalAttacks[@intFromEnum(types.PieceType.Rook)][sq] = get_rook_attacks_for_init(@enumFromInt(sq), 0); + PseudoLegalAttacks[@intFromEnum(types.PieceType.Queen)][sq] = PseudoLegalAttacks[@intFromEnum(types.PieceType.Bishop)][sq] | PseudoLegalAttacks[@intFromEnum(types.PieceType.Rook)][sq]; } } @@ -310,13 +310,13 @@ pub inline fn get_attacks(pt: types.PieceType, sq: types.Square, occ: types.Bitb types.PieceType.Rook => get_rook_attacks(sq, occ), types.PieceType.Bishop => get_bishop_attacks(sq, occ), types.PieceType.Queen => get_rook_attacks(sq, occ) | get_bishop_attacks(sq, occ), - else => PseudoLegalAttacks[@enumToInt(pt)][sq.index()], + else => PseudoLegalAttacks[@intFromEnum(pt)][sq.index()], }; } // Get Pawn attacks of a given color and square pub inline fn get_pawn_attacks(comptime color: types.Color, sq: types.Square) types.Bitboard { - return PawnAttacks[@enumToInt(color)][sq.index()]; + return PawnAttacks[@intFromEnum(color)][sq.index()]; } // Get Pawn attacks of every pawn on bitboard diff --git a/src/chess/types.zig b/src/chess/types.zig index e550456..c18d451 100644 --- a/src/chess/types.zig +++ b/src/chess/types.zig @@ -6,7 +6,7 @@ pub const Color = enum(u8) { White, Black, pub inline fn invert(self: Color) Color { - return @intToEnum(Color, @enumToInt(self) ^ 1); + return @enumFromInt(@intFromEnum(self) ^ 1); } }; @@ -26,7 +26,7 @@ pub const Direction = enum(i32) { SouthSouth = -16, pub inline fn relative_dir(self: Direction, comptime c: Color) Direction { - return if (c == Color.White) self else @intToEnum(Direction, -@enumToInt(self)); + return if (c == Color.White) self else @enumFromInt(-@intFromEnum(self)); } }; @@ -40,7 +40,7 @@ pub const PieceType = enum(u8) { King, pub inline fn index(self: PieceType) u8 { - return @enumToInt(self); + return @intFromEnum(self); } }; @@ -67,27 +67,27 @@ pub const Piece = enum(u8) { NO_PIECE, pub inline fn new(c: Color, pt: PieceType) Piece { - return @intToEnum(Piece, (@enumToInt(c) << 3) + @enumToInt(pt)); + return @enumFromInt((@intFromEnum(c) << 3) + @intFromEnum(pt)); } pub inline fn new_comptime(comptime c: Color, comptime pt: PieceType) Piece { - return @intToEnum(Piece, (@enumToInt(c) << 3) + @enumToInt(pt)); + return @enumFromInt((@intFromEnum(c) << 3) + @intFromEnum(pt)); } pub inline fn piece_type(self: Piece) PieceType { - return @intToEnum(PieceType, @enumToInt(self) & 0b111); + return @enumFromInt(@intFromEnum(self) & 0b111); } pub inline fn color(self: Piece) Color { - return @intToEnum(Color, (@enumToInt(self) & 0b1000) >> 3); + return @enumFromInt((@intFromEnum(self) & 0b1000) >> 3); } pub inline fn index(self: Piece) u8 { - return @enumToInt(self); + return @intFromEnum(self); } pub inline fn pure_index(self: Piece) usize { - return if (@enumToInt(self) <= 5) @enumToInt(self) else @enumToInt(self) - 2; + return if (@intFromEnum(self) <= 5) @intFromEnum(self) else @intFromEnum(self) - 2; } }; @@ -111,40 +111,40 @@ pub const Square = enum(u8) { // zig fmt: on pub inline fn inc(self: *Square) *Square { - self.* = @intToEnum(Square, @enumToInt(self.*) + 1); + self.* = @enumFromInt(@intFromEnum(self.*) + 1); return self; } pub inline fn add(self: Square, d: Direction) Square { - return @intToEnum(Square, @enumToInt(self) + @enumToInt(d)); + return @enumFromInt(@intFromEnum(self) + @intFromEnum(d)); } pub inline fn sub(self: Square, d: Direction) Square { - return @intToEnum(Square, @enumToInt(self) - @enumToInt(d)); + return @enumFromInt(@intFromEnum(self) - @intFromEnum(d)); } pub inline fn rank(self: Square) Rank { - return @intToEnum(Rank, @enumToInt(self) >> 3); + return @enumFromInt(@intFromEnum(self) >> 3); } pub inline fn file(self: Square) File { - return @intToEnum(File, @enumToInt(self) & 0b111); + return @enumFromInt(@intFromEnum(self) & 0b111); } pub inline fn diagonal(self: Square) i32 { - return @intCast(i32, 7 + @enumToInt(self.rank()) - @enumToInt(self.file())); + return @intCast(7 + @intFromEnum(self.rank()) - @intFromEnum(self.file())); } pub inline fn anti_diagonal(self: Square) i32 { - return @intCast(i32, @enumToInt(self.rank()) + @enumToInt(self.file())); + return @intCast(@intFromEnum(self.rank()) + @intFromEnum(self.file())); } pub inline fn new(f: File, r: Rank) Square { - return @intToEnum(Square, @enumToInt(f) | (@enumToInt(r) << 3)); + return @enumFromInt(@intFromEnum(f) | (@intFromEnum(r) << 3)); } pub inline fn index(self: Square) u8 { - return @intCast(u8, @enumToInt(self)); + return @intCast(@intFromEnum(self)); } }; @@ -175,7 +175,7 @@ pub const File = enum(u8) { HFILE, pub inline fn index(self: File) u8 { - return @enumToInt(self); + return @intFromEnum(self); } }; @@ -190,11 +190,11 @@ pub const Rank = enum(u8) { RANK8, pub inline fn index(self: Rank) u8 { - return @enumToInt(self); + return @intFromEnum(self); } pub inline fn relative_rank(self: Rank, comptime c: Color) Rank { - return if (c == Color.White) self else @intToEnum(Rank, @enumToInt(Rank.RANK8) - @enumToInt(self)); + return if (c == Color.White) self else @enumFromInt(@intFromEnum(Rank.RANK8) - @intFromEnum(self)); } }; @@ -266,7 +266,7 @@ pub fn debug_print_bitboard(b: Bitboard) void { while (i >= 0) : (i -= 8) { var j: i32 = 0; while (j < 8) : (j += 1) { - if ((b >> @intCast(u6, i + j)) & 1 != 0) { + if ((b >> @intCast(i + j)) & 1 != 0) { std.debug.print("1 ", .{}); } else { std.debug.print("0 ", .{}); @@ -283,15 +283,15 @@ pub const k3: Bitboard = 0x0f0f0f0f0f0f0f0f; pub const kf: Bitboard = 0x0101010101010101; pub inline fn popcount(x: Bitboard) i32 { - return @intCast(i32, @popCount(x)); + return @intCast(@popCount(x)); } pub inline fn popcount_usize(x: Bitboard) usize { - return @intCast(usize, @popCount(x)); + return @intCast(@popCount(x)); } pub inline fn lsb(x: Bitboard) i32 { - return @intCast(i32, @ctz(x)); + return @intCast(@ctz(x)); // Ancient machines: //const DEBRUIJN64: [64]i32 = .{ // // zig fmt: off @@ -310,9 +310,9 @@ pub inline fn lsb(x: Bitboard) i32 { } pub inline fn pop_lsb(x: *Bitboard) Square { - var l = lsb(x.*); + const l = lsb(x.*); x.* &= x.* - 1; - return @intToEnum(Square, l); + return @enumFromInt(l); } pub inline fn shift_bitboard(x: Bitboard, comptime d: Direction) Bitboard { @@ -321,12 +321,12 @@ pub inline fn shift_bitboard(x: Bitboard, comptime d: Direction) Bitboard { Direction.South => x >> 8, Direction.NorthNorth => x << 16, Direction.SouthSouth => x >> 16, - Direction.East => (x & ~MaskFile[@enumToInt(File.HFILE)]) << 1, - Direction.West => (x & ~MaskFile[@enumToInt(File.AFILE)]) >> 1, - Direction.NorthEast => (x & ~MaskFile[@enumToInt(File.HFILE)]) << 9, - Direction.NorthWest => (x & ~MaskFile[@enumToInt(File.AFILE)]) << 7, - Direction.SouthEast => (x & ~MaskFile[@enumToInt(File.HFILE)]) >> 7, - Direction.SouthWest => (x & ~MaskFile[@enumToInt(File.AFILE)]) >> 9, + Direction.East => (x & ~MaskFile[@intFromEnum(File.HFILE)]) << 1, + Direction.West => (x & ~MaskFile[@intFromEnum(File.AFILE)]) >> 1, + Direction.NorthEast => (x & ~MaskFile[@intFromEnum(File.HFILE)]) << 9, + Direction.NorthWest => (x & ~MaskFile[@intFromEnum(File.AFILE)]) << 7, + Direction.SouthEast => (x & ~MaskFile[@intFromEnum(File.HFILE)]) >> 7, + Direction.SouthWest => (x & ~MaskFile[@intFromEnum(File.AFILE)]) >> 9, }; } @@ -351,7 +351,7 @@ pub const MoveFlags = enum(u4) { PC_ROOK = 0b1110, pub inline fn promote_type(self: MoveFlags) PieceType { - return switch (@enumToInt(self) & @enumToInt(MoveFlags.PROMOTIONS)) { + return switch (@intFromEnum(self) & @intFromEnum(MoveFlags.PROMOTIONS)) { PR_KNIGHT => PieceType.Knight, PR_BISHOP => PieceType.Bishop, PR_ROOK => PieceType.Rook, @@ -377,19 +377,19 @@ pub const Move = packed struct { to: u6, pub inline fn to_u16(self: Move) u16 { - return @bitCast(u16, self); + return @bitCast(self); } pub inline fn get_flags(self: Move) MoveFlags { - return @intToEnum(MoveFlags, self.flags); + return @enumFromInt(self.flags); } pub inline fn get_from(self: Move) Square { - return @intToEnum(Square, self.from); + return @enumFromInt(self.from); } pub inline fn get_to(self: Move) Square { - return @intToEnum(Square, self.to); + return @enumFromInt(self.to); } pub inline fn empty() Move { @@ -401,19 +401,19 @@ pub const Move = packed struct { } pub inline fn new_from_to(from: Square, to: Square) Move { - return Move{ .flags = 0, .from = @intCast(u6, @enumToInt(from)), .to = @intCast(u6, @enumToInt(to)) }; + return Move{ .flags = 0, .from = @intCast(@intFromEnum(from)), .to = @intCast(@intFromEnum(to)) }; } pub inline fn new_from_to_flag(from: Square, to: Square, flag: MoveFlags) Move { - return Move{ .flags = @enumToInt(flag), .from = @intCast(u6, @enumToInt(from)), .to = @intCast(u6, @enumToInt(to)) }; + return Move{ .flags = @intFromEnum(flag), .from = @intCast(@intFromEnum(from)), .to = @intCast(@intFromEnum(to)) }; } pub fn new_from_string(pos: *position.Position, move: []const u8) Move { var list = std.ArrayList(Move).initCapacity(std.heap.c_allocator, 8) catch unreachable; defer list.deinit(); - var f = @intCast(u6, @enumToInt(Square.new(@intToEnum(File, move[0] - 'a'), @intToEnum(Rank, move[1] - '1')))); - var t = @intCast(u6, @enumToInt(Square.new(@intToEnum(File, move[2] - 'a'), @intToEnum(Rank, move[3] - '1')))); - var p: ?u8 = if (move.len >= 5) move[4] else null; + const f: u6 = @intCast(@intFromEnum(Square.new(@enumFromInt(move[0] - 'a'), @enumFromInt(move[1] - '1')))); + const t: u6 = @intCast(@intFromEnum(Square.new(@enumFromInt(move[2] - 'a'), @enumFromInt(move[3] - '1')))); + const p: ?u8 = if (move.len >= 5) move[4] else null; if (pos.turn == Color.White) { pos.generate_legal_moves(Color.White, &list); } else { diff --git a/src/chess/utils.zig b/src/chess/utils.zig index 5242bca..f6e2ce3 100644 --- a/src/chess/utils.zig +++ b/src/chess/utils.zig @@ -10,8 +10,8 @@ pub const PRNG = struct { x ^= x << 25; x ^= x >> 27; self.seed = x; - var r = @truncate(u64, x); - r = r ^ @truncate(u64, x >> 64); + var r: u64 = @truncate(x); + r = r ^ @as(u64, @truncate(x >> 64)); return r; } @@ -27,7 +27,7 @@ pub const PRNG = struct { pub fn first_index(comptime T: type, arr: []const T, val: T) ?usize { var i: usize = 0; - var end = arr.len; + const end = arr.len; while (i < end) : (i += 1) { if (arr[i] == val) { return i; diff --git a/src/engine/datagen.zig b/src/engine/datagen.zig index 63907cf..3945c6d 100644 --- a/src/engine/datagen.zig +++ b/src/engine/datagen.zig @@ -69,7 +69,7 @@ pub const DatagenSingle = struct { var white_win_count: usize = 0; var black_win_count: usize = 0; var ply: usize = 0; - var random_plies: u64 = 9 + (self.prng.rand64() % 4); + const random_plies: u64 = 9 + (self.prng.rand64() % 4); while (true) : (ply += 1) { if (self.searcher.is_draw(pos, true)) { result = 0.5; @@ -81,7 +81,7 @@ pub const DatagenSingle = struct { } else { pos.generate_legal_moves(types.Color.Black, &movelist); } - var move_size = movelist.items.len; + const move_size = movelist.items.len; if (move_size == 0) { if (pos.turn == types.Color.White) { if (pos.in_check(types.Color.White)) { @@ -102,7 +102,7 @@ pub const DatagenSingle = struct { // play a random move if we're in the first few plies or with a 0.01% chance if (ply < random_plies or self.prng.rand64() % 10000 == 0) { - var move = movelist.items[self.prng.rand64() % move_size]; + const move = movelist.items[self.prng.rand64() % move_size]; if (pos.turn == types.Color.White) { pos.play_move(types.Color.White, move); } else { @@ -113,7 +113,7 @@ pub const DatagenSingle = struct { } movelist.deinit(); - var res: i32 = if (pos.turn == types.Color.White) + const res: i32 = if (pos.turn == types.Color.White) self.searcher.iterative_deepening(pos, types.Color.White, MAX_DEPTH) else -self.searcher.iterative_deepening(pos, types.Color.Black, MAX_DEPTH); @@ -124,8 +124,8 @@ pub const DatagenSingle = struct { var best_move = self.searcher.best_move; - var fen = pos.basic_fen(arena.allocator()); - var in_check = if (pos.turn == types.Color.White) pos.in_check(types.Color.White) else pos.in_check(types.Color.Black); + const fen = pos.basic_fen(arena.allocator()); + const in_check = if (pos.turn == types.Color.White) pos.in_check(types.Color.White) else pos.in_check(types.Color.Black); if (pos.turn == types.Color.White) { pos.play_move(types.Color.White, best_move); @@ -175,7 +175,7 @@ pub const DatagenSingle = struct { continue; } - var gave_check = if (pos.turn == types.Color.White) pos.in_check(types.Color.White) else pos.in_check(types.Color.Black); + const gave_check = if (pos.turn == types.Color.White) pos.in_check(types.Color.White) else pos.in_check(types.Color.Black); if (!in_check and !gave_check and !best_move.is_capture() and !best_move.is_promotion()) { // pretty quiet try fens.append(fen); @@ -192,7 +192,7 @@ pub const DatagenSingle = struct { var i: usize = 0; while (i < fens.items.len) : (i += 1) { try writer.print("{s}", .{fens.items[i]}); - var s = if (result == 0.0) "0.0" else if (result == 1.0) "1.0" else "0.5"; + const s = if (result == 0.0) "0.0" else if (result == 1.0) "1.0" else "0.5"; try writer.print(" | {} | {s}\n", .{ evals.items[i], s }); } self.count += fens.items.len; @@ -206,9 +206,9 @@ pub const DatagenSingle = struct { try self.playGame(); game_count += 1; if (game_count % 50 == 0) { - var elapsed = @intToFloat(f64, self.timer.read()) / std.time.ns_per_s; - var pps = @intToFloat(f64, self.count) / elapsed; - var gps = @intToFloat(f64, game_count) / elapsed; + const elapsed = @as(f64, @floatFromInt(self.timer.read())) / std.time.ns_per_s; + const pps = @as(f64, @floatFromInt(self.count)) / elapsed; + const gps = @as(f64, @floatFromInt(game_count)) / elapsed; std.debug.print("id {}: {} games, {} pos, {d:.4} pos/s, {d:.4} games/s\n", .{ self.id, game_count, self.count, pps, gps }); } @@ -222,9 +222,9 @@ pub const Datagen = struct { datagens: std.ArrayList(DatagenSingle), pub fn new() Datagen { - var prng = std.rand.DefaultPrng.init(blk: { + var prng = std.Random.DefaultPrng.init(blk: { var seed: u64 = undefined; - std.os.getrandom(std.mem.asBytes(&seed)) catch unreachable; + std.posix.getrandom(std.mem.asBytes(&seed)) catch unreachable; break :blk seed; }); const rand = prng.random(); @@ -251,7 +251,7 @@ pub const Datagen = struct { ) catch { std.debug.panic("Unable to open {s}", .{path}); }; - var lock = std.Thread.Mutex{}; + const lock = std.Thread.Mutex{}; self.fileLock = FileLock{ .file = file, .lock = lock }; self.datagens.clearAndFree(); @@ -260,9 +260,9 @@ pub const Datagen = struct { var th: usize = 0; while (th < num_threads) : (th += 1) { - var datagen = DatagenSingle.new(&self.fileLock, &self.prng, th); + const datagen = DatagenSingle.new(&self.fileLock, &self.prng, th); try self.datagens.append(datagen); - var thread = std.Thread.spawn( + const thread = std.Thread.spawn( .{ .stack_size = 64 * 1024 * 1024 }, DatagenSingle.startMany, .{&self.datagens.items[th]}, @@ -279,7 +279,7 @@ pub const Datagen = struct { } pub fn startSingleThreaded(self: *Datagen) !void { - var id: u64 = @intCast(u64, std.time.timestamp()); + const id: u64 = @intCast(std.time.timestamp()); const path = try std.fmt.allocPrint(std.heap.page_allocator, "data_{}.txt", .{id}); const file = std.fs.cwd().createFile( path, @@ -287,7 +287,7 @@ pub const Datagen = struct { ) catch { std.debug.panic("Unable to open {s}", .{path}); }; - var lock = std.Thread.Mutex{}; + const lock = std.Thread.Mutex{}; self.fileLock = FileLock{ .file = file, .lock = lock }; self.datagens.clearAndFree(); diff --git a/src/engine/hce.zig b/src/engine/hce.zig index 99b086a..70d5dae 100644 --- a/src/engine/hce.zig +++ b/src/engine/hce.zig @@ -254,11 +254,11 @@ pub const DynamicEvaluator = struct { var mg: i32 = 0; var eg_material: i32 = 0; var eg_non_mat: i32 = 0; - for (pos.mailbox) |piece, index| { + for (pos.mailbox, 0..) |piece, index| { if (piece == types.Piece.NO_PIECE) { continue; } - var i = piece.piece_type().index(); + const i = piece.piece_type().index(); if (piece.color() == types.Color.White) { mg += Mateiral[i][0]; mg += PSQT[i][0][index ^ 56]; @@ -279,16 +279,16 @@ pub const DynamicEvaluator = struct { }; pub inline fn distance_eval(pos: *position.Position, comptime white_winning: bool) i32 { - var k1 = @intToEnum(types.Square, types.lsb(pos.piece_bitboards[types.Piece.WHITE_KING.index()])); - var k2 = @intToEnum(types.Square, types.lsb(pos.piece_bitboards[types.Piece.BLACK_KING.index()])); + const k1: types.Square = @enumFromInt(types.lsb(pos.piece_bitboards[types.Piece.WHITE_KING.index()])); + const k2: types.Square = @enumFromInt(types.lsb(pos.piece_bitboards[types.Piece.BLACK_KING.index()])); - var r1 = @intCast(i32, k1.rank().index()); - var r2 = @intCast(i32, k2.rank().index()); - var c1 = @intCast(i32, k1.file().index()); - var c2 = @intCast(i32, k2.file().index()); + const r1: i32 = @intCast(k1.rank().index()); + const r2: i32 = @intCast(k2.rank().index()); + const c1: i32 = @intCast(k1.file().index()); + const c2: i32 = @intCast(k2.file().index()); var score: i32 = 0; - var m_dist: i32 = (std.math.absInt(r1 - r2) catch 0) + (std.math.absInt(c1 - c2) catch 0); + const m_dist: i32 = @intCast(@abs(r1 - r2) + @abs(c1 - c2)); if (white_winning) { score -= m_dist * 5; @@ -302,7 +302,7 @@ pub inline fn distance_eval(pos: *position.Position, comptime white_winning: boo } pub fn evaluate_comptime(pos: *position.Position, comptime color: types.Color) i32 { - var phase = pos.phase(); + const phase = pos.phase(); var result: i32 = 0; if (UseNNUE and (phase >= 3 or pos.has_pawns())) { result = evaluate_nnue_comptime(pos, color); @@ -318,7 +318,7 @@ pub fn evaluate_comptime(pos: *position.Position, comptime color: types.Color) i var mg_score: i32 = 0; var eg_score: i32 = 0; - mg_phase = @intCast(i32, phase); + mg_phase = @intCast(phase); if (mg_phase > 24) { mg_phase = 24; } @@ -334,13 +334,13 @@ pub fn evaluate_comptime(pos: *position.Position, comptime color: types.Color) i // White is winning eg_score += distance_eval(pos, true); eg_score += @divTrunc(pos.evaluator.score_eg_non_mat, 2); - eg_score = @max(100, eg_score - @intCast(i32, pos.history[pos.game_ply].fifty)); + eg_score = @max(100, eg_score - @as(i32, @intCast(pos.history[pos.game_ply].fifty))); break; } else if (pos.piece_bitboards[types.Piece.WHITE_KING.index()] == pos.all_pieces(types.Color.White)) { // Black is winning eg_score += distance_eval(pos, false); eg_score += @divTrunc(pos.evaluator.score_eg_non_mat, 2); - eg_score = @min(-100, eg_score + @intCast(i32, pos.history[pos.game_ply].fifty)); + eg_score = @min(-100, eg_score + @as(i32, @intCast(pos.history[pos.game_ply].fifty))); break; } } @@ -350,7 +350,7 @@ pub fn evaluate_comptime(pos: *position.Position, comptime color: types.Color) i break; } - var score = @divTrunc(mg_score * mg_phase + eg_score * eg_phase, 24); + const score = @divTrunc(mg_score * mg_phase + eg_score * eg_phase, 24); if (color == types.Color.White) { result = score; } else { @@ -358,13 +358,13 @@ pub fn evaluate_comptime(pos: *position.Position, comptime color: types.Color) i } } - if (phase <= 5 and std.math.absInt(result) catch 0 >= 16 and is_material_drawish(pos)) { + if (phase <= 5 and @abs(result) >= 16 and is_material_drawish(pos)) { const drawish_factor: i32 = 8; result = @divTrunc(result, drawish_factor); } // Scaling idea from Clover - result = @divTrunc(result * (700 + @divTrunc(pos.phase_material(), 32) - @intCast(i32, pos.history[pos.game_ply].fifty) * 5), 1024); + result = @divTrunc(result * (700 + @divTrunc(pos.phase_material(), 32) - @as(i32, pos.history[pos.game_ply].fifty) * 5), 1024); return result; } @@ -378,22 +378,22 @@ pub inline fn evaluate_nnue_comptime(pos: *position.Position, comptime color: ty } pub inline fn is_material_draw(pos: *position.Position) bool { - var all = pos.all_pieces(types.Color.White) | pos.all_pieces(types.Color.Black); - var kings = pos.piece_bitboards[types.Piece.WHITE_KING.index()] | pos.piece_bitboards[types.Piece.BLACK_KING.index()]; + const all = pos.all_pieces(types.Color.White) | pos.all_pieces(types.Color.Black); + const kings = pos.piece_bitboards[types.Piece.WHITE_KING.index()] | pos.piece_bitboards[types.Piece.BLACK_KING.index()]; if (kings == all) { return true; } - var wb = pos.piece_bitboards[types.Piece.WHITE_BISHOP.index()]; - var bb = pos.piece_bitboards[types.Piece.BLACK_BISHOP.index()]; - var wn = pos.piece_bitboards[types.Piece.WHITE_KNIGHT.index()]; - var bn = pos.piece_bitboards[types.Piece.BLACK_KNIGHT.index()]; + const wb = pos.piece_bitboards[types.Piece.WHITE_BISHOP.index()]; + const bb = pos.piece_bitboards[types.Piece.BLACK_BISHOP.index()]; + const wn = pos.piece_bitboards[types.Piece.WHITE_KNIGHT.index()]; + const bn = pos.piece_bitboards[types.Piece.BLACK_KNIGHT.index()]; - var wbc = types.popcount(wb); - var bbc = types.popcount(bb); - var wnc = types.popcount(wn); - var bnc = types.popcount(bn); + const wbc = types.popcount(wb); + const bbc = types.popcount(bb); + const wnc = types.popcount(wn); + const bnc = types.popcount(bn); // KB vs K if (wbc == 1 and wb | kings == all) { @@ -417,22 +417,22 @@ pub inline fn is_material_draw(pos: *position.Position) bool { } pub inline fn is_material_drawish(pos: *position.Position) bool { - var all = pos.all_pieces(types.Color.White) | pos.all_pieces(types.Color.Black); - var kings = pos.piece_bitboards[types.Piece.WHITE_KING.index()] | pos.piece_bitboards[types.Piece.BLACK_KING.index()]; + const all = pos.all_pieces(types.Color.White) | pos.all_pieces(types.Color.Black); + const kings = pos.piece_bitboards[types.Piece.WHITE_KING.index()] | pos.piece_bitboards[types.Piece.BLACK_KING.index()]; if (kings == all) { return true; } - var wb = pos.piece_bitboards[types.Piece.WHITE_BISHOP.index()]; - var bb = pos.piece_bitboards[types.Piece.BLACK_BISHOP.index()]; - var wn = pos.piece_bitboards[types.Piece.WHITE_KNIGHT.index()]; - var bn = pos.piece_bitboards[types.Piece.BLACK_KNIGHT.index()]; + const wb = pos.piece_bitboards[types.Piece.WHITE_BISHOP.index()]; + const bb = pos.piece_bitboards[types.Piece.BLACK_BISHOP.index()]; + const wn = pos.piece_bitboards[types.Piece.WHITE_KNIGHT.index()]; + const bn = pos.piece_bitboards[types.Piece.BLACK_KNIGHT.index()]; - var wbc = types.popcount(wb); - var bbc = types.popcount(bb); - var wnc = types.popcount(wn); - var bnc = types.popcount(bn); + const wbc = types.popcount(wb); + const bbc = types.popcount(bb); + const wnc = types.popcount(wn); + const bnc = types.popcount(bn); // KN vs K or KNN vs K if (wnc <= 2 and wn | kings == all) { diff --git a/src/engine/interface.zig b/src/engine/interface.zig index 7a2183e..bf750ea 100644 --- a/src/engine/interface.zig +++ b/src/engine/interface.zig @@ -40,7 +40,7 @@ pub const UciInterface = struct { out: while (true) { // The command will probably be less than 16384 characters - var line = try stdin.readUntilDelimiterOrEofAlloc(command_arena.allocator(), '\n', 16384); + const line = try stdin.readUntilDelimiterOrEofAlloc(command_arena.allocator(), '\n', 16384); if (line == null) { break; @@ -48,7 +48,7 @@ pub const UciInterface = struct { const tline = std.mem.trim(u8, line.?, "\r"); - var tokens = std.mem.split(u8, tline, " "); + var tokens = std.mem.tokenizeSequence(u8, tline, " "); var token = tokens.next(); if (token == null) { break; @@ -133,42 +133,42 @@ pub const UciInterface = struct { const value = std.fmt.parseUnsigned(usize, token.?, 10) catch 16; switch (tunable.id) { 0 => { - parameters.LMRWeight = @intToFloat(f64, value) / 1000.0; + parameters.LMRWeight = @as(f64, @floatFromInt(value)) / 1000.0; search.init_lmr(); }, 1 => { - parameters.LMRBias = @intToFloat(f64, value) / 1000.0; + parameters.LMRBias = @as(f64, @floatFromInt(value)) / 1000.0; search.init_lmr(); }, 2 => { - parameters.RFPDepth = @intCast(i32, value); + parameters.RFPDepth = @intCast(value); }, 3 => { - parameters.RFPMultiplier = @intCast(i32, value); + parameters.RFPMultiplier = @intCast(value); }, 4 => { - parameters.RFPImprovingDeduction = @intCast(i32, value); + parameters.RFPImprovingDeduction = @intCast(value); }, 5 => { - parameters.NMPImprovingMargin = @intCast(i32, value); + parameters.NMPImprovingMargin = @intCast(value); }, 6 => { - parameters.NMPBase = @intCast(usize, value); + parameters.NMPBase = @intCast(value); }, 7 => { - parameters.NMPDepthDivisor = @intCast(usize, value); + parameters.NMPDepthDivisor = @intCast(value); }, 8 => { - parameters.NMPBetaDivisor = @intCast(i32, value); + parameters.NMPBetaDivisor = @intCast(value); }, 9 => { - parameters.RazoringBase = @intCast(i32, value); + parameters.RazoringBase = @intCast(value); }, 10 => { - parameters.RazoringMargin = @intCast(i32, value); + parameters.RazoringMargin = @intCast(value); }, 11 => { - parameters.AspirationWindow = @intCast(i32, value); + parameters.AspirationWindow = @intCast(value); }, else => unreachable, } @@ -194,7 +194,7 @@ pub const UciInterface = struct { depth = std.fmt.parseUnsigned(u32, token.?, 10) catch 1; } - depth = std.math.max(depth, 1); + depth = @max(depth, 1); _ = perft.perft_test(&self.position, depth); } else if (std.mem.eql(u8, token.?, "perftdiv")) { @@ -204,7 +204,7 @@ pub const UciInterface = struct { depth = std.fmt.parseUnsigned(u32, token.?, 10) catch 1; } - depth = std.math.max(depth, 1); + depth = @max(depth, 1); if (self.position.turn == types.Color.White) { perft.perft_div(types.Color.White, &self.position, depth); @@ -281,9 +281,8 @@ pub const UciInterface = struct { if (mt <= 0) { mt = 1; } - var t = @intCast(u64, mt); - mytime = t; + mytime = @intCast(mt); } } else if (std.mem.eql(u8, token.?, "btime")) { self.searcher.force_thinking = false; @@ -301,9 +300,7 @@ pub const UciInterface = struct { if (mt <= 0) { mt = 1; } - var t = @intCast(u64, mt); - - mytime = t; + mytime = @intCast(mt); } } else if (std.mem.eql(u8, token.?, "winc")) { self.searcher.force_thinking = false; @@ -345,7 +342,7 @@ pub const UciInterface = struct { } if (movetime != null) { - const overhead = 25; + const overhead: u64 = 25; if (mytime != null) { var inc: u64 = 0; if (myinc != null) { @@ -400,7 +397,7 @@ pub const UciInterface = struct { break; } - var move = types.Move.new_from_string(&self.position, token.?); + const move = types.Move.new_from_string(&self.position, token.?); if (self.position.turn == types.Color.White) { self.position.play_move(types.Color.White, move); @@ -413,23 +410,23 @@ pub const UciInterface = struct { } } } else if (std.mem.eql(u8, token.?, "fen")) { - tokens = std.mem.split(u8, tokens.rest(), " moves "); - var fen = tokens.next(); + tokens = std.mem.tokenizeSequence(u8, tokens.rest(), " moves "); + const fen = tokens.next(); if (fen != null) { self.position.set_fen(fen.?); self.searcher.hash_history.clearRetainingCapacity(); self.searcher.hash_history.append(self.position.hash) catch {}; - var afterfen = tokens.next(); + const afterfen = tokens.next(); if (afterfen != null) { - tokens = std.mem.split(u8, afterfen.?, " "); + tokens = std.mem.tokenizeSequence(u8, afterfen.?, " "); while (true) { token = tokens.next(); if (token == null) { break; } - var move = types.Move.new_from_string(&self.position, token.?); + const move = types.Move.new_from_string(&self.position, token.?); if (self.position.turn == types.Color.White) { self.position.play_move(types.Color.White, move); @@ -464,7 +461,7 @@ fn startSearch(searcher: *search.Searcher, pos: *position.Position, movetime: us } else { pos.generate_legal_moves(types.Color.Black, &movelist); } - var move_size = movelist.items.len; + const move_size = movelist.items.len; if (move_size == 1) { depth = 1; } diff --git a/src/engine/movepick.zig b/src/engine/movepick.zig index 7218ed1..d8f67c3 100644 --- a/src/engine/movepick.zig +++ b/src/engine/movepick.zig @@ -19,7 +19,7 @@ pub const SortCounterMove: i32 = 600_000; pub fn scoreMoves(searcher: *search.Searcher, pos: *position.Position, list: *std.ArrayList(types.Move), hashmove: types.Move, comptime is_null: bool) std.ArrayList(i32) { var res: std.ArrayList(i32) = std.ArrayList(i32).initCapacity(std.heap.c_allocator, list.items.len) catch unreachable; - var hm = hashmove.to_u16(); + const hm = hashmove.to_u16(); for (list.items) |move_| { var move: *const types.Move = &move_; @@ -37,7 +37,7 @@ pub fn scoreMoves(searcher: *search.Searcher, pos: *position.Position, list: *st if (pos.mailbox[move.to] == types.Piece.NO_PIECE) { score += SortWinningCapture + MVV_LVA[0][0]; } else { - var see_value = see.see_threshold(pos, move.*, -90); + const see_value = see.see_threshold(pos, move.*, -90); score += MVV_LVA[pos.mailbox[move.to].piece_type().index()][pos.mailbox[move.from].piece_type().index()]; @@ -57,16 +57,16 @@ pub fn scoreMoves(searcher: *search.Searcher, pos: *position.Position, list: *st } } } else { - var last = if (searcher.ply > 0) searcher.move_history[searcher.ply - 1] else types.Move.empty(); + const last = if (searcher.ply > 0) searcher.move_history[searcher.ply - 1] else types.Move.empty(); if (searcher.killer[searcher.ply][0].to_u16() == move.to_u16()) { score += SortKiller1; } else if (searcher.killer[searcher.ply][1].to_u16() == move.to_u16()) { score += SortKiller2; - } else if (searcher.ply >= 1 and searcher.counter_moves[@enumToInt(pos.turn)][last.from][last.to].to_u16() == move.to_u16()) { + } else if (searcher.ply >= 1 and searcher.counter_moves[@intFromEnum(pos.turn)][last.from][last.to].to_u16() == move.to_u16()) { score += SortCounterMove; } else { score += SortQuiet; - score += searcher.history[@enumToInt(pos.turn)][move.from][move.to]; + score += searcher.history[@intFromEnum(pos.turn)][move.from][move.to]; if (!is_null and searcher.ply >= 1) { const plies: [3]usize = .{ 0, 1, 3 }; for (plies) |plies_ago| { @@ -89,7 +89,7 @@ pub fn scoreMoves(searcher: *search.Searcher, pos: *position.Position, list: *st } pub inline fn getNextBest(list: *std.ArrayList(types.Move), evals: *std.ArrayList(i32), i: usize) types.Move { - var move_size = list.items.len; + const move_size = list.items.len; var j = i + 1; while (j < move_size) : (j += 1) { if (evals.items[i] < evals.items[j]) { diff --git a/src/engine/nnue.zig b/src/engine/nnue.zig index e280c0d..ea7d8cd 100644 --- a/src/engine/nnue.zig +++ b/src/engine/nnue.zig @@ -25,8 +25,8 @@ pub fn nnue_index(piece: types.Piece, sq: types.Square) WhiteBlackPair { const p: usize = piece.piece_type().index(); const c: types.Color = piece.color(); - const white = @intCast(usize, @enumToInt(c)) * 64 * 6 + p * 64 + @intCast(usize, sq.index()); - const black = @intCast(usize, @enumToInt(c.invert())) * 64 * 6 + p * 64 + @intCast(usize, sq.index() ^ 56); + const white = @as(usize, @intCast(@intFromEnum(c))) * 64 * 6 + p * 64 + @as(usize, @intCast(sq.index())); + const black = @as(usize, @intCast(@intFromEnum(c.invert()))) * 64 * 6 + p * 64 + @as(usize, @intCast(sq.index() ^ 56)); return WhiteBlackPair{ .white = white * weights.HIDDEN_SIZE, @@ -43,7 +43,7 @@ pub inline fn clipped_relu(input: i16) i32 { } } -pub const Accumulator = packed struct { +pub const Accumulator = extern struct { white: [weights.HIDDEN_SIZE]i16, black: [weights.HIDDEN_SIZE]i16, @@ -93,12 +93,12 @@ pub const NNUE = struct { self.stack_index = 0; self.accumulator_stack[0].clear(); - for (pos.mailbox) |pc, i| { + for (pos.mailbox, 0..) |pc, i| { if (pc == types.Piece.NO_PIECE) { continue; } - self.toggle(true, pc, @intToEnum(types.Square, i)); + self.toggle(true, pc, @enumFromInt(i)); } } diff --git a/src/engine/search.zig b/src/engine/search.zig index 052662b..a719a32 100644 --- a/src/engine/search.zig +++ b/src/engine/search.zig @@ -19,8 +19,8 @@ pub fn init_lmr() void { while (depth < 64) : (depth += 1) { var moves: usize = 1; while (moves < 64) : (moves += 1) { - const a = parameters.LMRWeight * std.math.ln(@intToFloat(f32, depth)) * std.math.ln(@intToFloat(f32, moves)) + parameters.LMRBias; - QuietLMR[depth][moves] = @floatToInt(i32, @floor(a)); + const a = parameters.LMRWeight * std.math.log(f32, std.math.e, @floatFromInt(depth)) * std.math.log(f32, std.math.e, @as(f32, @floatFromInt(moves))) + parameters.LMRBias; + QuietLMR[depth][moves] = @intFromFloat(@floor(a)); } } } @@ -159,7 +159,7 @@ pub const Searcher = struct { } pub inline fn should_not_continue(self: *Searcher, factor: f32) bool { - return self.stop or (self.thread_id == 0 and self.iterative_deepening_depth > self.min_depth and ((self.soft_max_nodes != null and self.nodes >= self.soft_max_nodes.?) or (!self.force_thinking and self.timer.read() / std.time.ns_per_ms >= @min(self.max_millis, @floatToInt(u64, @floor(@intToFloat(f32, self.ideal_time) * factor)))))); + return self.stop or (self.thread_id == 0 and self.iterative_deepening_depth > self.min_depth and ((self.soft_max_nodes != null and self.nodes >= self.soft_max_nodes.?) or (!self.force_thinking and self.timer.read() / std.time.ns_per_ms >= @min(self.max_millis, @as(u64, @intFromFloat(@floor(@as(f64, @floatFromInt(self.ideal_time)) * factor))))))); } pub fn iterative_deepening(self: *Searcher, pos: *position.Position, comptime color: types.Color, max_depth: ?u8) i32 { @@ -221,7 +221,7 @@ pub const Searcher = struct { self.nmp_min_ply = 0; - var val = self.negamax(pos, color, depth, alpha, beta, false, NodeType.Root, false); + const val = self.negamax(pos, color, depth, alpha, beta, false, NodeType.Root, false); if (depth > 1) { self.stop_helpers(); @@ -279,9 +279,9 @@ pub const Searcher = struct { self.timer.read() / std.time.ns_per_ms, }) catch {}; - if ((std.math.absInt(score) catch 0) >= (hce.MateScore - hce.MaxMate)) { + if (@abs(score) >= (hce.MateScore - hce.MaxMate)) { outW.print("mate {} pv", .{ - (@divTrunc(hce.MateScore - (std.math.absInt(score) catch 0), 2) + 1) * @as(i32, if (score > 0) 1 else -1), + (@divTrunc(hce.MateScore - @as(i32, @intCast(@abs(score))), 2) + 1) * @as(i32, if (score > 0) 1 else -1), }) catch {}; if (bound == MAX_PLY - 1) { bound = depth + 2; @@ -307,7 +307,7 @@ pub const Searcher = struct { out.flush() catch {}; } - var factor: f32 = @max(0.5, 1.1 - 0.03 * @intToFloat(f32, stability)); + var factor: f32 = @max(0.5, 1.1 - 0.03 * @as(f32, @floatFromInt(stability))); if (score - prev_score > parameters.AspirationWindow) { factor *= 1.1; @@ -348,12 +348,12 @@ pub const Searcher = struct { } if (self.hash_history.items.len > 1) { - var index: i16 = @intCast(i16, self.hash_history.items.len) - 3; - const limit: i16 = index - @intCast(i16, pos.history[pos.game_ply].fifty) - 1; + var index: i16 = @as(i16, @intCast(self.hash_history.items.len)) - 3; + const limit: i16 = @intCast(index - @as(i32, pos.history[pos.game_ply].fifty) - 1); var count: u8 = 0; const threshold: u8 = if (threefold) 2 else 1; while (index >= limit and index >= 0) { - if (self.hash_history.items[@intCast(usize, index)] == pos.hash) { + if (self.hash_history.items[@intCast(index)] == pos.hash) { count += 1; if (count >= threshold) { return true; @@ -369,7 +369,7 @@ pub const Searcher = struct { pub fn helpers(self: *Searcher, pos: *position.Position, comptime color: types.Color, depth_: usize, alpha_: i32, beta_: i32) void { var i: usize = 0; while (i < NUM_THREADS) : (i += 1) { - var id: usize = i + 1; + const id: usize = i + 1; if (threads.items[i] != null) { threads.items[i].?.join(); } @@ -422,7 +422,7 @@ pub const Searcher = struct { var alpha = alpha_; var beta = beta_; var depth = depth_; - comptime var opp_color = if (color == types.Color.White) types.Color.Black else types.Color.White; + const opp_color = comptime if (color == types.Color.White) types.Color.Black else types.Color.White; self.pv_size[self.ply] = 0; @@ -436,15 +436,15 @@ pub const Searcher = struct { self.seldepth = @max(self.seldepth, self.ply); - var is_root = node == NodeType.Root; - var on_pv: bool = node != NodeType.NonPV; + const is_root = node == NodeType.Root; + const on_pv: bool = node != NodeType.NonPV; // Step 1.3: Ply Overflow Check if (self.ply == MAX_PLY) { return hce.evaluate_comptime(pos, color); } - var in_check = pos.in_check(color); + const in_check = pos.in_check(color); // Step 4.1: Check Extension (moved up) if (in_check) { @@ -458,8 +458,8 @@ pub const Searcher = struct { // Step 1.4: Mate-distance pruning if (!is_root) { - var r_alpha = @max(-hce.MateScore + @intCast(i32, self.ply), alpha); - var r_beta = @min(hce.MateScore - @intCast(i32, self.ply) - 1, beta); + const r_alpha = @max(-hce.MateScore + @as(i32, @intCast(self.ply)), alpha); + const r_beta = @min(hce.MateScore - @as(i32, @intCast(self.ply)) - 1, beta); if (r_alpha >= r_beta) { return r_alpha; @@ -477,15 +477,15 @@ pub const Searcher = struct { var hashmove = types.Move.empty(); var tthit = false; var tt_eval: i32 = 0; - var entry = tt.GlobalTT.get(pos.hash); + const entry = tt.GlobalTT.get(pos.hash); if (entry != null) { tthit = true; tt_eval = entry.?.eval; if (tt_eval > hce.MateScore - hce.MaxMate and tt_eval <= hce.MateScore) { - tt_eval -= @intCast(i32, self.ply); + tt_eval -= @as(i32, @intCast(self.ply)); } else if (tt_eval < -hce.MateScore + hce.MaxMate and tt_eval >= -hce.MateScore) { - tt_eval += @intCast(i32, self.ply); + tt_eval += @as(i32, @intCast(self.ply)); } hashmove = entry.?.bestmove; if (is_root) { @@ -513,16 +513,15 @@ pub const Searcher = struct { } } - var static_eval: i32 = if (in_check) -hce.MateScore + @intCast(i32, self.ply) else if (tthit) entry.?.eval else if (is_null) -self.eval_history[self.ply - 1] else if (self.exclude_move[self.ply].to_u16() != 0) self.eval_history[self.ply] else hce.evaluate_comptime(pos, color); + const static_eval: i32 = if (in_check) -hce.MateScore + @as(i32, @intCast(self.ply)) else if (tthit) entry.?.eval else if (is_null) -self.eval_history[self.ply - 1] else if (self.exclude_move[self.ply].to_u16() != 0) self.eval_history[self.ply] else hce.evaluate_comptime(pos, color); var best_score: i32 = static_eval; var low_estimate: i32 = -hce.MateScore - 1; self.eval_history[self.ply] = static_eval; - var improving = !in_check and self.ply >= 2 and static_eval > self.eval_history[self.ply - 2]; - - var has_non_pawns = pos.has_non_pawns(); + const improving = !in_check and self.ply >= 2 and static_eval > self.eval_history[self.ply - 2]; + const has_non_pawns = pos.has_non_pawns(); var last_move = if (self.ply > 0) self.move_history[self.ply - 1] else types.Move.empty(); var last_last_last_move = if (self.ply > 2) self.move_history[self.ply - 3] else types.Move.empty(); @@ -539,8 +538,8 @@ pub const Searcher = struct { low_estimate = if (!tthit or entry.?.flag == tt.Bound.Lower) static_eval else entry.?.eval; // Step 4.1: Reverse Futility Pruning - if (std.math.absInt(beta) catch 0 < hce.MateScore - hce.MaxMate and depth <= parameters.RFPDepth) { - var n = @intCast(i32, depth) * parameters.RFPMultiplier; + if (@abs(beta) < hce.MateScore - hce.MaxMate and depth <= parameters.RFPDepth) { + var n = @as(i32, @intCast(depth)) * parameters.RFPMultiplier; if (improving) { n -= parameters.RFPImprovingDeduction; } @@ -557,7 +556,7 @@ pub const Searcher = struct { // Step 4.2: Null move pruning if (!is_null and depth >= 3 and self.ply >= self.nmp_min_ply and nmp_static_eval >= beta and has_non_pawns) { var r = parameters.NMPBase + depth / parameters.NMPDepthDivisor; - r += @intCast(usize, @min(4, @divTrunc((static_eval - beta), parameters.NMPBetaDivisor))); + r += @intCast(@min(4, @divTrunc((static_eval - beta), parameters.NMPBetaDivisor))); r = @min(r, depth); self.ply += 1; @@ -579,9 +578,9 @@ pub const Searcher = struct { return null_score; } - self.nmp_min_ply = self.ply + @intCast(u32, (depth - r) * 3 / 4); + self.nmp_min_ply = @intCast(self.ply + (depth - r) * 3 / 4); - var verif_score = self.negamax(pos, color, depth - r, beta - 1, beta, false, NodeType.NonPV, false); + const verif_score = self.negamax(pos, color, depth - r, beta - 1, beta, false, NodeType.NonPV, false); self.nmp_min_ply = 0; @@ -596,7 +595,7 @@ pub const Searcher = struct { } // Step 4.3: Razoring - if (depth <= 3 and static_eval - parameters.RazoringBase + parameters.RazoringMargin * @intCast(i32, depth) < alpha) { + if (depth <= 3 and static_eval - parameters.RazoringBase + parameters.RazoringMargin * @as(i32, @intCast(depth)) < alpha) { return self.quiescence_search(pos, color, alpha, beta); } } @@ -607,7 +606,7 @@ pub const Searcher = struct { var movelist = std.ArrayList(types.Move).initCapacity(std.heap.c_allocator, 64) catch unreachable; defer movelist.deinit(); pos.generate_legal_moves(color, &movelist); - var move_size = movelist.items.len; + const move_size = movelist.items.len; var quiet_moves = std.ArrayList(types.Move).initCapacity(std.heap.c_allocator, 32) catch unreachable; defer quiet_moves.deinit(); @@ -618,7 +617,7 @@ pub const Searcher = struct { if (move_size == 0) { if (in_check) { // Checkmate - return -hce.MateScore + @intCast(i32, self.ply); + return -hce.MateScore + @as(i32, @intCast(self.ply)); } else { // Stalemate return 0; @@ -631,7 +630,7 @@ pub const Searcher = struct { // Step 5.3: Move Iteration var best_move = types.Move.empty(); - best_score = -hce.MateScore + @intCast(i32, self.ply); + best_score = -hce.MateScore + @as(i32, @intCast(self.ply)); var skip_quiet = false; @@ -645,15 +644,15 @@ pub const Searcher = struct { continue; } - var is_capture = move.is_capture(); - var is_killer = move.to_u16() == self.killer[self.ply][0].to_u16() or move.to_u16() == self.killer[self.ply][1].to_u16(); + const is_capture = move.is_capture(); + const is_killer = move.to_u16() == self.killer[self.ply][0].to_u16() or move.to_u16() == self.killer[self.ply][1].to_u16(); if (!is_capture) { quiet_moves.append(move) catch unreachable; quiet_count += 1; } - var is_important = is_killer or move.is_promotion(); + const is_important = is_killer or move.is_promotion(); if (skip_quiet and !is_capture and !is_important) { continue; @@ -696,11 +695,11 @@ pub const Searcher = struct { and entry.?.depth >= depth - 3 ) { // zig fmt: on - var margin = @intCast(i32, depth); - var singular_beta = @max(tt_eval - margin, -hce.MateScore + hce.MaxMate); + const margin: i32 = @intCast(depth); + const singular_beta = @max(tt_eval - margin, -hce.MateScore + hce.MaxMate); self.exclude_move[self.ply] = hashmove; - var singular_score = self.negamax(pos, color, (depth - 1) / 2, singular_beta - 1, singular_beta, true, NodeType.NonPV, cutnode); + const singular_score = self.negamax(pos, color, (depth - 1) / 2, singular_beta - 1, singular_beta, true, NodeType.NonPV, cutnode); self.exclude_move[self.ply] = types.Move.empty(); if (singular_score < singular_beta) { extension = 1; @@ -718,7 +717,7 @@ pub const Searcher = struct { } } - var new_depth = @intCast(usize, @intCast(i32, depth) + extension - 1); + const new_depth: usize = @intCast(@as(i32, @intCast(depth)) + extension - 1); self.move_history[self.ply] = move; self.moved_piece_history[self.ply] = pos.mailbox[move.from]; @@ -729,7 +728,7 @@ pub const Searcher = struct { tt.GlobalTT.prefetch(pos.hash); var score: i32 = 0; - var min_lmr_move: usize = if (on_pv) 5 else 3; + const min_lmr_move: usize = if (on_pv) 5 else 3; const is_winning_capture = is_capture and evallist.items[index] >= movepick.SortWinningCapture - 200; var do_full_search = false; if (on_pv and legals == 1) { @@ -751,9 +750,9 @@ pub const Searcher = struct { reduction += 1; } - reduction -= @divTrunc(self.history[@enumToInt(color)][move.from][move.to], 6144); + reduction -= @divTrunc(self.history[@intFromEnum(color)][move.from][move.to], 6144); - var rd: usize = @intCast(usize, std.math.clamp(@intCast(i32, new_depth) - reduction, 1, new_depth + 1)); + const rd: usize = @intCast(std.math.clamp(@as(i32, @intCast(new_depth)) - reduction, 1, @as(i32, @intCast(new_depth + 1)))); // Step 5.7: Principal-Variation-Search (PVS) score = -self.negamax(pos, opp_color, rd, -alpha - 1, -alpha, false, NodeType.NonPV, true); @@ -791,7 +790,7 @@ pub const Searcher = struct { if (!is_null) { self.pv[self.ply][0] = move; - std.mem.copy(types.Move, self.pv[self.ply][1..(self.pv_size[self.ply + 1] + 1)], self.pv[self.ply + 1][0..(self.pv_size[self.ply + 1])]); + @memcpy(self.pv[self.ply][1..(self.pv_size[self.ply + 1] + 1)], self.pv[self.ply + 1][0..(self.pv_size[self.ply + 1])]); self.pv_size[self.ply] = self.pv_size[self.ply + 1] + 1; } @@ -812,22 +811,22 @@ pub const Searcher = struct { self.killer[self.ply][1] = temp; } - const adj = @min(1536, @intCast(i32, if (static_eval <= alpha) depth + 1 else depth) * 384 - 384); + const adj = @min(1536, @as(i32, @intCast(if (static_eval <= alpha) depth + 1 else depth)) * 384 - 384); if (!is_null and self.ply >= 1) { - var last = self.move_history[self.ply - 1]; - self.counter_moves[@enumToInt(color)][last.from][last.to] = best_move; + const last = self.move_history[self.ply - 1]; + self.counter_moves[@intFromEnum(color)][last.from][last.to] = best_move; } const b = best_move.to_u16(); const max_history: i32 = 16384; for (quiet_moves.items) |m| { const is_best = m.to_u16() == b; - const hist = self.history[@enumToInt(color)][m.from][m.to] * adj; + const hist = self.history[@intFromEnum(color)][m.from][m.to] * adj; if (is_best) { - self.history[@enumToInt(color)][m.from][m.to] += adj - @divTrunc(hist, max_history); + self.history[@intFromEnum(color)][m.from][m.to] += adj - @divTrunc(hist, max_history); } else { - self.history[@enumToInt(color)][m.from][m.to] += -adj - @divTrunc(hist, max_history); + self.history[@intFromEnum(color)][m.from][m.to] += -adj - @divTrunc(hist, max_history); } // Continuation History @@ -852,13 +851,13 @@ pub const Searcher = struct { // >> Step 7: Transposition Table Update if (!skip_quiet and self.exclude_move[self.ply].to_u16() == 0) { - var tt_flag = if (best_score >= beta) tt.Bound.Lower else if (alpha != alpha_) tt.Bound.Exact else tt.Bound.Upper; + const tt_flag = if (best_score >= beta) tt.Bound.Lower else if (alpha != alpha_) tt.Bound.Exact else tt.Bound.Upper; tt.GlobalTT.set(tt.Item{ .eval = best_score, .bestmove = best_move, .flag = tt_flag, - .depth = @intCast(u8, depth), + .depth = @intCast(depth), .hash = pos.hash, .age = tt.GlobalTT.age, }); @@ -869,8 +868,8 @@ pub const Searcher = struct { pub fn quiescence_search(self: *Searcher, pos: *position.Position, comptime color: types.Color, alpha_: i32, beta_: i32) i32 { var alpha = alpha_; - var beta = beta_; - comptime var opp_color = if (color == types.Color.White) types.Color.Black else types.Color.White; + const beta = beta_; + const opp_color = comptime if (color == types.Color.White) types.Color.Black else types.Color.White; // >> Step 1: Preparation @@ -894,11 +893,11 @@ pub const Searcher = struct { self.nodes += 1; - var in_check = pos.in_check(color); + const in_check = pos.in_check(color); // >> Step 2: Prunings - var best_score = -hce.MateScore + @intCast(i32, self.ply); + var best_score = -hce.MateScore + @as(i32, @intCast(self.ply)); var static_eval = best_score; if (!in_check) { static_eval = hce.evaluate_comptime(pos, color); @@ -915,7 +914,7 @@ pub const Searcher = struct { // >> Step 3: TT Probe var hashmove = types.Move.empty(); - var entry = tt.GlobalTT.get(pos.hash); + const entry = tt.GlobalTT.get(pos.hash); if (entry != null) { hashmove = entry.?.bestmove; @@ -937,12 +936,12 @@ pub const Searcher = struct { pos.generate_legal_moves(color, &movelist); if (movelist.items.len == 0) { // Checkmated - return -hce.MateScore + @intCast(i32, self.ply); + return -hce.MateScore + @as(i32, @intCast(self.ply)); } } else { pos.generate_q_moves(color, &movelist); } - var move_size = movelist.items.len; + const move_size = movelist.items.len; // Step 4.2: Q Move Ordering var evallist = movepick.scoreMoves(self, pos, &movelist, hashmove, false); @@ -953,11 +952,11 @@ pub const Searcher = struct { while (index < move_size) : (index += 1) { var move = movepick.getNextBest(&movelist, &evallist, index); - var is_capture = move.is_capture(); + const is_capture = move.is_capture(); // Step 4.4: SEE Pruning if (is_capture and index > 0) { - var see_score = evallist.items[index]; + const see_score = evallist.items[index]; if (see_score < movepick.SortWinningCapture - 2048) { continue; @@ -969,7 +968,7 @@ pub const Searcher = struct { self.ply += 1; pos.play_move(color, move); tt.GlobalTT.prefetch(pos.hash); - var score = -self.quiescence_search(pos, opp_color, -beta, -alpha); + const score = -self.quiescence_search(pos, opp_color, -beta, -alpha); self.ply -= 1; pos.undo_move(color, move); diff --git a/src/engine/see.zig b/src/engine/see.zig index c816ef1..4658032 100644 --- a/src/engine/see.zig +++ b/src/engine/see.zig @@ -12,8 +12,8 @@ pub fn see_score(pos: *position.Position, move: types.Move) i32 { var defenders: types.Bitboard = 0; var piece_bb: types.Bitboard = 0; - var to_sq = move.get_to(); - var all_pieces = pos.all_pieces(types.Color.White) | pos.all_pieces(types.Color.Black); + const to_sq = move.get_to(); + const all_pieces = pos.all_pieces(types.Color.White) | pos.all_pieces(types.Color.Black); var gains: [16]i32 = undefined; var opp = pos.turn.invert(); var blockers = all_pieces & ~types.SquareIndexBB[move.to]; @@ -30,12 +30,12 @@ pub fn see_score(pos: *position.Position, move: types.Move) i32 { defenders = pos.all_pieces(types.Color.Black) & blockers; } var pt = types.PieceType.Pawn.index(); - var ending = types.PieceType.King.index(); + const ending = types.PieceType.King.index(); while (pt <= ending) : (pt += 1) { last_piece_pts = SeeWeight[pt]; - piece_bb = (if (pt == 0) (if (opp == types.Color.White) tables.get_pawn_attacks(types.Color.Black, to_sq) else tables.get_pawn_attacks(types.Color.White, to_sq)) else (tables.get_attacks(@intToEnum(types.PieceType, pt), to_sq, blockers))) & defenders & (pos.piece_bitboards[pt] | pos.piece_bitboards[pt + 8]); + piece_bb = (if (pt == 0) (if (opp == types.Color.White) tables.get_pawn_attacks(types.Color.Black, to_sq) else tables.get_pawn_attacks(types.Color.White, to_sq)) else (tables.get_attacks(@enumFromInt(pt), to_sq, blockers))) & defenders & (pos.piece_bitboards[pt] | pos.piece_bitboards[pt + 8]); if (piece_bb != 0) { - blockers &= ~(types.SquareIndexBB[@intCast(usize, types.lsb(piece_bb))]); + blockers &= ~(types.SquareIndexBB[@intCast(types.lsb(piece_bb))]); opp = opp.invert(); continue :outer; } @@ -55,10 +55,10 @@ pub fn see_score(pos: *position.Position, move: types.Move) i32 { // Logic https://github.com/TerjeKir/weiss pub fn see_threshold(pos: *position.Position, move: types.Move, threshold: i32) bool { - var from = move.from; - var to = move.to; - var attacker = pos.mailbox[from].piece_type().index(); - var victim = pos.mailbox[to].piece_type().index(); + const from = move.from; + const to = move.to; + const attacker = pos.mailbox[from].piece_type().index(); + const victim = pos.mailbox[to].piece_type().index(); var swap = SeeWeight[victim] - threshold; if (swap < 0) { return false; @@ -68,13 +68,13 @@ pub fn see_threshold(pos: *position.Position, move: types.Move, threshold: i32) return true; } - var all = pos.all_pieces(types.Color.White) | pos.all_pieces(types.Color.Black); + const all = pos.all_pieces(types.Color.White) | pos.all_pieces(types.Color.Black); var occ = (all ^ types.SquareIndexBB[from]) | types.SquareIndexBB[to]; - var attackers = (pos.attackers_from(types.Color.White, @intToEnum(types.Square, to), occ) | pos.attackers_from(types.Color.Black, @intToEnum(types.Square, to), occ)) & occ; + var attackers = (pos.attackers_from(types.Color.White, @as(types.Square, @enumFromInt(to)), occ) | pos.attackers_from(types.Color.Black, @as(types.Square, @enumFromInt(to)), occ)) & occ; - var bishops = pos.diagonal_sliders(types.Color.White) | pos.diagonal_sliders(types.Color.Black); - var rooks = pos.orthogonal_sliders(types.Color.White) | pos.orthogonal_sliders(types.Color.Black); + const bishops = pos.diagonal_sliders(types.Color.White) | pos.diagonal_sliders(types.Color.Black); + const rooks = pos.orthogonal_sliders(types.Color.White) | pos.orthogonal_sliders(types.Color.Black); var stm = pos.mailbox[from].color().invert(); @@ -116,12 +116,12 @@ pub fn see_threshold(pos: *position.Position, move: types.Move, threshold: i32) break; } - occ ^= types.SquareIndexBB[@intCast(usize, types.lsb(my_attackers & (pos.piece_bitboards[pt] | pos.piece_bitboards[pt + 8])))]; + occ ^= types.SquareIndexBB[@intCast(types.lsb(my_attackers & (pos.piece_bitboards[pt] | pos.piece_bitboards[pt + 8])))]; if (pt == 0 or pt == 2 or pt == 4) { - attackers |= tables.get_bishop_attacks(@intToEnum(types.Square, to), occ) & bishops; + attackers |= tables.get_bishop_attacks(@as(types.Square, @enumFromInt(to)), occ) & bishops; } else if (pt == 3 or pt == 4) { - attackers |= tables.get_rook_attacks(@intToEnum(types.Square, to), occ) & rooks; + attackers |= tables.get_rook_attacks(@as(types.Square, @enumFromInt(to)), occ) & rooks; } } diff --git a/src/engine/tt.zig b/src/engine/tt.zig index 2f6cf2e..042ed3a 100644 --- a/src/engine/tt.zig +++ b/src/engine/tt.zig @@ -68,12 +68,12 @@ pub const TranspositionTable = struct { } pub inline fn index(self: *TranspositionTable, hash: u64) u64 { - return @intCast(u64, @intCast(u128, hash) * @intCast(u128, self.size) >> 64); + return @intCast(@as(u128, hash) * @as(u128, self.size) >> 64); } pub inline fn set(self: *TranspositionTable, entry: Item) void { - var p = &self.data.items[self.index(entry.hash)]; - var p_val: Item = @ptrCast(*Item, p).*; + const p = &self.data.items[self.index(entry.hash)]; + const p_val: Item = @as(*const Item, @ptrCast(p)).*; // We overwrite entry if: // 1. It's empty // 2. New entry is exact @@ -82,8 +82,8 @@ pub const TranspositionTable = struct { // 5. Previous entry is from same search but has lower depth if (p.* == 0 or entry.flag == Bound.Exact or p_val.age != self.age or p_val.hash != entry.hash or p_val.depth <= entry.depth + 4) { //_ = @atomicRmw(i128, p, .Xchg, @ptrCast(*const i128, @alignCast(@alignOf(i128), &entry)).*, .Acquire); - _ = @atomicRmw(i64, @intToPtr(*i64, @ptrToInt(p)), .Xchg, @intToPtr(*const i64, @ptrToInt(&entry)).*, .Acquire); - _ = @atomicRmw(i64, @intToPtr(*i64, @ptrToInt(p) + 8), .Xchg, @intToPtr(*const i64, @ptrToInt(&entry) + 8).*, .Acquire); + _ = @atomicRmw(i64, @as(*i64, @ptrFromInt(@intFromPtr(p))), .Xchg, @as(*const i64, @ptrFromInt(@intFromPtr(&entry))).*, .acquire); + _ = @atomicRmw(i64, @as(*i64, @ptrFromInt(@intFromPtr(p) + 8)), .Xchg, @as(*const i64, @ptrFromInt(@intFromPtr(&entry) + 8)).*, .acquire); } } @@ -98,7 +98,7 @@ pub const TranspositionTable = struct { pub inline fn get(self: *TranspositionTable, hash: u64) ?Item { // self.data.items[hash % self.size].lock.lock(); // defer self.data.items[hash % self.size].lock.unlock(); - var entry = @ptrCast(*Item, &self.data.items[self.index(hash)]); + const entry: *Item = @ptrCast(&self.data.items[self.index(hash)]); if (entry.flag != Bound.None and entry.hash == hash) { return entry.*; } diff --git a/src/engine/weights.zig b/src/engine/weights.zig index fcfd167..63b6cf7 100644 --- a/src/engine/weights.zig +++ b/src/engine/weights.zig @@ -1,6 +1,6 @@ const std = @import("std"); -const NNUE_SOURCE = @embedFile("../../nets/bingshan.nnue"); +const NNUE_SOURCE = @embedFile("net"); pub const INPUT_SIZE: usize = 768; pub const HIDDEN_SIZE: usize = 512; diff --git a/src/main.zig b/src/main.zig index 8aa5401..c756eeb 100644 --- a/src/main.zig +++ b/src/main.zig @@ -23,7 +23,7 @@ pub fn main() anyerror!void { var args = try std.process.argsWithAllocator(std.heap.page_allocator); _ = args.next(); - var second = args.next(); + const second = args.next(); if (second != null) { if (std.mem.eql(u8, second.?, "bench")) { try bench.bench(); diff --git a/src/tests.zig b/src/tests.zig index 6368104..fa4284f 100644 --- a/src/tests.zig +++ b/src/tests.zig @@ -55,7 +55,7 @@ test "Bitboard general" { try expect(types.popcount(0b0110111010010) == 7); try expect(types.lsb(0b01101000) == 3); var b: types.Bitboard = 0b01101000; - try expect(@enumToInt(types.pop_lsb(&b)) == 3); + try expect(@intFromEnum(types.pop_lsb(&b)) == 3); try expect(b == 0b01100000); var bb_i: types.Bitboard = 0x3c18183c0000; From e7171c7074d7caa20a041289384c2998840406ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Hallstr=C3=B6m?= Date: Fri, 6 Jun 2025 09:39:41 +0200 Subject: [PATCH 2/4] fix the crash and unbreak the makefile --- Makefile | 2 +- src/engine/interface.zig | 18 ++++++------------ src/engine/nnue.zig | 2 +- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index 1c3f394..6799b18 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ MV=mv bin/Avalanche $(EXE) default: - zig build -Drelease-fast --prefix ./ -Dtarget-name="Avalanche" + zig build --release=fast -Dtarget-name="Avalanche" ifdef EXE $(MV) diff --git a/src/engine/interface.zig b/src/engine/interface.zig index bf750ea..8ddd64d 100644 --- a/src/engine/interface.zig +++ b/src/engine/interface.zig @@ -28,8 +28,8 @@ pub const UciInterface = struct { pub fn main_loop(self: *UciInterface) !void { var stdin = std.io.getStdIn().reader(); var stdout = std.io.getStdOut().writer(); - var command_arena = std.heap.ArenaAllocator.init(std.heap.c_allocator); - defer command_arena.deinit(); + + const allocator = std.heap.c_allocator; self.searcher.deinit(); self.searcher = search.Searcher.new(); @@ -40,13 +40,10 @@ pub const UciInterface = struct { out: while (true) { // The command will probably be less than 16384 characters - const line = try stdin.readUntilDelimiterOrEofAlloc(command_arena.allocator(), '\n', 16384); - - if (line == null) { - break; - } + const line = (try stdin.readUntilDelimiterOrEofAlloc(allocator, '\n', 16384)) orelse break; + defer allocator.free(line); - const tline = std.mem.trim(u8, line.?, "\r"); + const tline = std.mem.trim(u8, line, "\r"); var tokens = std.mem.tokenizeSequence(u8, tline, " "); var token = tokens.next(); @@ -370,9 +367,8 @@ pub const UciInterface = struct { } self.searcher.stop = false; - self.search_thread = std.Thread.spawn( - .{ .stack_size = 64 * 1024 * 1024 }, + .{ .stack_size = 256 * 1024 * 1024 }, startSearch, .{ &self.searcher, &self.position, movetime.?, max_depth }, ) catch |e| { @@ -441,8 +437,6 @@ pub const UciInterface = struct { } } } - - command_arena.allocator().free(line.?); } self.searcher.deinit(); diff --git a/src/engine/nnue.zig b/src/engine/nnue.zig index ea7d8cd..9dfb7c6 100644 --- a/src/engine/nnue.zig +++ b/src/engine/nnue.zig @@ -43,7 +43,7 @@ pub inline fn clipped_relu(input: i16) i32 { } } -pub const Accumulator = extern struct { +pub const Accumulator = struct { white: [weights.HIDDEN_SIZE]i16, black: [weights.HIDDEN_SIZE]i16, From de03765933991a93fd148fd59ef7802b89555de1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Hallstr=C3=B6m?= Date: Fri, 6 Jun 2025 09:45:11 +0200 Subject: [PATCH 3/4] omit frame pointer in release builds --- build.zig | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/build.zig b/build.zig index 6f01e9c..e34fb48 100644 --- a/build.zig +++ b/build.zig @@ -62,13 +62,17 @@ pub fn build(b: *std.Build) void { ); // Standard release options allow the person running `zig build` to select // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. - const optimise = b.standardOptimizeOption(.{}); - + const optimize = b.standardOptimizeOption(.{}); + const omit_frame_ptr = switch (optimize) { + .ReleaseFast, .ReleaseSmall => true, + .Debug, .ReleaseSafe => false, + }; const exe = b.addExecutable(.{ .name = targetName, .root_source_file = b.path("src/main.zig"), .target = target, - .optimize = optimise, + .optimize = optimize, + .omit_frame_pointer = omit_frame_ptr, }); exe.root_module.addImport("net", net_module); @@ -95,7 +99,7 @@ pub fn build(b: *std.Build) void { const exe_tests = b.addTest(.{ .root_source_file = b.path("src/tests.zig"), .target = target, - .optimize = optimise, + .optimize = optimize, }); const test_step = b.step("test", "Run unit tests"); From 17b89da2656a5bc028b209b99571fb3c6e4957f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Hallstr=C3=B6m?= Date: Mon, 16 Jun 2025 20:24:18 +0200 Subject: [PATCH 4/4] recover some speed --- src/chess/position.zig | 44 ++++++++++++++++++++--------------------- src/chess/tables.zig | 4 ++-- src/engine/hce.zig | 4 ++-- src/engine/movepick.zig | 4 ++-- src/engine/search.zig | 8 ++++---- src/engine/see.zig | 12 +++++------ src/tests.zig | 6 +++--- 7 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/chess/position.zig b/src/chess/position.zig index 9a17cc7..b5690bf 100644 --- a/src/chess/position.zig +++ b/src/chess/position.zig @@ -67,7 +67,7 @@ pub const Position = struct { pub fn new() Position { var pos = Position{}; - @memset(pos.mailbox[0..types.N_SQUARES], types.Piece.NO_PIECE); + @memset((&pos.mailbox)[0..types.N_SQUARES], types.Piece.NO_PIECE); pos.history[0] = UndoInfo.new(); pos.evaluator = hce.DynamicEvaluator{}; @@ -83,7 +83,7 @@ pub const Position = struct { std.debug.print("{s} {} ", .{ line, @divTrunc(i, 8) + 1 }); var j: i32 = 0; while (j < 8) : (j += 1) { - std.debug.print("| {c} ", .{types.PieceString[self.mailbox[@intCast(i + j)].index()]}); + std.debug.print("| {c} ", .{types.PieceString[(&self.mailbox)[@intCast(i + j)].index()]}); } std.debug.print("| {}\n", .{@divTrunc(i, 8) + 1}); } @@ -166,10 +166,10 @@ pub const Position = struct { while (j < 8) : (j += 1) { const idx: usize = @intCast(i + j); - if (self.mailbox[idx] == types.Piece.NO_PIECE) { + if ((&self.mailbox)[idx] == types.Piece.NO_PIECE) { empty_count += 1; } else { - const pieceChar = types.PieceString[self.mailbox[idx].index()]; + const pieceChar = types.PieceString[(&self.mailbox)[idx].index()]; if (empty_count > 0) { fen[index] = empty_count + '0'; index += 1; @@ -246,17 +246,17 @@ pub const Position = struct { pub inline fn add_piece(self: *Position, pc: types.Piece, sq: types.Square) void { self.evaluator.add_piece(pc, sq, self); - self.mailbox[sq.index()] = pc; + (&self.mailbox)[sq.index()] = pc; self.piece_bitboards[pc.index()] |= types.SquareIndexBB[sq.index()]; self.hash ^= zobrist.ZobristTable[pc.index()][sq.index()]; } pub inline fn remove_piece(self: *Position, sq: types.Square) void { self.evaluator.remove_piece(sq, self); - const pc = self.mailbox[sq.index()].index(); + const pc = (&self.mailbox)[sq.index()].index(); self.hash ^= zobrist.ZobristTable[pc][sq.index()]; self.piece_bitboards[pc] &= ~types.SquareIndexBB[sq.index()]; - self.mailbox[sq.index()] = types.Piece.NO_PIECE; + (&self.mailbox)[sq.index()] = types.Piece.NO_PIECE; } pub inline fn move_piece(self: *Position, from: types.Square, to: types.Square) void { @@ -267,11 +267,11 @@ pub const Position = struct { // DO NOT CALL IF DESTINATION IS NOT EMPTY pub inline fn move_piece_quiet(self: *Position, from: types.Square, to: types.Square) void { self.evaluator.move_piece_quiet(from, to, self); - self.hash ^= zobrist.ZobristTable[self.mailbox[from.index()].index()][from.index()] ^ zobrist.ZobristTable[self.mailbox[from.index()].index()][to.index()]; + self.hash ^= zobrist.ZobristTable[(&self.mailbox)[from.index()].index()][from.index()] ^ zobrist.ZobristTable[(&self.mailbox)[from.index()].index()][to.index()]; - self.piece_bitboards[self.mailbox[from.index()].index()] ^= types.SquareIndexBB[from.index()] | types.SquareIndexBB[to.index()]; - self.mailbox[to.index()] = self.mailbox[from.index()]; - self.mailbox[from.index()] = types.Piece.NO_PIECE; + self.piece_bitboards[(&self.mailbox)[from.index()].index()] ^= types.SquareIndexBB[from.index()] | types.SquareIndexBB[to.index()]; + (&self.mailbox)[to.index()] = (&self.mailbox)[from.index()]; + (&self.mailbox)[from.index()] = types.Piece.NO_PIECE; } pub inline fn diagonal_sliders(self: Position, comptime color: types.Color) types.Bitboard { @@ -340,7 +340,7 @@ pub const Position = struct { const flags = move.get_flags(); self.history[self.game_ply].entry |= types.SquareIndexBB[move.to] | types.SquareIndexBB[move.from]; - const pt = self.mailbox[move.from].piece_type(); + const pt = (&self.mailbox)[move.from].piece_type(); if (pt == types.PieceType.Pawn or move.is_capture()) { self.history[self.game_ply].fifty = 0; } @@ -398,31 +398,31 @@ pub const Position = struct { }, types.PC_KNIGHT => { self.remove_piece(move.get_from()); - self.history[self.game_ply].captured = self.mailbox[move.to]; + self.history[self.game_ply].captured = (&self.mailbox)[move.to]; self.remove_piece(move.get_to()); self.add_piece(types.Piece.new_comptime(color, types.PieceType.Knight), move.get_to()); }, types.PC_BISHOP => { self.remove_piece(move.get_from()); - self.history[self.game_ply].captured = self.mailbox[move.to]; + self.history[self.game_ply].captured = (&self.mailbox)[move.to]; self.remove_piece(move.get_to()); self.add_piece(types.Piece.new_comptime(color, types.PieceType.Bishop), move.get_to()); }, types.PC_ROOK => { self.remove_piece(move.get_from()); - self.history[self.game_ply].captured = self.mailbox[move.to]; + self.history[self.game_ply].captured = (&self.mailbox)[move.to]; self.remove_piece(move.get_to()); self.add_piece(types.Piece.new_comptime(color, types.PieceType.Rook), move.get_to()); }, types.PC_QUEEN => { self.remove_piece(move.get_from()); - self.history[self.game_ply].captured = self.mailbox[move.to]; + self.history[self.game_ply].captured = (&self.mailbox)[move.to]; self.remove_piece(move.get_to()); self.add_piece(types.Piece.new_comptime(color, types.PieceType.Queen), move.get_to()); }, else => { if (flags == types.MoveFlags.CAPTURE) { - self.history[self.game_ply].captured = self.mailbox[move.to]; + self.history[self.game_ply].captured = (&self.mailbox)[move.to]; self.move_piece(move.get_from(), move.get_to()); } }, @@ -604,7 +604,7 @@ pub const Position = struct { const checker_sq: types.Square = @enumFromInt(types.lsb(self.checkers)); - switch (self.mailbox[checker_sq.index()]) { + switch ((&self.mailbox)[checker_sq.index()]) { types.Piece.new_comptime(opp, types.PieceType.Pawn) => { var ep = self.history[self.game_ply].ep_sq; if (self.checkers == types.shift_bitboard(types.SquareIndexBB[ep.index()], rel_south)) { @@ -628,7 +628,7 @@ pub const Position = struct { b1 = self.attackers_from(color, checker_sq, all_bb) & not_pinned; while (b1 != 0) { var psq = types.pop_lsb(&b1); - if (self.mailbox[psq.index()].piece_type() == types.PieceType.Pawn and (types.SquareIndexBB[psq.index()] & types.MaskRank[types.Rank.RANK7.relative_rank(color).index()]) != 0) { + if ((&self.mailbox)[psq.index()].piece_type() == types.PieceType.Pawn and (types.SquareIndexBB[psq.index()] & types.MaskRank[types.Rank.RANK7.relative_rank(color).index()]) != 0) { list.append(types.Move.new_from_to_flag(psq, checker_sq, @enumFromInt(types.PC_QUEEN))) catch {}; list.append(types.Move.new_from_to_flag(psq, checker_sq, @enumFromInt(types.PC_ROOK))) catch {}; list.append(types.Move.new_from_to_flag(psq, checker_sq, @enumFromInt(types.PC_KNIGHT))) catch {}; @@ -704,7 +704,7 @@ pub const Position = struct { // Only include moves that align with king. - b2 = tables.get_attacks(self.mailbox[sq.index()].piece_type(), sq, all_bb) & tables.LineOf[our_king.index()][sq.index()]; + b2 = tables.get_attacks((&self.mailbox)[sq.index()].piece_type(), sq, all_bb) & tables.LineOf[our_king.index()][sq.index()]; types.Move.make_all(types.MoveFlags.QUIET, sq, b2 & quiet_mask, list); types.Move.make_all(types.MoveFlags.CAPTURE, sq, b2 & capture_mask, list); } @@ -924,7 +924,7 @@ pub const Position = struct { var checker_sq: types.Square = @enumFromInt(types.lsb(self.checkers)); - switch (self.mailbox[checker_sq.index()]) { + switch ((&self.mailbox)[checker_sq.index()]) { types.Piece.new_comptime(opp, types.PieceType.Pawn) => { var ep = self.history[self.game_ply].ep_sq; if (self.checkers == types.shift_bitboard(types.SquareIndexBB[ep.index()], rel_south)) { @@ -995,7 +995,7 @@ pub const Position = struct { // Only include moves that align with king. - b2 = tables.get_attacks(self.mailbox[sq.index()].piece_type(), sq, all_bb) & tables.LineOf[our_king.index()][sq.index()]; + b2 = tables.get_attacks((&self.mailbox)[sq.index()].piece_type(), sq, all_bb) & tables.LineOf[our_king.index()][sq.index()]; types.Move.make_all(types.MoveFlags.CAPTURE, sq, b2 & capture_mask, list); } diff --git a/src/chess/tables.zig b/src/chess/tables.zig index 784798a..33a5856 100644 --- a/src/chess/tables.zig +++ b/src/chess/tables.zig @@ -154,7 +154,7 @@ pub fn init_rook_attacks() void { // Returns the bitboard for rook attacks pub inline fn get_rook_attacks(square: types.Square, occ: types.Bitboard) types.Bitboard { - return RookAttacks[square.index()][((occ & RookAttackMasks[square.index()]) *% RookMagics[square.index()]) >> @intCast(RookAttackShifts[square.index()])]; + return (&(&RookAttacks)[square.index()])[((occ & (&RookAttackMasks)[square.index()]) *% (&RookMagics)[square.index()]) >> @intCast((&RookAttackShifts)[square.index()])]; } // Returns x-ray attacks, which is the attack when the first-layer blockers are removed. @@ -222,7 +222,7 @@ pub fn init_bishop_attacks() void { // Returns the bitboard for bishop attacks pub inline fn get_bishop_attacks(square: types.Square, occ: types.Bitboard) types.Bitboard { - return BishopAttacks[square.index()][((occ & BishopAttackMasks[square.index()]) *% BishopMagics[square.index()]) >> @intCast(BishopAttackShifts[square.index()])]; + return (&(&BishopAttacks)[square.index()])[((occ & (&BishopAttackMasks)[square.index()]) *% (&BishopMagics)[square.index()]) >> @intCast((&BishopAttackShifts)[square.index()])]; } // Returns x-ray attacks, which is the attack when the first-layer blockers are removed. diff --git a/src/engine/hce.zig b/src/engine/hce.zig index 70d5dae..8c5146b 100644 --- a/src/engine/hce.zig +++ b/src/engine/hce.zig @@ -191,7 +191,7 @@ pub const DynamicEvaluator = struct { } pub inline fn remove_piece(self: *DynamicEvaluator, sq: types.Square, pos: *position.Position) void { - const pc = pos.mailbox[sq.index()]; + const pc = (&pos.mailbox)[sq.index()]; if (pc != types.Piece.NO_PIECE) { if (UseNNUE) { @@ -220,7 +220,7 @@ pub const DynamicEvaluator = struct { } pub inline fn move_piece_quiet(self: *DynamicEvaluator, from: types.Square, to: types.Square, pos: *position.Position) void { - const pc = pos.mailbox[from.index()]; + const pc = (&pos.mailbox)[from.index()]; if (pc != types.Piece.NO_PIECE) { if (UseNNUE) { self.nnue_evaluator.toggle(false, pc, from); diff --git a/src/engine/movepick.zig b/src/engine/movepick.zig index d8f67c3..b236ef1 100644 --- a/src/engine/movepick.zig +++ b/src/engine/movepick.zig @@ -34,12 +34,12 @@ pub fn scoreMoves(searcher: *search.Searcher, pos: *position.Position, list: *st if (hm == move.to_u16()) { score += SortHash; } else if (move.is_capture()) { - if (pos.mailbox[move.to] == types.Piece.NO_PIECE) { + if ((&pos.mailbox)[move.to] == types.Piece.NO_PIECE) { score += SortWinningCapture + MVV_LVA[0][0]; } else { const see_value = see.see_threshold(pos, move.*, -90); - score += MVV_LVA[pos.mailbox[move.to].piece_type().index()][pos.mailbox[move.from].piece_type().index()]; + score += MVV_LVA[(&pos.mailbox)[move.to].piece_type().index()][(&pos.mailbox)[move.from].piece_type().index()]; if (see_value) { score += SortWinningCapture; diff --git a/src/engine/search.zig b/src/engine/search.zig index a719a32..f9733f1 100644 --- a/src/engine/search.zig +++ b/src/engine/search.zig @@ -720,7 +720,7 @@ pub const Searcher = struct { const new_depth: usize = @intCast(@as(i32, @intCast(depth)) + extension - 1); self.move_history[self.ply] = move; - self.moved_piece_history[self.ply] = pos.mailbox[move.from]; + self.moved_piece_history[self.ply] = (&pos.mailbox)[move.from]; self.ply += 1; pos.play_move(color, move); self.hash_history.append(pos.hash) catch {}; @@ -789,8 +789,8 @@ pub const Searcher = struct { } if (!is_null) { - self.pv[self.ply][0] = move; - @memcpy(self.pv[self.ply][1..(self.pv_size[self.ply + 1] + 1)], self.pv[self.ply + 1][0..(self.pv_size[self.ply + 1])]); + ((&self.pv)[self.ply])[0] = move; + @memcpy((&self.pv)[self.ply][1..(self.pv_size[self.ply + 1] + 1)], (&self.pv)[self.ply + 1][0..(self.pv_size[self.ply + 1])]); self.pv_size[self.ply] = self.pv_size[self.ply + 1] + 1; } @@ -964,7 +964,7 @@ pub const Searcher = struct { } self.move_history[self.ply] = move; - self.moved_piece_history[self.ply] = pos.mailbox[move.from]; + self.moved_piece_history[self.ply] = (&pos.mailbox)[move.from]; self.ply += 1; pos.play_move(color, move); tt.GlobalTT.prefetch(pos.hash); diff --git a/src/engine/see.zig b/src/engine/see.zig index 4658032..bcf8aaf 100644 --- a/src/engine/see.zig +++ b/src/engine/see.zig @@ -18,8 +18,8 @@ pub fn see_score(pos: *position.Position, move: types.Move) i32 { var opp = pos.turn.invert(); var blockers = all_pieces & ~types.SquareIndexBB[move.to]; - gains[0] = SeeWeight[pos.mailbox[move.to].piece_type().index()]; - var last_piece_pts = SeeWeight[pos.mailbox[move.from].piece_type().index()]; + gains[0] = SeeWeight[(&pos.mailbox)[move.to].piece_type().index()]; + var last_piece_pts = SeeWeight[(&pos.mailbox)[move.from].piece_type().index()]; var depth: usize = 1; outer: while (depth < gains.len) : (depth += 1) { @@ -57,8 +57,8 @@ pub fn see_score(pos: *position.Position, move: types.Move) i32 { pub fn see_threshold(pos: *position.Position, move: types.Move, threshold: i32) bool { const from = move.from; const to = move.to; - const attacker = pos.mailbox[from].piece_type().index(); - const victim = pos.mailbox[to].piece_type().index(); + const attacker = (&pos.mailbox)[from].piece_type().index(); + const victim = (&pos.mailbox)[to].piece_type().index(); var swap = SeeWeight[victim] - threshold; if (swap < 0) { return false; @@ -76,7 +76,7 @@ pub fn see_threshold(pos: *position.Position, move: types.Move, threshold: i32) const bishops = pos.diagonal_sliders(types.Color.White) | pos.diagonal_sliders(types.Color.Black); const rooks = pos.orthogonal_sliders(types.Color.White) | pos.orthogonal_sliders(types.Color.Black); - var stm = pos.mailbox[from].color().invert(); + var stm = (&pos.mailbox)[from].color().invert(); while (true) { attackers &= occ; @@ -125,5 +125,5 @@ pub fn see_threshold(pos: *position.Position, move: types.Move, threshold: i32) } } - return stm != pos.mailbox[from].color(); + return stm != (&pos.mailbox)[from].color(); } diff --git a/src/tests.zig b/src/tests.zig index fa4284f..e188d66 100644 --- a/src/tests.zig +++ b/src/tests.zig @@ -154,14 +154,14 @@ test "Position" { try expect(pos.hash == 0); try expect(pos.turn == types.Color.White); try expect(pos.game_ply == 0); - try expect(pos.mailbox[0] == types.Piece.NO_PIECE); + try expect((&pos.mailbox)[0] == types.Piece.NO_PIECE); pos.add_piece(types.Piece.WHITE_KNIGHT, types.Square.f3); - try expect(pos.mailbox[types.Square.f3.index()] == types.Piece.WHITE_KNIGHT); + try expect((&pos.mailbox)[types.Square.f3.index()] == types.Piece.WHITE_KNIGHT); try expect(pos.piece_bitboards[types.Piece.WHITE_KNIGHT.index()] == 0x200000); pos.remove_piece(types.Square.f3); - try expect(pos.mailbox[types.Square.f3.index()] == types.Piece.NO_PIECE); + try expect((&pos.mailbox)[types.Square.f3.index()] == types.Piece.NO_PIECE); try expect(pos.piece_bitboards[types.Piece.WHITE_KNIGHT.index()] == 0); pos = position.Position.new();