Skip to content

Instantly share code, notes, and snippets.

@bolencki13
Created July 7, 2025 15:39
Show Gist options
  • Select an option

  • Save bolencki13/8d210154e4413d70dafd4fb6fdcfdac9 to your computer and use it in GitHub Desktop.

Select an option

Save bolencki13/8d210154e4413d70dafd4fb6fdcfdac9 to your computer and use it in GitHub Desktop.
TicTacToe in typescript types
// Game setup
type BoardPosition = [number, number];
type Space<Location extends BoardPosition, X extends BoardPosition[], Y extends BoardPosition[]> = Location extends X[number] ? 1 : Location extends Y[number] ? 2 : 0;
type Board<X extends BoardPosition[], Y extends BoardPosition[]> = [
[Space<[0,0], X, Y>,Space<[0,1], X, Y>,Space<[0,2], X, Y>],
[Space<[1,0], X, Y>,Space<[1,1], X, Y>,Space<[1,2], X, Y>],
[Space<[2,0], X, Y>,Space<[2,1], X, Y>,Space<[2,2], X, Y>]
];
// Validation
type HasValidRow<M extends BoardPosition[], R extends number> = [R, 0] extends M[number]
? [R, 1] extends M[number]
? [R, 2] extends M[number]
? true
: false
: false
: false;
type HasValidCol<M extends BoardPosition[], R extends number> = [0, R] extends M[number]
? [1, R] extends M[number]
? [2, R] extends M[number]
? true
: false
: false
: false;
type HasValidForwardSlash<M extends BoardPosition[]> = [0,0] extends M[number]
? [1, 1] extends M[number]
? [2, 2] extends M[number]
? true
: false
: false
: false;
type HasValidBackwardSlash<M extends BoardPosition[]> = [0,2] extends M[number]
? [1, 1] extends M[number]
? [2, 0] extends M[number]
? true
: false
: false
: false;
type ValidateBoardForUsersMoves<M extends BoardPosition[]> = HasValidRow<M, 0> extends false
? HasValidRow<M, 1> extends false
? HasValidRow<M, 2> extends false
? HasValidCol<M, 0> extends false
? HasValidCol<M, 1> extends false
? HasValidCol<M, 2> extends false
? HasValidForwardSlash<M> extends false
? HasValidBackwardSlash<M> extends false
? false
: true
: true
: true
: true
: true
: true
: true
: true;
type ValidateBoard<X extends BoardPosition[] = [], Y extends BoardPosition[] = []> =
ValidateBoardForUsersMoves<X> extends true
? 'X'
: ValidateBoardForUsersMoves<Y> extends true
? 'Y'
: null;
// Convert string of moves to a board position array
type ToNumber<S extends string> = S extends `${infer N extends number}` ? N : never
type GreaterThan<
N1 extends number,
N2 extends number,
A extends unknown[] = [],
> = A['length'] extends N1
? false
: A['length'] extends N2
? true
: GreaterThan<N1, N2, [0, ...A]>;
type HasValue<T extends string, C extends String> = T extends C ? true : false;
type RemoveUndefined<T extends unknown[]> = T extends [infer A, ...infer rest] ? [...(A extends undefined ? [] : [A]), ...RemoveUndefined<rest>] : [];
type StringToGrid<T extends string[], C extends string> = RemoveUndefined<{
[index in keyof T]: GreaterThan<ToNumber<`${index}`>, 5> extends true
? GreaterThan<ToNumber<`${index}`>, 7> extends true
? HasValue<T[index], C> extends true ? [2,2] : undefined
: GreaterThan<ToNumber<`${index}`>, 6> extends true
? HasValue<T[index], C> extends true ? [2,1] : undefined
: HasValue<T[index], C> extends true ? [2,0] : undefined
: GreaterThan<ToNumber<`${index}`>, 2> extends true
? GreaterThan<ToNumber<`${index}`>, 4> extends true
? HasValue<T[index], C> extends true ? [1,2] : undefined
: GreaterThan<ToNumber<`${index}`>, 3> extends true
? HasValue<T[index], C> extends true ? [1,1] : undefined
: HasValue<T[index], C> extends true ? [1,0] : undefined
: GreaterThan<ToNumber<`${index}`>, 1> extends true
? HasValue<T[index], C> extends true ? [0,2] : undefined
: GreaterThan<ToNumber<`${index}`>, 0> extends true
? HasValue<T[index], C> extends true ? [0,1] : undefined
: HasValue<T[index], C> extends true ? [0,0] : undefined
}>
type ToBoardPosition<T extends unknown> = T extends BoardPosition[] ? T : never;
// Game helpers
type TicTacToe<Game extends string[]> = ValidateBoard<ToBoardPosition<StringToGrid<Game, 'x'>>, ToBoardPosition<StringToGrid<Game, 'y'>>> extends 'X' ? 'X has won!' : ValidateBoard<ToBoardPosition<StringToGrid<Game, 'x'>>, ToBoardPosition<StringToGrid<Game, 'y'>>> extends 'Y' ? 'Y has won!' : 'No winner';
type Result = TicTacToe<[
'x','','y',
'y','y','',
'','x','x'
]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment