-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path#21.ts
127 lines (117 loc) · 3.63 KB
/
#21.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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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 GetIndexFromPosition<
Pos extends TicTacToeYPositions | TicTacToeXPositions
> = Pos extends "top"
? 0
: Pos extends "left"
? 0
: Pos extends "middle"
? 1
: Pos extends "center"
? 1
: Pos extends "right"
? 2
: Pos extends "bottom"
? 2
: 0;
type EmptyBoard = [[" ", " ", " "], [" ", " ", " "], [" ", " ", " "]];
type NewGame = {
board: EmptyBoard;
state: "❌";
};
type CheckState<
Board extends TicTactToeBoard,
CurrentState extends TicTacToeChip,
PreviousBoard extends TicTactToeBoard
> = CheckInvalid<Board, PreviousBoard> extends true
? CurrentState
: CheckWin<Board, "❌"> extends true
? "❌ Won"
: CheckWin<Board, "⭕"> extends true
? "⭕ Won"
: CheckDraw<Board> extends true
? "Draw"
: CurrentState extends "❌"
? "⭕"
: "❌";
type AllLines<Board extends TicTactToeBoard> =
| (0 | 1 | 2 extends infer Line
? Line extends number
?
| [Board[0][Line], Board[1][Line], Board[2][Line]]
| [Board[Line][0], Board[Line][1], Board[Line][2]]
: never
: never)
| [Board[0][0], Board[1][1], Board[2][2]]
| [Board[0][2], Board[1][1], Board[2][0]];
// Credits to @phry for this type
type CheckWin<Board extends TicTactToeBoard, Player extends TicTacToeChip> = [
Player,
Player,
Player
] extends AllLines<Board>
? true
: false;
type CheckDraw<Board extends TicTactToeBoard> = Board extends TicTacToeChip[][]
? true
: false;
type CheckInvalid<
Board extends TicTactToeBoard,
PreviousBoard extends TicTactToeBoard
> = PreviousBoard extends Board ? true : false;
type PlayMove<
Board extends TicTactToeBoard,
Move extends string,
Player extends TicTacToeChip,
Acc extends TicTactToeBoard = []
> = Acc["length"] extends Board["length"]
? Acc
: Move extends `${infer TicTacToeYPosition extends TicTacToeYPositions}-${infer TicTacToeXPosition extends TicTacToeXPositions}`
? Acc["length"] extends GetIndexFromPosition<TicTacToeYPosition>
? PlayMove<
Board,
Move,
Player,
[...Acc, PlayMoveColumn<Board[Acc["length"]], Move, Player>]
>
: PlayMove<Board, Move, Player, [...Acc, Board[Acc["length"]]]>
: never;
type PlayMoveColumn<
Row extends TicTacToeCell[],
Move extends string,
Player extends TicTacToeChip,
Acc extends TicTacToeCell[] = []
> = Acc["length"] extends Row["length"]
? Acc
: Move extends `${infer TicTacToeYPosition extends TicTacToeYPositions}-${infer TicTacToeXPosition extends TicTacToeXPositions}`
? Acc["length"] extends GetIndexFromPosition<TicTacToeXPosition>
? Row[Acc["length"]] extends " "
? PlayMoveColumn<Row, Move, Player, [...Acc, Player]>
: PlayMoveColumn<Row, Move, Player, [...Acc, Row[Acc["length"]]]>
: PlayMoveColumn<Row, Move, Player, [...Acc, Row[Acc["length"]]]>
: never;
type TicTacToe<
Game extends TicTacToeGame,
Move extends string
> = Game["state"] extends TicTacToeChip
? {
board: PlayMove<Game["board"], Move, Game["state"]>;
state: CheckState<
PlayMove<Game["board"], Move, Game["state"]>,
Game["state"],
Game["board"]
>;
}
: Game;