@wsabol/sudoku-solver 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import { ValidationResult } from "./validate.js";
2
2
  import type { Board } from "./boardGeo.js";
3
3
  import type { Move, EliminationMove } from "./move.js";
4
- export type Algorithm = "Last Digit" | "Full House" | "Naked Single" | "Hidden Single" | "Pointing Pair" | "Pointing Triple" | "Naked Pair" | "Naked Triple" | "Naked Quad" | "Hidden Pair" | "Hidden Triple" | "Hidden Quad";
4
+ export type Algorithm = "Last Digit" | "Full House" | "Naked Single" | "Hidden Single" | "Pointing Pair" | "Pointing Triple" | "X-Wing" | "Naked Pair" | "Naked Triple" | "Naked Quad" | "Hidden Pair" | "Hidden Triple" | "Hidden Quad";
5
5
  export type DifficultyLevel = "Easy" | "Medium" | "Hard" | "Diabolical" | "Impossible";
6
6
  export type ValidationReasonType = "duplicate_in_row" | "duplicate_in_column" | "duplicate_in_box" | "invalid_value" | "invalid_board_length" | "invalid_board_characters" | "empty_cell_no_candidates" | "too_many_empty_cells";
7
7
  export default class SudokuSolver {
@@ -43,6 +43,12 @@ export default class SudokuSolver {
43
43
  private findHiddenSingleInCol;
44
44
  private findHiddenSingleInBox;
45
45
  private findPointingPairTriple;
46
+ /** Empty cells in `row` where `digit` is still a candidate (column indices). */
47
+ private colsWithDigitCandidates;
48
+ /** Empty cells in `col` where `digit` is still a candidate (row indices). */
49
+ private rowsWithDigitCandidates;
50
+ /** Classic row/column X-Wing only (box forms duplicate pointing / line–box). */
51
+ private findXWing;
46
52
  private eachHouseInOrder;
47
53
  private findNakedSubsetElimination;
48
54
  /** `houseCells` is one full row, column, or box (9 cells). */
@@ -1 +1 @@
1
- {"version":3,"file":"sudokuSolver.d.ts","sourceRoot":"","sources":["../src/sudokuSolver.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,gBAAgB,EAAoB,MAAM,eAAe,CAAC;AACrF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,EAAE,IAAI,EAAiB,eAAe,EAAE,MAAM,WAAW,CAAC;AAEtE,MAAM,MAAM,SAAS,GACf,YAAY,GACZ,YAAY,GACZ,cAAc,GACd,eAAe,GACf,eAAe,GACf,iBAAiB,GACjB,YAAY,GACZ,cAAc,GACd,YAAY,GACZ,aAAa,GACb,eAAe,GACf,aAAa,CAAC;AAEpB,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,YAAY,GAAG,YAAY,CAAC;AAEvF,MAAM,MAAM,oBAAoB,GAC1B,kBAAkB,GAClB,qBAAqB,GACrB,kBAAkB,GAClB,eAAe,GACf,sBAAsB,GACtB,0BAA0B,GAC1B,0BAA0B,GAC1B,sBAAsB,CAAC;AA+C7B,MAAM,CAAC,OAAO,OAAO,YAAY;IAC7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAOnC;IAEF,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,aAAa,CAAe;gBAExB,KAAK,EAAE,MAAM,GAAG,KAAK;IAOjC,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAS5B,OAAO,IAAI,KAAK;IAIhB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE;IAIhD,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAIjE,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAmB7D,gBAAgB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI;IAM7C,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAQ3B,UAAU,IAAI,OAAO;IAIrB,eAAe,IAAI,MAAM;IAIzB,WAAW,CAAC,KAAK,GAAE,MAAU,GAAG,MAAM;IAOtC,QAAQ,IAAI,gBAAgB;IAiG5B,OAAO,IAAI,OAAO;IAKlB,UAAU,IAAI,eAAe;IAiB7B,WAAW,IAAI,IAAI,GAAG,IAAI;IAO1B,KAAK,IAAI,OAAO;IAchB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,MAAM;IAYd,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,mBAAmB;IAU3B,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,iBAAiB;IAkBzB,OAAO,CAAC,mBAAmB;IAqB3B,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,gBAAgB;IAmBxB,OAAO,CAAC,eAAe;IA+CvB,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,qBAAqB;IAsB7B,OAAO,CAAC,qBAAqB;IAsB7B,OAAO,CAAC,qBAAqB;IAuB7B,OAAO,CAAC,sBAAsB;IAqD9B,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,0BAA0B;IAUlC,8DAA8D;IAC9D,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,qBAAqB;IAwD7B,OAAO,CAAC,2BAA2B;IAUnC,OAAO,CAAC,+BAA+B;IAWvC,OAAO,CAAC,sBAAsB;IAgE9B,OAAO,CAAC,gBAAgB;CAe3B"}
1
+ {"version":3,"file":"sudokuSolver.d.ts","sourceRoot":"","sources":["../src/sudokuSolver.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,gBAAgB,EAAoB,MAAM,eAAe,CAAC;AACrF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,EAAE,IAAI,EAAiB,eAAe,EAAE,MAAM,WAAW,CAAC;AAEtE,MAAM,MAAM,SAAS,GACf,YAAY,GACZ,YAAY,GACZ,cAAc,GACd,eAAe,GACf,eAAe,GACf,iBAAiB,GACjB,QAAQ,GACR,YAAY,GACZ,cAAc,GACd,YAAY,GACZ,aAAa,GACb,eAAe,GACf,aAAa,CAAC;AAEpB,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,YAAY,GAAG,YAAY,CAAC;AAEvF,MAAM,MAAM,oBAAoB,GAC1B,kBAAkB,GAClB,qBAAqB,GACrB,kBAAkB,GAClB,eAAe,GACf,sBAAsB,GACtB,0BAA0B,GAC1B,0BAA0B,GAC1B,sBAAsB,CAAC;AAsD7B,MAAM,CAAC,OAAO,OAAO,YAAY;IAC7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAQnC;IAEF,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,aAAa,CAAe;gBAExB,KAAK,EAAE,MAAM,GAAG,KAAK;IAOjC,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAS5B,OAAO,IAAI,KAAK;IAIhB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE;IAIhD,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAIjE,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAmB7D,gBAAgB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI;IAM7C,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAQ3B,UAAU,IAAI,OAAO;IAIrB,eAAe,IAAI,MAAM;IAIzB,WAAW,CAAC,KAAK,GAAE,MAAU,GAAG,MAAM;IAOtC,QAAQ,IAAI,gBAAgB;IAiG5B,OAAO,IAAI,OAAO;IAKlB,UAAU,IAAI,eAAe;IAiB7B,WAAW,IAAI,IAAI,GAAG,IAAI;IAO1B,KAAK,IAAI,OAAO;IAchB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,MAAM;IAYd,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,mBAAmB;IAU3B,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,iBAAiB;IAkBzB,OAAO,CAAC,mBAAmB;IAqB3B,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,gBAAgB;IAqBxB,OAAO,CAAC,eAAe;IA+CvB,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,qBAAqB;IAsB7B,OAAO,CAAC,qBAAqB;IAsB7B,OAAO,CAAC,qBAAqB;IAuB7B,OAAO,CAAC,sBAAsB;IAqD9B,gFAAgF;IAChF,OAAO,CAAC,uBAAuB;IAU/B,6EAA6E;IAC7E,OAAO,CAAC,uBAAuB;IAU/B,gFAAgF;IAChF,OAAO,CAAC,SAAS;IA8DjB,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,0BAA0B;IAUlC,8DAA8D;IAC9D,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,qBAAqB;IAwD7B,OAAO,CAAC,2BAA2B;IAUnC,OAAO,CAAC,+BAA+B;IAWvC,OAAO,CAAC,sBAAsB;IAgE9B,OAAO,CAAC,gBAAgB;CAe3B"}
@@ -41,6 +41,7 @@ export default class SudokuSolver {
41
41
  "Pointing",
42
42
  "NakedSubset",
43
43
  "HiddenSubset",
44
+ "Fish",
44
45
  "NakedHiddenQuads",
45
46
  ];
46
47
  board;
@@ -322,6 +323,8 @@ export default class SudokuSolver {
322
323
  return this.findHiddenSingle();
323
324
  case "Pointing":
324
325
  return this.findPointingPairTriple();
326
+ case "Fish":
327
+ return this.findXWing();
325
328
  case "NakedSubset":
326
329
  return this.findNakedSubsetElimination();
327
330
  case "HiddenSubset":
@@ -498,6 +501,90 @@ export default class SudokuSolver {
498
501
  }
499
502
  return null;
500
503
  }
504
+ /** Empty cells in `row` where `digit` is still a candidate (column indices). */
505
+ colsWithDigitCandidates(row, digit) {
506
+ const cols = [];
507
+ for (let col = 0; col < 9; col++) {
508
+ if (this.board[row][col] === 0 && this.possiblesGrid[row][col].includes(digit)) {
509
+ cols.push(col);
510
+ }
511
+ }
512
+ return cols;
513
+ }
514
+ /** Empty cells in `col` where `digit` is still a candidate (row indices). */
515
+ rowsWithDigitCandidates(col, digit) {
516
+ const rows = [];
517
+ for (let row = 0; row < 9; row++) {
518
+ if (this.board[row][col] === 0 && this.possiblesGrid[row][col].includes(digit)) {
519
+ rows.push(row);
520
+ }
521
+ }
522
+ return rows;
523
+ }
524
+ /** Classic row/column X-Wing only (box forms duplicate pointing / line–box). */
525
+ findXWing() {
526
+ for (let digit = 1; digit <= 9; digit++) {
527
+ for (let r1 = 0; r1 < 9; r1++) {
528
+ const cols1 = this.colsWithDigitCandidates(r1, digit);
529
+ if (cols1.length !== 2)
530
+ continue;
531
+ const baseCols = [...cols1].sort((a, b) => a - b);
532
+ for (let r2 = r1 + 1; r2 < 9; r2++) {
533
+ const cols2 = this.colsWithDigitCandidates(r2, digit);
534
+ if (cols2.length !== 2)
535
+ continue;
536
+ const pair = [...cols2].sort((a, b) => a - b);
537
+ if (pair[0] !== baseCols[0] || pair[1] !== baseCols[1])
538
+ continue;
539
+ const eliminations = [];
540
+ for (const col of baseCols) {
541
+ for (let row = 0; row < 9; row++) {
542
+ if (row === r1 || row === r2)
543
+ continue;
544
+ if (this.board[row][col] === 0 && this.possiblesGrid[row][col].includes(digit)) {
545
+ eliminations.push({ row, col, value: digit });
546
+ }
547
+ }
548
+ }
549
+ if (eliminations.length > 0) {
550
+ const reasoning = `X-Wing on ${digit}: rows ${r1 + 1} and ${r2 + 1} each have ${digit} only in columns ${baseCols[0] + 1} and ${baseCols[1] + 1}, so ${digit} cannot appear elsewhere in those columns.`;
551
+ return this.finalizeElimination(eliminations, "X-Wing", reasoning);
552
+ }
553
+ }
554
+ }
555
+ }
556
+ for (let digit = 1; digit <= 9; digit++) {
557
+ for (let c1 = 0; c1 < 9; c1++) {
558
+ const rows1 = this.rowsWithDigitCandidates(c1, digit);
559
+ if (rows1.length !== 2)
560
+ continue;
561
+ const baseRows = [...rows1].sort((a, b) => a - b);
562
+ for (let c2 = c1 + 1; c2 < 9; c2++) {
563
+ const rows2 = this.rowsWithDigitCandidates(c2, digit);
564
+ if (rows2.length !== 2)
565
+ continue;
566
+ const pair = [...rows2].sort((a, b) => a - b);
567
+ if (pair[0] !== baseRows[0] || pair[1] !== baseRows[1])
568
+ continue;
569
+ const eliminations = [];
570
+ for (const row of baseRows) {
571
+ for (let col = 0; col < 9; col++) {
572
+ if (col === c1 || col === c2)
573
+ continue;
574
+ if (this.board[row][col] === 0 && this.possiblesGrid[row][col].includes(digit)) {
575
+ eliminations.push({ row, col, value: digit });
576
+ }
577
+ }
578
+ }
579
+ if (eliminations.length > 0) {
580
+ const reasoning = `X-Wing on ${digit}: columns ${c1 + 1} and ${c2 + 1} each have ${digit} only in rows ${baseRows[0] + 1} and ${baseRows[1] + 1}, so ${digit} cannot appear elsewhere in those rows.`;
581
+ return this.finalizeElimination(eliminations, "X-Wing", reasoning);
582
+ }
583
+ }
584
+ }
585
+ }
586
+ return null;
587
+ }
501
588
  eachHouseInOrder() {
502
589
  const houses = [];
503
590
  for (let r = 0; r < 9; r++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wsabol/sudoku-solver",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "TypeScript Sudoku solver module with solve, next move, describe, and validate APIs.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",