数独
更新时间:2023-02-22 15:57:53标签:算法web前端游戏
暴力破解大法
6 | 4 | |||||||
2 | 5 | 1 | ||||||
9 | 6 | 7 | ||||||
7 | 5 | 9 | ||||||
2 | 4 | |||||||
2 | 3 | 6 | ||||||
1 | 9 | 5 | ||||||
9 | 1 | 3 | ||||||
8 | 7 |
1import { sleep } from '@shared/utils';23class Sudoku {4 static readonly nums = [1, 2, 3, 4, 5, 6, 7, 8, 9];5 static readonly square = 9;6 static generateEmptyBoards() {7 return new Array(Sudoku.square).fill(null).map(() => new Array(Sudoku.square).fill(null)) as (null | number)[][];8 }9 private row = 0;10 private column = 0;11 private original = Sudoku.generateEmptyBoards();12 private direction: 'forward' | 'back' = 'forward';13 private abortController?: AbortController;1415 public boards = Sudoku.generateEmptyBoards();1617 constructor(boards: (null | number)[][] = []) {18 this.init(boards);19 }2021 public init(boards: (null | number)[][]) {22 for (let i = 0; i < this.original.length; i += 1) {23 for (let j = 0; j < this.original[i].length; j += 1) {24 this.original[i][j] = boards?.[i]?.[j] ?? null;25 }26 }27 this.reset();28 }29 public reset() {30 this.row = 0;31 this.column = 0;32 this.boards = this.original.map(row => [...row]);33 }34 public fill() {35 if (this.original[this.row][this.column] === null) {36 const rows = this.boards[this.row];37 const columns = this.boards.map(row => row[this.column]);38 const startColumn = this.column - this.column % 3;39 const startRow = this.row - this.row % 3;40 const squares = this.boards.reduce((pre, current, index) => {41 if (index >= startRow && index < startRow + 3) {42 pre.push(...current.slice(startColumn, startColumn + 3));43 }44 return pre;45 }, [] as (number | null)[]);46 const availableNums = Sudoku.nums.filter(num => !rows.includes(num) && !columns.includes(num) && !squares.includes(num));47 const available = availableNums.find(num => {48 const current = this.boards[this.row][this.column];49 return current === null || num > current;50 });51 if (available) {52 this.boards[this.row][this.column] = available;53 this.direction = 'forward';54 } else {55 this.boards[this.row][this.column] = null;56 this.direction = 'back';57 }58 }59 }60 private round() {61 if (this.column > Sudoku.square - 1) {62 this.row += 1;63 this.column = 0;64 return true;65 }66 if (this.column < 0) {67 this.row -= 1;68 this.column = Sudoku.square - 1;69 return true;70 }71 this.fill();72 this.column = this.direction === 'forward' ? this.column + 1 : this.column - 1;73 return false;74 }75 public destroy() {76 this.abortController?.abort();77 }78 public async async(cb?: (boards: (number | null)[][]) => void, millisecond = 0) {79 this.abortController = new AbortController();80 this.reset();81 while (this.row < Sudoku.square && this.row >= 0) {82 if (this.round()) continue;83 await sleep(millisecond, this.abortController.signal);84 cb?.(this.boards);85 }86 if (this.row < 0) {87 throw new Error('无解');88 }89 return this.boards;90 }91 public sync() {92 this.reset();93 while (this.row < Sudoku.square && this.row >= 0) {94 this.round();95 }96 if (this.row < 0) {97 throw new Error('无解');98 }99 return this.boards;100 }101}102103export { Sudoku };