-
Notifications
You must be signed in to change notification settings - Fork 23
/
index.ts
105 lines (95 loc) · 2.34 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import { M, IsNever, CheckWinner, RenderBoard } from "./utils";
export type P1 = 1;
export type P2 = 2;
type Rows = 1 | 2 | 3;
type Cols = 1 | 2 | 3;
type Cell = 0 | P1 | P2;
export type FlattenBoardShape = [
Cell,
Cell,
Cell,
Cell,
Cell,
Cell,
Cell,
Cell,
Cell
];
type Players = {
P1: "p1";
P2: "p2";
};
type InsertOnBoard<
Board extends FlattenBoardShape,
RowIdx extends number,
ColIdx extends number,
Num
> = Extract<
{
[Row in keyof Board]: Row extends `${M.Add<
M.Multiply<M.Subtract<RowIdx, 1>, 3>,
M.Subtract<ColIdx, 1>
>}`
? Board[Row] extends 0
? Num
: "Invalid position"
: Board[Row];
},
FlattenBoardShape
>;
type GameState = {
board: FlattenBoardShape;
previousTurn: Players[keyof Players];
currentRow: Rows;
currentCol: Cols;
};
type NextState<State extends GameState> = ReturnType<Game<State>>;
type Turn<
State extends GameState,
Player extends keyof Players
> = State["previousTurn"] extends Players[Player]
? () => `Invalid turn, it's ${Player}'s turn`
: <R extends Rows, C extends Cols>(
row: R,
col: C
) => NextState<{
error: never;
board: InsertOnBoard<State["board"], R, C, Player extends "P1" ? 1 : 2>;
previousTurn: Players[Player];
currentRow: R;
currentCol: C;
}>;
type Game<
State extends GameState = {
board: [0, 0, 0, 0, 0, 0, 0, 0, 0];
previousTurn: Players["P2"];
currentRow: Rows;
currentCol: Cols;
}
> = () => {
p1: Turn<State, "P1">;
p2: Turn<State, "P2">;
checkWinner: CheckWinner<State["board"]> extends infer WinState
? WinState extends "Incomplete"
? () => "Incomplete"
: WinState extends "Tie"
? () => "Tie"
: (won: "Winner winner chicken dinner") => WinState
: never;
checkState: IsNever<State["board"]> extends true
? `Invalid turn by ${State["previousTurn"]}, Cell ${State["currentRow"]}-${State["currentCol"]} is already taken`
: () => State;
state: State;
board: State["board"];
ui: {
winner: CheckWinner<State["board"]>;
board: RenderBoard<State["board"], CheckWinner<State["board"]>>;
};
};
declare const game: Game;
const g = game().p1(1, 1).p2(2, 2).p1(1, 2).p2(3, 3).p1(2, 3);
// hover over these to check for game state
g.checkWinner();
g.checkState();
// hover over this to render board
g.ui.board;