const std = @import("std"); const types = @import("types.zig"); pub fn moveTypeToStr(move: types.move, buf: []u8) void { const xTo = @mod(move.To, 8); const yTo = @divTrunc(move.To, 8); const xFrom = @mod(move.From, 8); const yFrom = @divTrunc(move.From, 8); buf[0] = @intCast(xFrom + 'a'); buf[1] = @intCast(yFrom + '0' + 1); buf[2] = @intCast(xTo + 'a'); buf[3] = @intCast(yTo + '0' + 1); buf[4] = move.Promo; } pub fn playMoves(game: *types.game, str: []const u8) *types.game { if (str.len < 4) return game; var splitItr = std.mem.splitSequence(u8, str, " "); while (splitItr.next()) |moveString| { if (moveString.len < 4 or moveString[0] > 'h') continue; var move: types.move = .{ .To = 0, .From = 0, .Promo = 0 }; if (moveString.len < 4) continue; move.From = (moveString[0] - 'a') + (moveString[1] - '1') * 8; move.To = (moveString[2] - 'a') + (moveString[3] - '1') * 8; move.Promo = if (moveString.len == 5) moveString[4] else 0; makeMove(@ptrCast(game), @ptrCast(&move)); } return game; } fn fullSet(set: *types.set) u64 { return set.bishops | set.king | set.knights | set.pawns | set.queen | set.rooks; } fn findSet(game: *types.game, bit: u64) ?*u64 { if (game.white.pawns & bit != 0) { return &game.white.pawns; } else if (game.white.knights & bit != 0) { return &game.white.knights; } else if (game.white.bishops & bit != 0) { return &game.white.bishops; } else if (game.white.rooks & bit != 0) { return &game.white.rooks; } else if (game.white.queen & bit != 0) { return &game.white.queen; } else if (game.white.king & bit != 0) { return &game.white.king; } else if (game.black.pawns & bit != 0) { return &game.black.pawns; } else if (game.black.knights & bit != 0) { return &game.black.knights; } else if (game.black.bishops & bit != 0) { return &game.black.bishops; } else if (game.black.rooks & bit != 0) { return &game.black.rooks; } else if (game.black.queen & bit != 0) { return &game.black.queen; } else if (game.black.king & bit != 0) { return &game.black.king; } else { return null; } } fn makeMove(game: *types.game, move: *types.move) void { const from = @as(u64, 1) << @truncate(move.From); const to = @as(u64, 1) << @truncate(move.To); const set = findSet(game, from); if (set == null) return; set.?.* &= ~from; const cap = findSet(game, to); if (cap != null) cap.?.* &= ~to; if (move.Promo != 0) { charToSet(game, move.Promo).* |= to; } else { set.?.* |= to; } game.whiteToMove = !game.whiteToMove; } pub fn charToSet(g: *types.game, chr: u8) *u64 { return switch (chr) { 'P' => &g.white.pawns, 'N' => &g.white.knights, 'B' => &g.white.bishops, 'R' => &g.white.rooks, 'Q' => &g.white.queen, 'K' => &g.white.king, 'p' => &g.black.pawns, 'n' => &g.black.knights, 'b' => &g.black.bishops, 'r' => &g.black.rooks, 'q' => &g.black.queen, 'k' => &g.black.king, else => { std.log.err("you should not be here ${c}$", .{chr}); unreachable; }, }; } // pub fn pawnMove(arr: std.ArrayList(c.move)) void { // const move = c.move{ .From = 8, .To = 16, .Promo = 0 }; // } pub fn sqrScan(rook: u64, hit: u64, flip: bool) u64 { const vecLut: [64]u64 = undefined; //todo comptime init var center = rook; var hits = hit; if (flip) { center = @bitReverse(rook); hits = @bitReverse(hit); } const vec = vecLut[@ctz(center)]; var attackedBits = hits & vec; const n = @popCount(attackedBits); var min: u64 = vec; for (0..n) |_| { const pos = @ctz(attackedBits); const bit = @as(u64, 1) << pos; attackedBits = attackedBits & ~bit; if (bit - 1 < min) min = bit - 1; } return min; } pub fn knightMove(g: *types.game, arr: *std.ArrayList(types.move)) void { const moveLut: [64]u64 = comptime blk: { var value: [64]u64 = undefined; for (0..64) |i| { value[i] = knightCalc(@truncate(i)); } break :blk value; }; const set = if (g.whiteToMove) &g.white.knights else &g.black.knights; const fset: u64 = if (g.whiteToMove) @as(u64, fullSet(@ptrCast(&g.white))) else @as(u64, fullSet(@ptrCast(&g.black))); var val = set.*; //local copy const n = @popCount(val); for (0..n) |_| { const pos = @ctz(val); const moves = moveLut[pos] & ~fset; val = val ^ (@as(u64, 1) << @truncate(pos)); bitboardToMoves(pos, moves, arr); } } fn knightCalc(index: u8) u64 { var moves: u64 = 0; const offsets = [_]i8{ 17, -17, 15, -15, 10, -10, 6, -6 }; var cnt: u8 = undefined; for (offsets) |off| { if (off > 0) { cnt = index + @abs(off); } else if (index > @abs(off)) { //Icky bad that zig makes me do cnt = index - @abs(off); } const fromFile: i32 = index % 8; const toFile: i32 = cnt % 8; const fromRank: i32 = index / 8; const toRank: i32 = cnt / 8; const fileDiff = @abs(fromFile - toFile); const rankDiff = @abs(fromRank - toRank); if (!((fileDiff == 1 and rankDiff == 2) or (fileDiff == 2 and rankDiff == 1)) or cnt > 63) continue; moves = moves | @as(u64, 1) << @truncate(cnt); } return moves; } fn bitboardToMoves(start: u8, moves: u64, arr: *std.ArrayList(types.move)) void { var lmoves = moves; while (lmoves != 0) { const pos = @ctz(lmoves); const m: types.move = .{ .From = start, .Promo = 0, .To = pos }; lmoves = lmoves & ~@as(u64, 1) << @truncate(pos); arr.append(m) catch unreachable; } }