31797-hard-sudoku

Back

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

Challenge 31797 - Sudoku

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

TypeScript playground

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];

Playground

Solution by teamchong #33129