7SQSGQOZRCHN3GGWPNFI36K2R7YZMOPXZP3FP4PYDDOZML5YIYOQC IBUD4SUGA4IS6HUQIHVJJOFS4CMTWJMTMXS4LWGFVK4PFUFKE5LAC XCZABYMDLHLHXNTHZFCXPNP6VOCNYUROAQACE5SWBL5FJK2EB7WQC WTTQGET65BQV7NSFOI75JGCTWFS6R73OFZE4V63JYWAODNIOUAHQC BL3ZR4OWJM54HFXUNMUZKB5YQYVBT7ETFIXCOXWL6S5SZFM6IFDQC GZPVUGLJGD3VGLIK7JDABQ24E5SWN5CYRDGI6PIAFZ2BIMRDMANQC YCH5WGGP3PPG2PUNVJIJ6SQXDPYU7NGCVQEJYN27B6FYV5JYQOMQC TDHJSFFSJZBEZFMDHPLRSVB6CIVJ7AWGGNIC3WUCADQLQSIQKXDAC QYOCQUIWNSZNLCPDJCKERKC6BXBUNTE6AJCFYL4WDRU32LFX37XQC 7T5U3ARTEEAORKCSJY763X5TJRGHCEQK3OW323YO5CZIM77EH77AC O6734I3LMVTKXE5Y7FR3EDGSVIJQHFATUPJJCMRYXD7KLAN6E4UQC .P, .p => {while (board != 0) {const s = @intCast(u6, @ctz(board));source_square = @as(BoardType, 1) << s;std.debug.print("pawn: {any}\n", .{@intToEnum(Square, s)});
.P, .p => self.pawnMoves(board),else => {},}}// generate move for rest of pieces}fn pawnMoves(self: @This(), board_in: BoardType) void {var source_square: SquareType = undefined;var target_square: SquareType = undefined;var board = board_in;while (board != 0) {source_square = @intCast(SquareType, @ctz(board));// std.debug.print("pawn: {any}\n", .{@intToEnum(Square, source_square)});// early exit on underflow/overflowswitch (self.side) {.white => if (@subWithOverflow(SquareType, source_square, 8, &target_square)) continue,.black => if (@addWithOverflow(SquareType, source_square, 8, &target_square)) continue,}
// early exit on underflow/overflowswitch (piece) {.P => if (@subWithOverflow(BoardType, source_square, 8, &target_square)) continue,.p => if (@addWithOverflow(BoardType, source_square, 8, &target_square)) continue,else => unreachable,}
const promote_condition = switch (self.side) {.white => source_square >= @enumToInt(Square.a7) andsource_square <= @enumToInt(Square.h7),.black => source_square >= @enumToInt(Square.a2) andsource_square <= @enumToInt(Square.h2),};
// generate quiet pawn movesif (self.occupBoth() & target_square == 0) {const promote_condition = switch (piece) {.P => source_square >= @enumToInt(Square.a7) andsource_square <= @enumToInt(Square.h7),.p => source_square >= @enumToInt(Square.a2) andsource_square <= @enumToInt(Square.h2),else => unreachable,};const double_step_condition = switch (piece) {.P => source_square >= @enumToInt(Square.a2) andsource_square <= @enumToInt(Square.h2) andself.occupBoth() & (target_square - 8) == 0,.p => source_square >= @enumToInt(Square.a7) andsource_square <= @enumToInt(Square.h7) andself.occupBoth() & (target_square + 8) == 0,else => unreachable,};
// generate quiet movesif (self.occupBoth() & (@as(BoardType, 1) << target_square) == 0) {const double_step_condition = switch (self.side) {.white => source_square >= @enumToInt(Square.a2) andsource_square <= @enumToInt(Square.h2) andself.occupBoth() & (@as(BoardType, 1) << (target_square - 8)) == 0,.black => source_square >= @enumToInt(Square.a7) andsource_square <= @enumToInt(Square.h7) andself.occupBoth() & (@as(BoardType, 1) << (target_square + 8)) == 0,};if (promote_condition) {for ([_]u8{ 'q', 'r', 'b', 'n' }) |prom| {std.debug.print("pawn promotions {any}->{any}{c}\n", .{@intToEnum(Square, source_square),@intToEnum(Square, target_square),prom,});}} else {std.debug.print("pawn push: {any}->{any}\n", .{@intToEnum(Square, source_square),@intToEnum(Square, target_square),});
if (promote_condition) {// TODO: add move to move list} else {// TODO: single step
// TODO: check: if single step is no-go, double can not workif (double_step_condition) {const double_target = switch (self.side) {.white => target_square - 8,.black => target_square + 8,};std.debug.print("pawn push double: {any}->{any}\n", .{@intToEnum(Square, source_square),@intToEnum(Square, double_target),});}}}
// TODO: double step// FIXME: if single step is no-go, double can not workif (double_step_condition) {}}}
// generate attacksconst other = switch (self.side) {.white => Colors.black,.black => Colors.white,};var attacks =self.attacks.pawn_attacks[@enumToInt(self.side)][source_square] &self.occupancies[@enumToInt(other)];while (attacks != 0) {target_square = @intCast(SquareType, @ctz(attacks));
// pop least significant bitboard ^= source_square;
if (promote_condition) {for ([_]u8{ 'q', 'r', 'b', 'n' }) |prom| {std.debug.print("pawn promotion attacks {any}->{any}{c}\n", .{@intToEnum(Square, source_square),@intToEnum(Square, target_square),prom,});
// generate move for rest of pieces}};
// generate enpassant capturesif (self.enpassant != null) {const enpassant_attacks = self.attacks.pawn_attacks[@enumToInt(self.side)][source_square] &@as(BoardType, 1) << self.enpassant.?.int();
test "parseFEN" {const empty_board = "8/8/8/8/8/8/8/8 w - -";const start_position = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";const tricky_position = "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1";const killer_position = "rnbqkb1r/pp1p1pPp/8/2p1pP2/1P1P4/3P3P/P1P1P3/RNBQKBNR w KQkq e6 0 1";const cmk_position = "r2q1rk1/ppp2ppp/2n1bn2/2b1p3/3pP3/3P1NPP/PPP1NPB1/R1BQ1RK1 b - - 0 9";
if (enpassant_attacks != 0) {const target_enpassant: SquareType = @intCast(u6, @ctz(enpassant_attacks));std.debug.print("pawn enpassant capture: {any}->{any}\n", .{@intToEnum(Square, source_square),@intToEnum(Square, target_enpassant),});}}
var game = Game{ .attacks = Attacks.init() };try game.parseFEN(empty_board);try game.parseFEN(start_position);try game.parseFEN(tricky_position);try game.parseFEN(killer_position);try game.parseFEN(cmk_position);}
// pop processed board bitboard ^= @as(BoardType, 1) << source_square;}}};