Last active
December 21, 2023 12:13
-
-
Save martinkadlec0/bd87678c79ef1843ad28805191bab591 to your computer and use it in GitHub Desktop.
Advent of Typescript - Day 21 - Tic Tac Toe
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 WinLanes = [ | |
| // horizontal | |
| [[0,0], [0,1], [0,2]], | |
| [[1,0], [1,1], [1,2]], | |
| [[2,0], [2,1], [2,2]], | |
| // vertical | |
| [[0,0], [1,0], [2,0]], | |
| [[0,1], [1,1], [2,1]], | |
| [[0,2], [1,2], [2,2]], | |
| // diagonal | |
| [[0,0], [1,1], [2,2]], | |
| [[0,2], [1,1], [2,0]], | |
| ] | |
| type YMap = {'top': 0, 'middle': 1, 'bottom': 2} | |
| type XMap = {'left': 0, 'center': 1, 'right': 2} | |
| // Check if given Chip has a winning lane | |
| type CheckChip<TLanes extends number[][][], Board extends TicTactToeBoard, Chip extends TicTacToeChip> = | |
| TLanes extends [infer Lane extends number[][], ...infer Rest extends number[][][]] | |
| ? `${Board[Lane[0][0]][Lane[0][1]]}${Board[Lane[1][0]][Lane[1][1]]}${Board[Lane[2][0]][Lane[2][1]]}` extends `${Chip}${Chip}${Chip}` | |
| ? true | |
| : CheckChip<Rest, Board, Chip> | |
| : false | |
| type Flatten<T extends any[][], Acc extends any[] = []> = | |
| T extends [infer Item extends any[], ...infer Rest extends any[][]] | |
| ? Flatten<Rest, [...Acc, ...Item]> | |
| : Acc | |
| type IsDraw<Board extends TicTactToeBoard> = | |
| TicTacToeEmptyCell extends Flatten<Board>[number] ? false : true | |
| // Create new state value based on new board & current chip | |
| type FindState<Board extends TicTactToeBoard, Chip extends TicTacToeChip> = | |
| CheckChip<WinLanes, Board, Chip> extends true | |
| ? `${Chip} Won` | |
| : IsDraw<Board> extends true | |
| ? 'Draw' | |
| : Chip extends '⭕' ? '❌' : '⭕' | |
| // Goes over cells in given Row and puts Chip into given coordinate | |
| type ProcessCells<TCells extends TicTacToeCell[], XPos extends number, Chip extends TicTacToeChip> = { | |
| [K in keyof TCells]: K extends `${XPos}` ? Chip : TCells[K] | |
| } | |
| // Goes over rows in current board and puts Chip into given coordinates | |
| type ProcessRows<TBoard extends TicTactToeBoard, YPos extends number, XPos extends number, Chip extends TicTacToeChip> = { | |
| [K in keyof TBoard]: K extends `${YPos}` | |
| ? ProcessCells<TBoard[K], XPos, Chip> | |
| : TBoard[K] | |
| } | |
| type TicTacToe<TGame extends TicTacToeGame, TPos extends TicTacToePositions> = | |
| // Separate coordinates | |
| TPos extends `${infer YPos extends TicTacToeYPositions}-${infer XPos extends TicTacToeXPositions}` | |
| // Don't allow more moves once game is over | |
| ? TGame['state'] extends infer Chip extends TicTacToeChip | |
| // Don't allow overwriting of cells | |
| ? TGame['board'][YMap[YPos]][XMap[XPos]] extends TicTacToeEmptyCell | |
| // Create new board | |
| ? ProcessRows<TGame['board'], YMap[YPos], XMap[XPos], Chip> extends infer NewBoard extends TicTactToeBoard | |
| ? { | |
| board: NewBoard, | |
| state: FindState<NewBoard, Chip> | |
| } | |
| : TGame | |
| : TGame | |
| : TGame | |
| : TGame |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment