-
Notifications
You must be signed in to change notification settings - Fork 1
/
tic-tac-toe.ts
99 lines (85 loc) · 3.51 KB
/
tic-tac-toe.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
type TicTacToeChip = "❌" | "⭕";
type TicTacToeEndState = "❌ Won" | "⭕ Won" | "Draw";
type TicTacToeState = TicTacToeChip | TicTacToeEndState;
type TicTacToeEmptyCell = " ";
type TicTacToeCell = TicTacToeChip | TicTacToeEmptyCell;
type TicTacToeYPositions = "top" | "middle" | "bottom";
type TicTacToeXPositions = "left" | "center" | "right";
type TicTacToePositions = `${TicTacToeYPositions}-${TicTacToeXPositions}`;
type TicTactToeBoard = TicTacToeCell[][];
type TicTacToeGame = {
board: TicTactToeBoard;
state: TicTacToeState;
};
type EmptyBoard = [[" ", " ", " "], [" ", " ", " "], [" ", " ", " "]];
type NewGame = {
board: EmptyBoard;
state: "❌";
};
type YToIdx = {
'top': 0,
'middle': 1,
'bottom': 2
}
type XToIdx = {
'left': 0,
'center': 1,
'right': 2
}
type ModifyRow<Row extends TicTactToeBoard[number], Chip extends TicTacToeChip, XPos extends TicTacToeXPositions> =
XPos extends 'left'
? Row extends [TicTacToeCell, ...infer Rest] ? [Chip, ...Rest] : never
: XPos extends 'right'
? Row extends [...infer First, TicTacToeCell] ? [...First, Chip] : never
: XPos extends 'center'
? Row extends [infer A extends TicTacToeCell, TicTacToeCell, infer B extends TicTacToeCell]
? [A, Chip, B]
: never
: never
type ModifyGame<Board extends TicTactToeBoard, NewPlacement extends TicTacToePositions, NewChip extends TicTacToeChip> =
NewPlacement extends `${infer YPosStr extends TicTacToeYPositions}-${infer XPosStr extends TicTacToeXPositions}`
? Board[YToIdx[YPosStr]][XToIdx[XPosStr]] extends " " ? {board: [
YToIdx[YPosStr] extends 0 ? ModifyRow<Board[0], NewChip, XPosStr> : Board[0],
YToIdx[YPosStr] extends 1 ? ModifyRow<Board[1], NewChip, XPosStr> : Board[1],
YToIdx[YPosStr] extends 2 ? ModifyRow<Board[2], NewChip, XPosStr> : Board[2]
], state: NewChip} : {board: Board, state: OmitUnion<TicTacToeChip, NewChip>}
: never;
type OmitUnion<A, B> = [A] extends [B | infer Rest] ? Rest : never
type GetColumn<Board extends TicTactToeBoard, Idx extends number> =
Board extends []
? []
: Board extends [infer First extends TicTactToeBoard[number], ...infer Rest extends TicTactToeBoard[number][]]
? [First[Idx], ...GetColumn<Rest, Idx>]
: never
type Transpose<Board extends TicTactToeBoard, Cur extends TicTactToeBoard = []> =
Cur['length'] extends Board['length']
? Cur
: Transpose<Board, [...Cur, GetColumn<Board, Cur['length']>]>
type CheckWin<Board extends TicTactToeBoard> =
["⭕", "⭕", "⭕"] extends Board[number]
? "⭕"
: ["❌", "❌", "❌"] extends Board[number]
? "❌"
: ' ' extends Board[number][number] ? never : false
type ModForWin<Game extends TicTacToeGame> =
[(CheckWin<Game['board']> | CheckWin<Transpose<Game['board']>>)] extends [infer Result extends TicTacToeChip | false]
? [Result] extends [never] ? {
board: Game['board'],
state: OmitUnion<TicTacToeChip, Game['state']>
} : Result extends false ? {
board: Game['board'],
state: "Draw"
} : {
board: Game['board'],
state: `${Result} Won`
}
: never
type Exiii = ModForWin<{
board: [["⭕", "❌", " "], [" ", "❌", " "], ["⭕", "❌", " "]],
state: "❌"
}>
type TicTacToe<
Game extends TicTacToeGame,
Move extends TicTacToePositions,
> = Game['state'] extends TicTacToeEndState ? Game : ModForWin<ModifyGame<Game['board'], Move, Game['state'] extends TicTacToeChip ? Game['state'] : never>>;
type Ex = TicTacToe<NewGame, "top-center">