fix: tests and infer props
This commit is contained in:
@@ -1,31 +1,27 @@
|
||||
// NOTE: will work as long as React keeps the props as the first argument in the functional components
|
||||
type ArgumentTypes<F extends Function> = F extends (
|
||||
props: infer TT,
|
||||
...args: any
|
||||
) => any
|
||||
? TT
|
||||
: never;
|
||||
type ArgumentTypes<F extends React.FC<any>> = F extends React.FC<infer TT>
|
||||
? TT
|
||||
: never;
|
||||
|
||||
type Head<T extends Array<Function>> = T extends [
|
||||
infer TT extends Function,
|
||||
...any
|
||||
type Head<T extends Array<React.FC<any>>> = T extends [
|
||||
infer TT extends React.FC<any>,
|
||||
...any
|
||||
]
|
||||
? TT
|
||||
: never;
|
||||
? TT
|
||||
: never;
|
||||
|
||||
type Tail<T extends Array<Function>> = T extends [
|
||||
any,
|
||||
...infer TT extends Array<Function>
|
||||
type Tail<T extends Array<React.FC<any>>> = T extends [
|
||||
any,
|
||||
...infer TT extends Array<React.FC<any>>
|
||||
]
|
||||
? TT
|
||||
: never;
|
||||
? TT
|
||||
: never;
|
||||
|
||||
type UglyInferProps<T extends Array<Function>> = T extends [Function]
|
||||
? ArgumentTypes<Head<T>>
|
||||
: ArgumentTypes<Head<T>> & UglyInferProps<Tail<T>>;
|
||||
type UglyInferProps<T extends Array<React.FC<any>>> = T extends [React.FC<any>]
|
||||
? ArgumentTypes<Head<T>>
|
||||
: ArgumentTypes<Head<T>> & UglyInferProps<Tail<T>>;
|
||||
|
||||
type Prettify<T> = { [K in keyof T]: T[K] } & {};
|
||||
|
||||
type InferProps<T extends Array<Function>> = Prettify<UglyInferProps<T>>;
|
||||
type InferProps<T extends Array<React.FC<any>>> = Prettify<UglyInferProps<T>>;
|
||||
|
||||
export default InferProps;
|
||||
|
||||
@@ -1,28 +1,52 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import Chess, { InternalMove, MOVE_FLAGS, Square } from "../engine";
|
||||
import Chess, {
|
||||
COLOR,
|
||||
Color,
|
||||
InternalMove,
|
||||
MOVE_FLAGS,
|
||||
Square,
|
||||
} from "../engine";
|
||||
|
||||
type TestMove = Omit<InternalMove, "piece">;
|
||||
|
||||
type ExpectedMoves = Record<
|
||||
string,
|
||||
{
|
||||
square: Square;
|
||||
moves: InternalMove[];
|
||||
moves: Array<TestMove>;
|
||||
}[]
|
||||
>;
|
||||
|
||||
function runTest(fen: string, expectedMoves: ExpectedMoves) {
|
||||
function runTest(fen: string, expectedMoves: ExpectedMoves, color?: Color) {
|
||||
const chess = Chess.load(fen);
|
||||
|
||||
Object.keys(expectedMoves).forEach((key) =>
|
||||
test(key.split("_").join(" "), () =>
|
||||
expectedMoves[key].forEach(({ square, moves: expectedMoves }) => {
|
||||
const moves = chess.getMovesForSquare(square);
|
||||
test(
|
||||
key
|
||||
.split("_")
|
||||
.concat([color ?? ""])
|
||||
.join(" "),
|
||||
() =>
|
||||
expectedMoves[key].forEach(({ square, moves: expectedMoves }) => {
|
||||
const moves: Array<TestMove> = chess
|
||||
.getMovesForSquare(square)
|
||||
.map(({ from, to, flags, promotion }) => {
|
||||
return promotion
|
||||
? {
|
||||
from,
|
||||
to,
|
||||
flags,
|
||||
promotion,
|
||||
}
|
||||
: { from, to, flags };
|
||||
});
|
||||
|
||||
expect(moves).toHaveLength(expectedMoves.length);
|
||||
moves.forEach((move) => expect(expectedMoves).toContainEqual(move));
|
||||
expectedMoves.forEach((expectedMove) =>
|
||||
expect(moves).toContainEqual(expectedMove)
|
||||
);
|
||||
})
|
||||
expect(moves).toHaveLength(expectedMoves.length);
|
||||
moves.forEach((move) => expect(expectedMoves).toContainEqual(move));
|
||||
expectedMoves.forEach((expectedMove) =>
|
||||
expect(moves).toContainEqual(expectedMove)
|
||||
);
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -32,8 +56,8 @@ function runTests(
|
||||
expectedMovesW: ExpectedMoves,
|
||||
expectedMovesB: ExpectedMoves
|
||||
) {
|
||||
runTest(fen.replace("%", "w"), expectedMovesW);
|
||||
runTest(fen.replace("%", "b"), expectedMovesB);
|
||||
runTest(fen.replace("%", "w"), expectedMovesW, COLOR.WHITE);
|
||||
runTest(fen.replace("%", "b"), expectedMovesB, COLOR.BLACK);
|
||||
}
|
||||
|
||||
describe("pawn moves", () => {
|
||||
@@ -55,6 +79,30 @@ describe("pawn moves", () => {
|
||||
{ from: "b7", to: "b8", flags: MOVE_FLAGS.PROMOTION, promotion: "b" },
|
||||
{ from: "b7", to: "b8", flags: MOVE_FLAGS.PROMOTION, promotion: "r" },
|
||||
{ from: "b7", to: "b8", flags: MOVE_FLAGS.PROMOTION, promotion: "q" },
|
||||
{
|
||||
from: "b7",
|
||||
to: "a8",
|
||||
flags: MOVE_FLAGS.PROMOTION | MOVE_FLAGS.CAPTURE,
|
||||
promotion: "n",
|
||||
},
|
||||
{
|
||||
from: "b7",
|
||||
to: "a8",
|
||||
flags: MOVE_FLAGS.PROMOTION | MOVE_FLAGS.CAPTURE,
|
||||
promotion: "b",
|
||||
},
|
||||
{
|
||||
from: "b7",
|
||||
to: "a8",
|
||||
flags: MOVE_FLAGS.PROMOTION | MOVE_FLAGS.CAPTURE,
|
||||
promotion: "r",
|
||||
},
|
||||
{
|
||||
from: "b7",
|
||||
to: "a8",
|
||||
flags: MOVE_FLAGS.PROMOTION | MOVE_FLAGS.CAPTURE,
|
||||
promotion: "q",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -99,6 +147,30 @@ describe("pawn moves", () => {
|
||||
{ from: "g2", to: "g1", flags: MOVE_FLAGS.PROMOTION, promotion: "b" },
|
||||
{ from: "g2", to: "g1", flags: MOVE_FLAGS.PROMOTION, promotion: "r" },
|
||||
{ from: "g2", to: "g1", flags: MOVE_FLAGS.PROMOTION, promotion: "q" },
|
||||
{
|
||||
from: "g2",
|
||||
to: "h1",
|
||||
flags: MOVE_FLAGS.PROMOTION | MOVE_FLAGS.CAPTURE,
|
||||
promotion: "n",
|
||||
},
|
||||
{
|
||||
from: "g2",
|
||||
to: "h1",
|
||||
flags: MOVE_FLAGS.PROMOTION | MOVE_FLAGS.CAPTURE,
|
||||
promotion: "b",
|
||||
},
|
||||
{
|
||||
from: "g2",
|
||||
to: "h1",
|
||||
flags: MOVE_FLAGS.PROMOTION | MOVE_FLAGS.CAPTURE,
|
||||
promotion: "r",
|
||||
},
|
||||
{
|
||||
from: "g2",
|
||||
to: "h1",
|
||||
flags: MOVE_FLAGS.PROMOTION | MOVE_FLAGS.CAPTURE,
|
||||
promotion: "q",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -131,7 +203,7 @@ describe("pawn moves", () => {
|
||||
};
|
||||
|
||||
runTests(
|
||||
"7k/1Pp1p2p/2P2p2/4p3/3P4/2P5/P5p1/K7 % - - 0 1",
|
||||
"r6k/1Pp1p2p/2P2p2/4p3/3P4/2P5/P5p1/K6R % - - 0 1",
|
||||
expectedMovesW,
|
||||
expectedMovesB
|
||||
);
|
||||
@@ -213,7 +285,7 @@ describe("knight moves", () => {
|
||||
square: "c3",
|
||||
moves: [
|
||||
{ from: "c3", to: "e4", flags: MOVE_FLAGS.NORMAL },
|
||||
{ from: "c3", to: "b5", flags: MOVE_FLAGS.CAPTURE },
|
||||
{ from: "c3", to: "b5", flags: MOVE_FLAGS.NORMAL },
|
||||
{ from: "c3", to: "a4", flags: MOVE_FLAGS.NORMAL },
|
||||
{ from: "c3", to: "a2", flags: MOVE_FLAGS.CAPTURE },
|
||||
{ from: "c3", to: "b1", flags: MOVE_FLAGS.NORMAL },
|
||||
@@ -225,7 +297,7 @@ describe("knight moves", () => {
|
||||
};
|
||||
|
||||
runTests(
|
||||
"n7/1n6/8/1K1kN3/8/2n5/N5N1/7N % - - 0 1",
|
||||
"n7/Kn6/8/3kN3/8/2n5/N5N1/7N % - - 0 1",
|
||||
expectedMovesW,
|
||||
expectedMovesB
|
||||
);
|
||||
|
||||
+20
-16
@@ -11,7 +11,7 @@ export const PIECE = Object.freeze({
|
||||
} as const);
|
||||
|
||||
function isPieceValid(string: string): boolean {
|
||||
return (Object.values(PIECE) as string[]).includes(string);
|
||||
return (Object.values(PIECE) as Array<string>).includes(string);
|
||||
}
|
||||
|
||||
export const PIECE_PROMOTION = Object.freeze([
|
||||
@@ -34,7 +34,7 @@ export type Piece = {
|
||||
color: Color;
|
||||
};
|
||||
|
||||
export type Board = (Piece | null)[];
|
||||
export type Board = Array<Piece | null>;
|
||||
|
||||
// prettier-ignore
|
||||
export const SQUARES = Object.freeze([
|
||||
@@ -331,12 +331,16 @@ function generatePawnMoves(
|
||||
color: Color,
|
||||
board: Readonly<Board>,
|
||||
enPassantSquare: Square
|
||||
): InternalMove[] {
|
||||
): Array<InternalMove> {
|
||||
if (board[position] == null) return [];
|
||||
|
||||
const moves: InternalMove[] = [];
|
||||
const moves: Array<InternalMove> = [];
|
||||
|
||||
const generatePromotionMoves = (from: number, to: number, flag: MoveFlag) => {
|
||||
const generatePromotionMoves = (
|
||||
from: number,
|
||||
to: number,
|
||||
flag?: MoveFlag
|
||||
) => {
|
||||
const fromAlgebraic = algebraic(from);
|
||||
const toAlgebraic = algebraic(to);
|
||||
|
||||
@@ -346,7 +350,7 @@ function generatePawnMoves(
|
||||
from: fromAlgebraic,
|
||||
to: toAlgebraic,
|
||||
promotion: piece,
|
||||
flags: MOVE_FLAGS.PROMOTION | flag,
|
||||
flags: MOVE_FLAGS.PROMOTION | (flag ?? 0),
|
||||
})
|
||||
);
|
||||
};
|
||||
@@ -356,7 +360,7 @@ function generatePawnMoves(
|
||||
|
||||
if (board[nextPosition] == null)
|
||||
if (rank(nextPosition) == PAWN_MOVE_INFO[color].promotion)
|
||||
generatePromotionMoves(position, nextPosition, MOVE_FLAGS.NORMAL);
|
||||
generatePromotionMoves(position, nextPosition);
|
||||
else {
|
||||
moves.push({
|
||||
piece: { type: PIECE.PAWN, color },
|
||||
@@ -409,13 +413,13 @@ export function generatePieceMoves(
|
||||
piece: Piece,
|
||||
board: Readonly<Board>,
|
||||
enPassantSquare: Square
|
||||
): InternalMove[] {
|
||||
): Array<InternalMove> {
|
||||
if (piece.type == PIECE.PAWN)
|
||||
return generatePawnMoves(position, piece.color, board, enPassantSquare);
|
||||
|
||||
const type = piece.type; // hacked the type system
|
||||
const generateOnce = () => {
|
||||
const moves: InternalMove[] = [];
|
||||
const moves: Array<InternalMove> = [];
|
||||
|
||||
PIECE_MOVE_INFO[type].moves.forEach(({ offset, excludedFiles }) => {
|
||||
if (excludedFiles.includes(file(position))) return;
|
||||
@@ -446,7 +450,7 @@ export function generatePieceMoves(
|
||||
};
|
||||
|
||||
const generateMultiple = () => {
|
||||
const moves: InternalMove[] = [];
|
||||
const moves: Array<InternalMove> = [];
|
||||
|
||||
PIECE_MOVE_INFO[type].moves.forEach(({ offset, excludedFiles }) => {
|
||||
if (excludedFiles.includes(file(position))) return;
|
||||
@@ -509,9 +513,9 @@ export default class Chess {
|
||||
private _fullMoves;
|
||||
private _kings;
|
||||
|
||||
private _moves: InternalMove[] = [];
|
||||
private _attacks: number[] = [];
|
||||
private _history: Readonly<{ fen: string; san: string }>[] = [];
|
||||
private _moves: Array<InternalMove> = [];
|
||||
private _attacks: Array<number> = [];
|
||||
private _history: Array<Readonly<{ fen: string; san: string }>> = [];
|
||||
private _enableProcessMoves = true;
|
||||
private _boardPositionCounter = new Map<string, number>();
|
||||
|
||||
@@ -702,7 +706,7 @@ export default class Chess {
|
||||
if (this._castling.b & MOVE_FLAGS.Q_CASTLE) castling += "q";
|
||||
if (castling == "") castling = "-";
|
||||
|
||||
const arr: any[] = [
|
||||
const arr: Array<any> = [
|
||||
position.substring(1), // remove first '/'
|
||||
this._turn,
|
||||
castling,
|
||||
@@ -743,7 +747,7 @@ export default class Chess {
|
||||
return str;
|
||||
}
|
||||
|
||||
getMoves(): InternalMove[] {
|
||||
getMoves(): Array<InternalMove> {
|
||||
return this._moves;
|
||||
}
|
||||
|
||||
@@ -765,7 +769,7 @@ export default class Chess {
|
||||
}, this);
|
||||
}
|
||||
|
||||
getMovesForSquare(square: Square): InternalMove[] {
|
||||
getMovesForSquare(square: Square): Array<InternalMove> {
|
||||
return this._moves.filter(({ from }) => from == square);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user