feat(chess): add attribute schema and piece fact shape (P2.5)
This commit is contained in:
parent
aabd4a396a
commit
ea4d6e9a69
2 changed files with 130 additions and 0 deletions
62
packages/chess/src/schema.test.ts
Normal file
62
packages/chess/src/schema.test.ts
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// @vitest-environment node
|
||||
import { describe, it, expect } from "vitest";
|
||||
import {
|
||||
GAME_ENTITY, chessFact, oppositeColor, PROMOTION_PIECES,
|
||||
type Square,
|
||||
} from "./schema.js";
|
||||
import type { EntityId } from "@paratype/rete";
|
||||
|
||||
const mkId = (n: number) => n as EntityId;
|
||||
|
||||
describe("GAME_ENTITY", () => {
|
||||
it("is EntityId 0", () => { expect(GAME_ENTITY).toBe(0); });
|
||||
});
|
||||
|
||||
describe("chessFact()", () => {
|
||||
it("creates typed PieceType fact", () => {
|
||||
const f = chessFact(mkId(1), "PieceType", "pawn");
|
||||
expect(f).toEqual({ id: 1, attr: "PieceType", value: "pawn" });
|
||||
});
|
||||
it("creates numeric Position fact", () => {
|
||||
const f = chessFact(mkId(2), "Position", 28);
|
||||
expect(f.value).toBe(28);
|
||||
expect(typeof f.value).toBe("number");
|
||||
});
|
||||
it("creates game-level Turn fact using GAME_ENTITY", () => {
|
||||
const f = chessFact(GAME_ENTITY, "Turn", "white");
|
||||
expect(f.id).toBe(0);
|
||||
expect(f.attr).toBe("Turn");
|
||||
});
|
||||
it("creates HasMoved boolean fact", () => {
|
||||
const f = chessFact(mkId(3), "HasMoved", false);
|
||||
expect(f.value).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("oppositeColor()", () => {
|
||||
it("white -> black", () => { expect(oppositeColor("white")).toBe("black"); });
|
||||
it("black -> white", () => { expect(oppositeColor("black")).toBe("white"); });
|
||||
});
|
||||
|
||||
describe("PROMOTION_PIECES", () => {
|
||||
it("has exactly 4 entries", () => { expect(PROMOTION_PIECES).toHaveLength(4); });
|
||||
it("excludes king and pawn", () => {
|
||||
expect(PROMOTION_PIECES).not.toContain("king");
|
||||
expect(PROMOTION_PIECES).not.toContain("pawn");
|
||||
});
|
||||
it("includes queen, rook, bishop, knight", () => {
|
||||
expect(PROMOTION_PIECES).toContain("queen");
|
||||
expect(PROMOTION_PIECES).toContain("rook");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Square encoding", () => {
|
||||
it("a1=0, h1=7, a8=56, h8=63, e4=28", () => {
|
||||
const a1: Square = 0;
|
||||
const h8: Square = 63;
|
||||
const e4: Square = 28; // rank3*8 + file4
|
||||
expect(a1).toBe(0);
|
||||
expect(h8).toBe(63);
|
||||
expect(e4).toBe(28);
|
||||
});
|
||||
});
|
||||
68
packages/chess/src/schema.ts
Normal file
68
packages/chess/src/schema.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* Chess attribute schema for @paratype/chess.
|
||||
* All EAV attribute types for the chess game.
|
||||
* Squares: 0..63 where square = rank * 8 + file
|
||||
* file: 0=a, 1=b, ..., 7=h
|
||||
* rank: 0=rank1, 1=rank2, ..., 7=rank8
|
||||
* e.g. a1=0, h1=7, a8=56, h8=63, e4=28
|
||||
*/
|
||||
import type { EntityId } from "@paratype/rete";
|
||||
|
||||
export type PieceType = "pawn" | "knight" | "bishop" | "rook" | "queen" | "king";
|
||||
export type PieceColor = "white" | "black";
|
||||
export type Square = number; // 0..63
|
||||
export type GameStatus = "active" | "checkmate" | "stalemate" | "draw";
|
||||
export type GameResult = PieceColor | "draw";
|
||||
|
||||
/** EntityId reserved for game-level facts (Turn, HalfmoveClock, etc.). */
|
||||
export const GAME_ENTITY: EntityId = 0 as EntityId;
|
||||
|
||||
/**
|
||||
* Maps attribute name to its TypeScript type.
|
||||
* Used for typed fact construction and WM queries.
|
||||
*/
|
||||
export interface ChessAttrMap {
|
||||
// Piece attributes
|
||||
PieceType: PieceType;
|
||||
Color: PieceColor;
|
||||
Position: Square;
|
||||
HasMoved: boolean;
|
||||
// Game-level attributes
|
||||
Turn: PieceColor;
|
||||
HalfmoveClock: number;
|
||||
FullmoveNumber: number;
|
||||
EnPassantTarget: Square | null;
|
||||
GameStatus: GameStatus;
|
||||
Winner: GameResult | null;
|
||||
// Custom rule attributes (from RULES.md presets)
|
||||
Hp: number;
|
||||
PoisonedSquare: boolean;
|
||||
}
|
||||
|
||||
export type ChessAttrKey = keyof ChessAttrMap;
|
||||
|
||||
/** A typed chess fact triple. */
|
||||
export interface ChessFact<K extends ChessAttrKey = ChessAttrKey> {
|
||||
readonly id: EntityId;
|
||||
readonly attr: K;
|
||||
readonly value: ChessAttrMap[K];
|
||||
}
|
||||
|
||||
/** Construct a typed chess fact. */
|
||||
export function chessFact<K extends ChessAttrKey>(
|
||||
id: EntityId,
|
||||
attr: K,
|
||||
value: ChessAttrMap[K],
|
||||
): ChessFact<K> {
|
||||
return { id, attr, value };
|
||||
}
|
||||
|
||||
/** Return the opposite color. */
|
||||
export function oppositeColor(color: PieceColor): PieceColor {
|
||||
return color === "white" ? "black" : "white";
|
||||
}
|
||||
|
||||
/** Valid promotion piece types (excludes pawn and king). */
|
||||
export const PROMOTION_PIECES: ReadonlyArray<PieceType> = [
|
||||
"queen", "rook", "bishop", "knight",
|
||||
];
|
||||
Loading…
Add table
Add a link
Reference in a new issue