type Digits = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
type G1 = [0, 1, 2];
type G2 = [3, 4, 5];
type G3 = [6, 7, 8];
type IsPass<T extends number[]> = Digits extends T[number] ? true : false;
type Flatten<T extends number[][][]> = T extends [[infer G1 extends number[], infer G2 extends number[], infer G3 extends number[]], ...infer R extends number[][][]] ?
[[...G1, ...G2, ...G3], ...Flatten<R>] : [];
type ColCollector<T extends number[][], CI extends number, _I extends 1[] = []> =
_I[`length`] extends 9 ? [] : [T[_I[`length`]][CI], ...ColCollector<T, CI, [..._I, 1]>];
type GridCollector<T extends number[][][], CI extends number, _I extends 1[] = [],
_ColIndex extends number = [0, 1, 2, 0, 1, 2, 0, 1, 2][CI],
_RowIndex extends number = [G1, G1, G1, G2, G2, G2, G3, G3, G3][CI][_I[`length`]]> =
_I[`length`] extends 3 ? [] : [...T[_RowIndex][_ColIndex], ...GridCollector<T, CI, [..._I, 1]>];
type RowChecker<T extends number[][][]> = T extends [[infer G1 extends number[], infer G2 extends number[], infer G3 extends number[]], ...infer R extends number[][][]] ?
IsPass<[...G1, ...G2, ...G3]> extends true ? RowChecker<R> : false :
true;
type ColChecker<T extends number[][][], _IndexCounter extends 1[] = [], _Flatten extends number[][] = Flatten<T>> =
_IndexCounter[`length`] extends 9 ? true :
IsPass<ColCollector<_Flatten, _IndexCounter[`length`]>> extends true ? ColChecker<T, [..._IndexCounter, 1], _Flatten> : false;
type GridChecker<T extends number[][][], _IndexCounter extends 1[] = []> =
_IndexCounter[`length`] extends 9 ? true :
IsPass<GridCollector<T, _IndexCounter[`length`]>> extends true ? GridChecker<T, [..._IndexCounter, 1]> : false;
type SudokuSolved<T extends number[][][]> = RowChecker<T> | ColChecker<T> | GridChecker<T> extends true ? true : false;
Solution by E-uler #34717
type VerRows<T> = T extends [ infer F, ...infer R ]
? F extends [ [ infer A, infer B, infer C ], [ infer D, infer E, infer F ], [ infer G, infer H, infer I ] ]
? Digits extends [A, B, C, D, E, F, G, H, I][number]
? VerRows<R>
: false
: never
: true
type UndefHelper<T> = T extends undefined ? unknown : T
type VerCols<T, _R extends unknown[] = [], > = T extends [ infer F, ...infer R ]
? F extends [ [ infer A extends UndefHelper<_R[0]>, infer B extends UndefHelper<_R[1]>, infer C extends UndefHelper<_R[2]> ],
[ infer D extends UndefHelper<_R[3]>, infer E extends UndefHelper<_R[4]>, infer F extends UndefHelper<_R[5]> ],
[ infer G extends UndefHelper<_R[6]>, infer H extends UndefHelper<_R[7]>, infer I extends UndefHelper<_R[8]> ]
]
? VerCols<R, [ _R[0] | A, _R[1] | B, _R[2] | C, _R[3] | D, _R[4] | E, _R[5] | F, _R[6] | G, _R[7] | H, _R[8] | I ]>
: _R
: true
type VerGrids<T> = T extends [
[ infer A extends Digits[], ...infer RA ],
[ infer B extends Digits[], ...infer RB ],
[ infer C extends Digits[], ...infer RC ],
...infer R
] ? Digits extends A[number] | B[number] | C[number]
? VerGrids<[ [RA], [RB], [RC], ...R ]>
: false
: true
type Digits = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
type SudokuSolved<T> = VerRows<T> extends false ? false : VerCols<T> extends false ? false : VerGrids<T> extends false ? false : true
Solution by lvjiaxuan #33613
type Digit = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
type Group = [Digit, Digit, Digit]
type Row = [Group, Group, Group]
type Grid = [Row, Row, Row, Row, Row, Row, Row, Row, Row]
type RowGroups = [0, 0, 0, 1, 1, 1, 2, 2, 2]
type GroupNrs = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
type Index3 = 0 | 1 | 2
type Index9 = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
type Coord = `${Index9}${Index3}${Index3}`
type IdCoord<Crd = Coord> =
Crd extends `${infer R extends Index9}${infer G extends Index3}${infer C extends Index3}`
? `R${R}:${Crd}` | `C${GroupNrs[G][C]}:${Crd}` | `G${GroupNrs[RowGroups[R]][G]}:${Crd}`
: never
type Lookup<Grd extends Grid, IdCrd = IdCoord> =
IdCrd extends `${infer ID}:${infer R extends Index9}${infer G extends Index3}${infer C extends Index3}`
? `${ID}:${Grd[R][G][C]}`
: never
type Solved = `${'R' | 'C' | 'G'}${Index9}:${Digit}`
type SudokuSolved<Grd extends Grid> = Solved extends Lookup<Grd> ? true : false
The Diagnose
type below shows the exact problems with a solution, rather than just true
or false
.
type IndexNrs = [1, 2, 3, 4, 5, 6, 7, 8, 9]
type RCGNames = {R: 'row', C: 'column', G: 'group'}
// Evaluates to a union of all missing digits and respective locations.
type Diagnose<Grd extends Grid, Missing = Exclude<Solved, Lookup<Grd>>> =
[Missing] extends [never]
? 'Solution is correct!'
: Missing extends `${infer RCG extends keyof RCGNames}${infer Ix extends Index9}:${infer D}`
? `Missing ${D} in ${RCGNames[RCG]} ${IndexNrs[Ix]}`
: never
Solution by Oblosys #33407
type Digits = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
type SudokuSolved<Grid extends number[][][]> =
| CheckSubGrids<Grid>
| CheckRows<Tuple2union<Grid>>
| CheckColumns<Tuple2union<Grid>> extends true
? true
: false
type CheckSubGrids<Grid extends number[][][]> = Grid extends [
infer Grid1 extends number[][],
infer Gird2 extends number[][],
infer Grid3 extends number[][],
...infer Rest extends number[][][],
]
? CheckSubGrid<Grid1 | Gird2 | Grid3> extends true
? CheckSubGrids<Rest>
: false
: true
type CheckSubGrid<
SubGrid extends number[][],
C extends number = 0 | 1 | 2,
> = C extends C
? Digits extends Tuple2union<SubGrid[C]>
? true
: false
: never
type CheckRows<Rows extends number[][]> = Rows extends Rows
? Digits extends Tuple2union<Tuple2union<Rows>>
? true
: false
: never
type CheckColumns<
Rows extends number[][],
I extends number = 0 | 1 | 2,
J extends number = 0 | 1 | 2,
> = I extends I
? J extends J
? Digits extends Rows[I][J]
? true
: false
: never
: never
type Tuple2union<T extends any[]> = T[number]
Solution by Sun79 #33179
type Digits = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
type DigitsX3<D = Digits> = [D, D, D];
type Grid<Row = DigitsX3<DigitsX3>> = [Row, Row, Row, Row, Row, Row, Row, Row, Row];
type SudokuSolved<T extends Grid> = [ReturnType<<D extends Digits>() =>
| (D extends D ? (Digits extends RowValues<T, D> ? never : `Unresolved in Row ${D}`) : never)
| (D extends D ? (Digits extends ColValues<T, D> ? never : `Unresolved in Col ${D}`) : never)
| (D extends D ? Digits extends SubgridValues<T, D> ? never : `Unresolved in Subgrid ${D}` : never)
>] extends [never] ? true : false;
type RowValues<G extends Grid, Row extends Digits, _ extends number = number> = [never,
G[0][_][_],
G[1][_][_],
G[2][_][_],
G[3][_][_],
G[4][_][_],
G[5][_][_],
G[6][_][_],
G[7][_][_],
G[8][_][_],
][Row];
type ColValues<G extends Grid, Col extends Digits, _ extends number = number> = [never,
G[_][0][0], G[_][0][1], G[_][0][2], G[_][1][0], G[_][1][1], G[_][1][2], G[_][2][0], G[_][2][1], G[_][2][2],
][Col];
type SubgridValues<G extends Grid, Subgrid extends Digits, _ extends number = number> = [never,
G[0 | 1 | 2][0][_], G[0 | 1 | 2][1][_], G[0 | 1 | 2][2][_],
G[3 | 4 | 5][0][_], G[3 | 4 | 5][1][_], G[3 | 4 | 5][2][_],
G[6 | 7 | 8][0][_], G[6 | 7 | 8][1][_], G[6 | 7 | 8][2][_],
][Subgrid];
Solution by teamchong #33129