I am making a checkers game in Zig, and I have a function that checks if you can capture the enemies checker if you move in a direction from a position.
fn checkCaptureDirection(board: [8][8]u8, start_pos: Position, color: MoveColor, limit: bool, move_row: i2, move_col: i2) bool {
if (findClosestChecker(board, start_pos, move_row, move_col)) |checker| {
//Can't capture your own pieces
if (checker.color == color) return false;
//If at the edge we can't capture it
if (checker.position.col == 0 or checker.position.col == 7 or checker.position.row == 0 or checker.position.row == 7) return false;
//Find a space behind the other piece in the direction
const behind_other: Position = .{
.row = @intCast(@as(i4, checker.position.row) + move_row),
.col = @intCast(@as(i4, checker.position.col) + move_col),
};
//We move diagnaly and so we only need to find length on one axis
const move_len_row = @abs(@as(i4, behind_other.row) - @as(i4, start_pos.row));
//Limit the normal checker to only be close
if (limit and move_len_row > 2) return false;
//Can't move onto the other piece
if (getPieceAtPosition(board, behind_other) != 0) return false;
std.debug.assert(validateCapture(board, .{
.color = color,
.from = start_pos,
.to = behind_other,
}));
return true;
}
//No checker in that direction so can't capture anything
return false;
}
Now I need a function that would not only check if you can, but also find all possible capture moves in that direction and save them to an arrayList that I would pass into it.
On one hand the logic will be quite simular and I don’t want to duplicate code, but on the other hand, it feels like this function will do too much and adding an allocator and arrayList to parameters when they will only be used half of the time and error to return seems very ugly.
Yes, the are would be mostly same but would behave slightly differently. The yes or no just does one check for if your piece can move behind the other one (which would capture it) and returns, the new one would need to also check all spaces after it and add all those moves to the list
That will not work. This is what that function looks like
fn checkCaptureDirection(board: [8][8]u8, start_pos: Position, color: MoveColor, limit: bool, move_row: i2, move_col: i2) bool {
if (findClosestChecker(board, start_pos, move_row, move_col)) |checker| {
//Can't capture your own pieces
if (checker.color == color) return false;
//If at the edge we can't capture it
if (checker.position.col == 0 or checker.position.col == 7 or checker.position.row == 0 or checker.position.row == 7) return false;
//Find a space behind the other piece in the direction
const behind_other: Position = .{
.row = @intCast(@as(i4, checker.position.row) + move_row),
.col = @intCast(@as(i4, checker.position.col) + move_col),
};
//We move diagnaly and so we only need to find length on one axis
const move_len_row = @abs(@as(i4, behind_other.row) - @as(i4, start_pos.row));
//Limit the normal checker to only be close
if (limit and move_len_row > 2) return false;
//Can't move onto the other piece
if (getPieceAtPosition(board, behind_other) != 0) return false;
std.debug.assert(validateCapture(board, .{
.color = color,
.from = start_pos,
.to = behind_other,
}));
return true;
}
//No checker in that direction so can't capture anything
return false;
}
Seems to me like you have one common thing like fn getNextCaptureAndReturnNewPosition(startPosition, ...) ?Position (needs better name)
Then two functions who utilize this. fn checkCaptureDirection which just checks if the above returns null or not
And you new function which uses the return position to do a new captureCheck. But I am also not expierenced with checkers, so I may be missing something.