FOORIA7SEZCLKDBNMV6KEDTQOJJVAH57BQFBRSQMET6FERJPHCVQC OF6NBX4Y6UWXBSSENWBBYH3AU4TI5FCD5S7WKYMINBUBCKA2MD4AC A46B5KNQFPTZEIL2JZKD2CQELGU3COE6FGTV2ABS5U7DVTVDGEBQC BL3ZR4OWJM54HFXUNMUZKB5YQYVBT7ETFIXCOXWL6S5SZFM6IFDQC 2CU67A3QXXPH722WBAL74O6P2N2RRXFBQVPT3A5QAXTUCQ3UUU5AC TB4YBE4CMWCLSKJ43QF6IU5HVYUUO33BLXVG7XDRLJS3IFIBQLYAC GDHXEMN5IXJDS63G3DUZH5PR2XH2SSXISABF2JHCYA3JSRXDPLMQC XHCMZF25YBLNQLVKKBJJWWJ3G24VFUSLE3LAT2DRWL52RJX4Z3EAC const std = @import("std");const Board = @import("Board.zig");pub const Perft = struct {nodes: usize = 0,gs: Board.GameState,pub fn perftDriver(self: *@This(), depth: usize) void {if (depth == 0) {// count nodesself.nodes += 1;return;}var ml = Board.MoveList.init(0) catch unreachable;self.gs.generateMoves(&ml) catch unreachable;for (ml.slice()) |move| {const bk = self.gs.backup();if (!self.gs.makeMove(move, .all)) {continue;}self.perftDriver(depth - 1);self.gs.restore(bk);}}fn perftTest(self: *@This(), depth: usize) void {var ml = Board.MoveList.init(0) catch unreachable;self.gs.generateMoves(&ml) catch unreachable;for (ml.slice()) |move| {const bk = self.gs.backup();if (!self.gs.makeMove(move, .all)) {std.debug.print("ILLEGAL MOVE\n", .{});continue;}const cummulative_nodes = self.nodes;self.perftDriver(depth - 1);const old_nodes = self.nodes - cummulative_nodes;self.gs.restore(bk);move.show();std.debug.print("nodes: {d}\n", .{old_nodes});}}};test "Perft" {var gs = Board.GameState.init("8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -") catch unreachable;var p = Perft{ .gs = gs };p.perftDriver(2);try std.testing.expectEqual(@as(usize, 191), p.nodes);}
var bit_board: Chess.BitBoard = .{ .board = 0 };bit_board.show();
var gs = try Board.GameState.init("8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -");var p = Perft{ .gs = gs };var timer = try std.time.Timer.start();p.perftDriver(4);std.debug.print("Nodes: {d} time: {d}\n", .{ p.nodes, timer.read() / std.time.ns_per_ms });
fn show(self: @This()) void {std.debug.print("\nsource: {any}\n", .{self.source});std.debug.print("target: {any}\n", .{self.target});std.debug.print("piece: {any}\n", .{self.piece});std.debug.print("promote: {any}\n", .{self.prom});std.debug.print("capture: {any}\n", .{self.capture});std.debug.print("double: {any}\n", .{self.double});std.debug.print("enpassant: {any}\n", .{self.enpassant});std.debug.print("castling: {any}\n", .{self.castling});
pub fn show(self: @This()) void {// std.debug.print("source: {any}\n", .{self.source});// std.debug.print("target: {any}\n", .{self.target});// std.debug.print("piece: {any}\n", .{self.piece});// std.debug.print("promote: {any}\n", .{self.prom});// std.debug.print("capture: {any}\n", .{self.capture});// std.debug.print("double: {any}\n", .{self.double});// std.debug.print("enpassant: {any}\n", .{self.enpassant});// std.debug.print("castling: {any}\n", .{self.castling});std.debug.print("{s} {s}{s}\t", .{@tagName(self.piece),@tagName(self.source),@tagName(self.target),});
.N, .n => try self.genMoves(board, piece),.B, .b => try self.genMoves(board, piece),.R, .r => try self.genMoves(board, piece),.Q, .q => try self.genMoves(board, piece),
.N, .n => try self.genMoves(ml, board, piece),.B, .b => try self.genMoves(ml, board, piece),.R, .r => try self.genMoves(ml, board, piece),.Q, .q => try self.genMoves(ml, board, piece),
if (self.occupancies[@enumToInt(self.enemy)].isSet(@intToEnum(Square, target_square))) {try self.moves.append(BitMove{
if (self.occupancies[@enumToInt(self.side.enemy())].isSet(@intToEnum(Square, target_square))) {try ml.append(BitMove{
// handle occupancy arrays{// remove source target, one of them is no-opself.occupancies[@enumToInt(Chess.Colors.white)].unSet(move.source);self.occupancies[@enumToInt(Chess.Colors.black)].unSet(move.source);// set target for the proper sideswitch (self.side) {.white => {self.occupancies[@enumToInt(Chess.Colors.white)].set(move.target);self.occupancies[@enumToInt(Chess.Colors.black)].unSet(move.target);},.black => {self.occupancies[@enumToInt(Chess.Colors.black)].set(move.target);self.occupancies[@enumToInt(Chess.Colors.white)].unSet(move.target);},}}
// handle occupancy arrays TODO: perf test!// {// // remove source target, one of them is no-op// self.occupancies[@enumToInt(Chess.Colors.white)].unSet(move.source);// self.occupancies[@enumToInt(Chess.Colors.black)].unSet(move.source);
// TODO: reset enpassant// self.enpassant = null;
// // set target for the proper side// switch (self.side) {// .white => {// self.occupancies[@enumToInt(Chess.Colors.white)].set(move.target);// self.occupancies[@enumToInt(Chess.Colors.black)].unSet(move.target);// },// .black => {// self.occupancies[@enumToInt(Chess.Colors.black)].set(move.target);// self.occupancies[@enumToInt(Chess.Colors.white)].unSet(move.target);// },// }// }
const target = switch (self.side) {.white => @intToEnum(Square, @enumToInt(move.target) + 8),.black => @intToEnum(Square, @enumToInt(move.target) - 8),};self.bitboards[move.piece.int()].pop(target);
switch (self.side) {.white => self.bitboards[Chess.PE.p.int()].pop(@intToEnum(Square, @enumToInt(move.target) + 8)),.black => self.bitboards[Chess.PE.P.int()].pop(@intToEnum(Square, @enumToInt(move.target) - 8)),}
self.occupancies[@enumToInt(Chess.Colors.white)].pop(Square.h1);self.occupancies[@enumToInt(Chess.Colors.white)].set(Square.f1);
// self.occupancies[@enumToInt(Chess.Colors.white)].pop(Square.h1);// self.occupancies[@enumToInt(Chess.Colors.white)].set(Square.f1);
self.occupancies[@enumToInt(Chess.Colors.white)].pop(Square.a1);self.occupancies[@enumToInt(Chess.Colors.white)].set(Square.d1);
// self.occupancies[@enumToInt(Chess.Colors.white)].pop(Square.a1);// self.occupancies[@enumToInt(Chess.Colors.white)].set(Square.d1);
self.occupancies[@enumToInt(Chess.Colors.black)].pop(Square.h1);self.occupancies[@enumToInt(Chess.Colors.black)].set(Square.f1);
// self.occupancies[@enumToInt(Chess.Colors.black)].pop(Square.h1);// self.occupancies[@enumToInt(Chess.Colors.black)].set(Square.f1);
self.occupancies[@enumToInt(Chess.Colors.black)].pop(Square.a8);self.occupancies[@enumToInt(Chess.Colors.black)].set(Square.d8);
// self.occupancies[@enumToInt(Chess.Colors.black)].pop(Square.a8);// self.occupancies[@enumToInt(Chess.Colors.black)].set(Square.d8);
// make sure the move is valid (no check)
// update occupancy boards{var white: BoardType = 0;var black: BoardType = 0;for ([_]Chess.PE{ .P, .N, .B, .R, .Q, .K }) |piece| {white |= @bitCast(BoardType, self.bitboards[piece.int()]);}for ([_]Chess.PE{ .p, .n, .b, .r, .q, .k }) |piece| {black |= @bitCast(BoardType, self.bitboards[piece.int()]);}self.occupancies[@enumToInt(Chess.Colors.white)] = @bitCast(BitBoard, white);self.occupancies[@enumToInt(Chess.Colors.black)] = @bitCast(BitBoard, black);}// make sure the move is valid (king is not in check)
test "makeMove" {const test_pos = "r3k2r/pPppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq c6 0 1";var gs = try GameState.init(test_pos);try gs.generateMoves();for (gs.moves.slice()) |move| {if (move.castling) {gs.show();move.show();const bk = gs.backup();_ = gs.makeMove(move, .all);gs.show();gs.restore(bk);}}}