commit aab172c73b463fd843910fe2bc5c5044e1438659
parent b5b8e9b5efe9a97a565a17c725cea3bd1b6d4d96
Author: thing1 <thing1@seacrossedlovers.xyz>
Date: Wed, 21 Jan 2026 00:00:19 +0000
added move checks for every piece
Diffstat:
3 files changed, 108 insertions(+), 70 deletions(-)
diff --git a/chess/chess.ha b/chess/chess.ha
@@ -16,23 +16,24 @@ export type ptype = enum rune {
};
export type color = enum {BLACK = 'b', WHITE = 'w'};
-export type movefn = *fn(_: i64, _: i64, _: i64, _: i64) bool;
+export type movefn = *fn(_: piece, _: board, _: i64, _: i64) bool;
export type piece = struct {
- x: size,
- y: size,
+ x: i64,
+ y: i64,
ty: ptype,
team: color,
- valid: movefn
+ valid: movefn,
+ moved: bool
};
export type board = struct {
- w: size,
- h: size,
+ w: i64,
+ h: i64,
pieces: []piece,
};
-export fn mkboard(w: size, h: size) board = {
+export fn mkboard(w: i64, h: i64) board = {
return board{w = w, h = h, pieces = []};
};
@@ -40,7 +41,7 @@ export fn finish(b: *board) void = {
free(b.pieces);
};
-export fn mkpiece(b: *board, x: size, y: size, ty: ptype, team: color) (*piece | !invalidplace) = {
+export fn mkpiece(b: *board, x: i64, y: i64, ty: ptype, team: color) (*piece | !invalidplace) = {
if (x < 0 || x >= b.w || y < 0 || y >= b.h) return invalidplace;
let valid = switch(ty) {
@@ -49,14 +50,14 @@ export fn mkpiece(b: *board, x: size, y: size, ty: ptype, team: color) (*piece |
case ptype::BISHOP => yield &bishopmove;
case ptype::KNIGHT => yield &knightmove;
case ptype::ROOK => yield &rookmove;
- case ptype::PAWN => yield &truemove;
+ case ptype::PAWN => yield &pawnmove;
};
- append(b.pieces, piece{x = x, y = y, ty = ty, team = team, valid = valid})!;
+ append(b.pieces, piece{x = x, y = y, ty = ty, team = team, valid = valid, moved = false})!;
return &b.pieces[len(b.pieces) - 1];
};
-export fn getpiece(b: *board, x: size, y: size) (*piece | !empty | !invalidplace) = {
+export fn getpiece(b: *board, x: i64, y: i64) (*piece | !empty | !invalidplace) = {
if (x < 0 || x >= b.w || y < 0 || y >= b.h) return invalidplace;
for (let p &.. b.pieces)
if (p.x == x && p.y == y)
@@ -64,20 +65,17 @@ export fn getpiece(b: *board, x: size, y: size) (*piece | !empty | !invalidplace
return empty;
};
-export fn movepiece(b: *board, x1: size, y1: size, x2: size, y2: size) (void | !empty | !invalidmove | !invalidplace) = {
- let p = getpiece(b, x1, x2)?;
- if (p.ty == ptype::PAWN)
- if (!p.valid(x1: i64, y1: i64, x2: i64, y2: i64)) return invalidmove;
+export fn movepiece(b: *board, x1: i64, y1: i64, x2: i64, y2: i64) (void | !empty | !invalidmove | !invalidplace) = {
+ let p = getpiece(b, x1, y1)?;
+ if (!p.valid(*p, *b, x2, y2)) return invalidmove;
+ p.x = x2;
+ p.y = y2;
+ p.moved = true;
};
export fn print_board(b: board, f: io::handle) void = {
- const w = 500z;
- const h = 500z;
-
for (let p .. b.pieces) {
- let x = (w / b.w) * p.x;
- let y = (h / b.h) * p.y + 23;
let text = if (p.team == color::WHITE) ascii::toupper(p.ty: rune) else p.ty: rune;
- fmt::fprintf(f, "{} {} {}\n", text, x, y)!;
+ fmt::fprintf(f, "{} {} {}\n", text, p.x, p.y)!;
};
};
diff --git a/chess/moves.ha b/chess/moves.ha
@@ -1,70 +1,102 @@
use math;
+use fmt;
fn invalid(x2: i64, y2: i64) bool =
if (x2 < 0 || y2 < 0 || x2 >= 8 || y2 >= 8) true
else false;
-export fn kingmove(x1: i64, y1: i64, x2: i64, y2: i64) bool =
- if (invalid(x2, y2)) false
- else if (math::absi64(x2 - x1) > 1 || math::absi64(y2 - y1) > 1) false
- else true;
+fn selftake(p: piece, b: board, x2: i64, y2: i64) bool =
+ match (getpiece(&b, x2, y2)) {
+ case let p2: *piece => return (p2.team == p.team);
+ case => return false;
+ };
+
+fn checkdiag(p: piece, b: board, x2: i64, y2: i64) bool = {
+ if (math::absi64(x2 - p.x) == math::absi64(y2 - p.y)) {
+ let xdir = if ((x2 - p.x) > 0) 1 else -1;
+ let ydir = if ((y2 - p.y) > 0) 1 else -1;
+ let y = p.y + ydir;
+ for (let x = p.x + xdir; x != x2; x += xdir) {
+ let p2 = getpiece(&b, x, y);
+ if (!(p2 is empty)) return false;
+ y += ydir;
+ };
+ return true;
+ };
+
+ return false;
+};
+
+fn checkstraight(p: piece, b: board, x2: i64, y2: i64) bool = {
+ if (p.x == x2) {
+ let xdir = if ((x2 - p.x) > 0) 1 else -1;
+ for (let x = p.x; x != x2; x += xdir) {
+ let p2 = getpiece(&b, x, p.y);
+ if (!(p2 is empty)) return false;
+ };
+ return true;
+ } else if (p.y == y2) {
+ let ydir = if ((y2 - p.y) > 0) 1 else -1;
+ for (let y = p.y; y != y2; y += ydir) {
+ let p2 = getpiece(&b, p.x, y);
+ if (!(p2 is empty)) return false;
+ };
+ return true;
+ };
+
+ return false;
+};
+
+fn kingmove(p: piece, b: board, x2: i64, y2: i64) bool = {
+ if (invalid(x2, y2)) return false
+ else if (selftake(p, b, x2, y2)) return false
+ else if (math::absi64(x2 - p.x) > 1 || math::absi64(y2 - p.y) > 1) return false;
-export fn queenmove(x1: i64, y1: i64, x2: i64, y2: i64) bool =
+ let p2 = getpiece(&b, x2, y2);
+ if (p2 is empty || (p2 as *piece).team != p.team) return true;
+
+ return false;
+};
+
+fn queenmove(p: piece, b: board, x2: i64, y2: i64) bool =
if (invalid(x2, y2)) false
- else if (math::absi64(x2 - x1) == math::absi64(y2 - y1) || x1 == x2 || y1 == y2) true
+ else if (selftake(p, b, x2, y2)) false
+ else if (checkdiag(p, b, x2, y2)) true
+ else if (checkstraight(p, b, x2, y2)) true
else false;
-export fn bishopmove(x1: i64, y1: i64, x2: i64, y2: i64) bool =
+fn bishopmove(p: piece, b: board, x2: i64, y2: i64) bool =
if (invalid(x2, y2)) false
- else if (math::absi64(x2 - x1) == math::absi64(y2 - y1)) true
+ else if (selftake(p, b, x2, y2)) false
+ else if (checkdiag(p, b, x2, y2)) true
else false;
-export fn rookmove(x1: i64, y1: i64, x2: i64, y2: i64) bool =
+fn rookmove(p: piece, b: board, x2: i64, y2: i64) bool =
if (invalid(x2, y2)) false
- else if (x1 == x2 || y1 == y2) true
+ else if (selftake(p, b, x2, y2)) false
+ else if (checkstraight(p, b, x2, y2)) true
else false;
-export fn knightmove(x1: i64, y1: i64, x2: i64, y2: i64) bool =
+fn knightmove(p: piece, b: board, x2: i64, y2: i64) bool =
if (invalid(x2, y2)) false
- else if (math::absi64(x2 - x1) == 1 && math::absi64(y2 - y1) == 2) true
- else if (math::absi64(x2 - x1) == 2 && math::absi64(y2 - y1) == 1) true
+ else if (selftake(p, b, x2, y2)) return false
+ else if (math::absi64(x2 - p.x) == 1 && math::absi64(y2 - p.y) == 2) true
+ else if (math::absi64(x2 - p.x) == 2 && math::absi64(y2 - p.y) == 1) true
else false;
-export fn pawnmove(x1: i64, y1: i64, x2: i64, y2: i64, b: board) bool = {
+fn pawnmove(p: piece, b: board, x2: i64, y2: i64) bool = {
if (invalid(x2, y2)) return false
+ else if (selftake(p, b, x2, y2)) return false
+ else if (p.moved && math::absi64(y2 - p.y) > 1) return false
+ else if (!p.moved && math::absi64(y2 - p.y) > 2) return false;
- let p = getpiece(b, x1, y1)!;
- // white is on the 0 row
- if (p.team == color::WHITE) {
- if (y2 <= y1) return false;
+ if (x2 == p.x + 1 || x2 == p.x - 1 || x2 == p.x) {
+ match (getpiece(&b, x2, y2)) {
+ case empty => return (x2 == p.x);
+ case let p2: *piece => return (x2 != p.x && p2.team != p.team);
+ case => return false;
+ };
};
- else {
- if (y2 >= y1) return false;
- };
- // TODO here
- //
-};
-
-export fn truemove(x1: i64, y1: i64, x2: i64, y2: i64) bool = !invalid(x2, y2);
-
-@test fn kingmove() void = assert(kingmove(4, 0, 4, 1) == true, "(4, 0) -> (4, 1) should be valid");
-@test fn kingmove() void = assert(kingmove(4, 0, 4, 2) == false, "(4, 0) -> (4, 2) should be invalid");
-@test fn kingmove() void = assert(kingmove(4, 0, 4, -1) == false, "(4, 0) -> (4, -1) should be invalid");
-@test fn kingmove() void = assert(kingmove(4, 0, 3, 0) == true, "(4, 0) -> (3, 0) should be valid");
-
-@test fn queenmove() void = assert(queenmove(3, 2, 3, 7) == true, "(3, 2) -> (3, 7) should be valid");
-@test fn queenmove() void = assert(queenmove(2, 3, 7, 2) == false, "(2, 3) -> (7, 2) should be invalid");
-@test fn queenmove() void = assert(queenmove(3, 3, 6, 6) == true, "(3, 3) -> (6, 6) should be valid");
-@test fn queenmove() void = assert(queenmove(3, 3, 6, 5) == false, "(3, 3) -> (6, 5) should be invalid");
-
-@test fn bishopmove() void = assert(bishopmove(3, 3, 6, 6) == true, "(3, 3) -> (6, 6) should be valid");
-@test fn bishopmove() void = assert(bishopmove(3, 3, 6, 2) == false, "(3, 3) -> (6, 2) should be invalid");
-
-@test fn rookmove() void = assert(rookmove(3, 3, 6, 6) == false, "(3, 3) -> (6, 6) should be invalid");
-@test fn rookmove() void = assert(rookmove(3, 3, 3, 7) == true, "(3, 3) -> (3, 7) should be valid");
-
-@test fn knightmove() void = assert(knightmove(0, 1, 2, 2) == true, "(0, 1) -> (2, 2) should be valid");
-@test fn knightmove() void = assert(knightmove(2, 2, 0, 1) == true, "(2, 2) -> (0, 1) should be valid");
-@test fn knightmove() void = assert(knightmove(2, 3, 0, 1) == false, "(2, 3) -> (0, 1) should be invalid");
-@test fn knightmove() void = assert(knightmove(2, 0, 0, 1) == true, "(2, 0) -> (0, 1) should be valid");
+ return false;
+};
diff --git a/cmd/betterchess/main.ha b/cmd/betterchess/main.ha
@@ -7,14 +7,22 @@ use chess;
export fn main() void = {
let b = chess::mkboard(8, 8);
- let p = match (chess::mkpiece(&b, 0, 0, chess::ptype::ROOK, chess::color::WHITE)) {
+ let p = match (chess::mkpiece(&b, 3, 6, chess::ptype::PAWN, chess::color::BLACK)) {
case let p: *chess::piece => yield p;
case => fmt::fatal("invalid placement");
};
- let p = match (chess::mkpiece(&b, 1, 0, chess::ptype::BISHOP, chess::color::WHITE)) {
+ let p = match (chess::mkpiece(&b, 2, 5, chess::ptype::PAWN, chess::color::WHITE)) {
case let p: *chess::piece => yield p;
case => fmt::fatal("invalid placement");
};
+
+ match (chess::movepiece(&b, 3, 6, 3, 4)) {
+ case chess::empty => fmt::println("empty space")!;
+ case chess::invalidmove => fmt::println("invalid move")!;
+ case chess::invalidplace => fmt::println("invalid place")!;
+ case => fmt::println("valid move")!;
+ };
+
chess::print_board(b, os::stdout);
};