RatChess/src/move.zig
k a7c9f4f472
All checks were successful
Verify build / verify_build (push) Successful in 1m9s
removed all c code
2025-10-27 13:54:27 -04:00

192 lines
5.9 KiB
Zig

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;
}
}