Files

322 lines
9.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
id: 5a23c84252665b21eecc803c
title: Судоку
challengeType: 5
forumTopicId: 302329
dashedName: sudoku
---
# --description--
Напишіть функцію, яка вирішить частково заповнений стандартний квадрат [судоку](https://en.wikipedia.org/wiki/Sudoku) розміром 9х9 та поверне результат. Порожні поля представлені як `-1`. [Алгоритми вирішення судоку](https://en.wikipedia.org/wiki/Algorithmics_of_sudoku) можуть допомогти з реалізацією.
# --hints--
`solveSudoku` має бути функцією.
```js
assert(typeof solveSudoku == 'function');
```
`solveSudoku([[8, 1, 9, -1, -1, 5, -1, -1, -1],[-1, -1, 2, -1, -1, -1, 7, 5, -1],[-1, 3, 7, 1, -1, 4, -1, 6, -1],[4, -1, -1, 5, 9, -1, 1, -1, -1],[7, -1, -1, 3, -1, 8, -1, -1, 2],[-1, -1, 3, -1, 6, 2, -1, -1, 7],[-1, 5, -1, 7, -1, 9, 2, 1, -1],[-1, 6, 4, -1, -1, -1, 9, -1, -1],[-1, -1, -1, 2, -1, -1, 4, 3, 8]])` має повернути масив.
```js
assert(
Array.isArray(
solveSudoku([
[8, 1, 9, -1, -1, 5, -1, -1, -1],
[-1, -1, 2, -1, -1, -1, 7, 5, -1],
[-1, 3, 7, 1, -1, 4, -1, 6, -1],
[4, -1, -1, 5, 9, -1, 1, -1, -1],
[7, -1, -1, 3, -1, 8, -1, -1, 2],
[-1, -1, 3, -1, 6, 2, -1, -1, 7],
[-1, 5, -1, 7, -1, 9, 2, 1, -1],
[-1, 6, 4, -1, -1, -1, 9, -1, -1],
[-1, -1, -1, 2, -1, -1, 4, 3, 8]
])
)
);
```
`вирішитиСудоку([[8, 1, 9, -1, -1, 5, -1, -1, -1],[-1, -1, 2, -1, -1, -1, 7, 5, -1],[-1, 3, 7, 1, -1, 4, -1, 6, -1],[4, -1, -1, 5, 9, -1, 1, -1, -1],[7, -1, -1, 3, -1, 8, -1, -1, 2],[-1, -1, 3, -1, 6, 2, -1, -1, 7],[-1, 5, -1, 7, -1, 9, 2, 1, -1],[-1, 6, 4, -1, -1, -1, 9, -1, -1],[-1, -1, -1, 2, -1, -1, 4, 3, 8]])` має повернути `[[8, 1, 9, 6, 7, 5, 3, 2, 4],[6, 4, 2, 9, 8, 3, 7, 5, 1],[5, 3, 7, 1, 2, 4, 8, 6, 9],[4, 2, 6, 5, 9, 7, 1, 8, 3],[7, 9, 5, 3, 1, 8, 6, 4, 2],[1, 8, 3, 4, 6, 2, 5, 9, 7],[3, 5, 8, 7, 4, 9, 2, 1, 6],[2, 6, 4, 8, 3, 1, 9, 7, 5],[9, 7, 1, 2, 5, 6, 4, 3, 8]]`.
```js
assert.deepEqual(
solveSudoku([
[8, 1, 9, -1, -1, 5, -1, -1, -1],
[-1, -1, 2, -1, -1, -1, 7, 5, -1],
[-1, 3, 7, 1, -1, 4, -1, 6, -1],
[4, -1, -1, 5, 9, -1, 1, -1, -1],
[7, -1, -1, 3, -1, 8, -1, -1, 2],
[-1, -1, 3, -1, 6, 2, -1, -1, 7],
[-1, 5, -1, 7, -1, 9, 2, 1, -1],
[-1, 6, 4, -1, -1, -1, 9, -1, -1],
[-1, -1, -1, 2, -1, -1, 4, 3, 8]
]),
[
[8, 1, 9, 6, 7, 5, 3, 2, 4],
[6, 4, 2, 9, 8, 3, 7, 5, 1],
[5, 3, 7, 1, 2, 4, 8, 6, 9],
[4, 2, 6, 5, 9, 7, 1, 8, 3],
[7, 9, 5, 3, 1, 8, 6, 4, 2],
[1, 8, 3, 4, 6, 2, 5, 9, 7],
[3, 5, 8, 7, 4, 9, 2, 1, 6],
[2, 6, 4, 8, 3, 1, 9, 7, 5],
[9, 7, 1, 2, 5, 6, 4, 3, 8]
]
);
```
`вирішитиСудоку([[5, 3, -1, -1, 2, 4, 7, -1, -1],[-1, -1, 2, -1, -1, -1, 8, -1, -1],[1, -1, -1, 7, -1, 3, 9, -1, 2],[-1, -1, 8, -1, 7, 2, -1, 4, 9],[-1, 2, -1, 9, 8, -1, -1, 7, -1],[7, 9, -1, -1, -1, -1, -1, 8, -1],[-1, -1, -1, -1, 3, -1, 5, -1, 6],[9, 6, -1, -1, 1, -1, 3, -1, -1],[-1, 5, -1, 6, 9, -1, -1, 1, -1]])` має повернути `[[5, 3, 9, 8, 2, 4, 7, 6, 1],[6, 7, 2, 1, 5, 9, 8, 3, 4],[1, 8, 4, 7, 6, 3, 9, 5, 2],[3, 1, 8, 5, 7, 2, 6, 4, 9],[4, 2, 5, 9, 8, 6, 1, 7, 3],[7, 9, 6, 3, 4, 1, 2, 8, 5],[8, 4, 1, 2, 3, 7, 5, 9, 6],[9, 6, 7, 4, 1, 5, 3, 2, 8],[2, 5, 3, 6, 9, 8, 4, 1, 7]]`.
```js
assert.deepEqual(
solveSudoku([
[5, 3, -1, -1, 2, 4, 7, -1, -1],
[-1, -1, 2, -1, -1, -1, 8, -1, -1],
[1, -1, -1, 7, -1, 3, 9, -1, 2],
[-1, -1, 8, -1, 7, 2, -1, 4, 9],
[-1, 2, -1, 9, 8, -1, -1, 7, -1],
[7, 9, -1, -1, -1, -1, -1, 8, -1],
[-1, -1, -1, -1, 3, -1, 5, -1, 6],
[9, 6, -1, -1, 1, -1, 3, -1, -1],
[-1, 5, -1, 6, 9, -1, -1, 1, -1]
]),
[
[5, 3, 9, 8, 2, 4, 7, 6, 1],
[6, 7, 2, 1, 5, 9, 8, 3, 4],
[1, 8, 4, 7, 6, 3, 9, 5, 2],
[3, 1, 8, 5, 7, 2, 6, 4, 9],
[4, 2, 5, 9, 8, 6, 1, 7, 3],
[7, 9, 6, 3, 4, 1, 2, 8, 5],
[8, 4, 1, 2, 3, 7, 5, 9, 6],
[9, 6, 7, 4, 1, 5, 3, 2, 8],
[2, 5, 3, 6, 9, 8, 4, 1, 7]
]
);
```
`solveSudoku([[-1, -1, 3, -1, 2, -1, 6, -1, -1],[9, -1, -1, 3, -1, 5, -1, -1, 1],[-1, -1, 1, 8, -1, 6, 4, -1, -1],[-1, -1, 8, 1, -1, 2, 9, -1, -1],[7, -1, -1, -1, -1, -1, -1, -1, 8],[-1, -1, 6, 7, -1, 8, 2, -1, -1],[-1, -1, 2, 6, -1, 9, 5, -1, -1],[8, -1, -1, 2, -1, 3, -1, -1, 9],[-1, -1, 5, -1, 1, -1, 3, -1, -1]])` має повернути`[[4, 8, 3, 9, 2, 1, 6, 5, 7],[9, 6, 7, 3, 4, 5, 8, 2, 1],[2, 5, 1, 8, 7, 6, 4, 9, 3],[5, 4, 8, 1, 3, 2, 9, 7, 6],[7, 2, 9, 5, 6, 4, 1, 3, 8],[1, 3, 6, 7, 9, 8, 2, 4, 5],[3, 7, 2, 6, 8, 9, 5, 1, 4],[8, 1, 4, 2, 5, 3, 7, 6, 9],[6, 9, 5, 4, 1, 7, 3, 8, 2]]`.
```js
assert.deepEqual(
solveSudoku([
[-1, -1, 3, -1, 2, -1, 6, -1, -1],
[9, -1, -1, 3, -1, 5, -1, -1, 1],
[-1, -1, 1, 8, -1, 6, 4, -1, -1],
[-1, -1, 8, 1, -1, 2, 9, -1, -1],
[7, -1, -1, -1, -1, -1, -1, -1, 8],
[-1, -1, 6, 7, -1, 8, 2, -1, -1],
[-1, -1, 2, 6, -1, 9, 5, -1, -1],
[8, -1, -1, 2, -1, 3, -1, -1, 9],
[-1, -1, 5, -1, 1, -1, 3, -1, -1]
]),
[
[4, 8, 3, 9, 2, 1, 6, 5, 7],
[9, 6, 7, 3, 4, 5, 8, 2, 1],
[2, 5, 1, 8, 7, 6, 4, 9, 3],
[5, 4, 8, 1, 3, 2, 9, 7, 6],
[7, 2, 9, 5, 6, 4, 1, 3, 8],
[1, 3, 6, 7, 9, 8, 2, 4, 5],
[3, 7, 2, 6, 8, 9, 5, 1, 4],
[8, 1, 4, 2, 5, 3, 7, 6, 9],
[6, 9, 5, 4, 1, 7, 3, 8, 2]
]
);
```
# --seed--
## --seed-contents--
```js
function solveSudoku(puzzle) {
}
```
# --solutions--
```js
function solveSudoku(puzzle) {
var solution;
class DoX {
constructor(V, H) {
this.V = V;
this.L = this;
this.R = this;
this.U = this;
this.D = this;
this.S = 1;
this.H = H || this;
H && (H.S += 1);
}
}
const addRight = (e, n) => {
n.R = e.R;
n.L = e;
e.R.L = n;
return (e.R = n);
};
const addBelow = (e, n) => {
n.D = e.D;
n.U = e;
e.D.U = n;
return (e.D = n);
};
const search = function(h, s) {
if (h.R == h) {
printSol(s);
} else {
let c = chooseColumn(h);
cover(c);
for (let r = c.D; r != c; r = r.D) {
s.push(r);
for (let j = r.R; r != j; j = j.R) {
cover(j.H);
}
search(h, s);
r = s.pop();
for (let j = r.R; j != r; j = j.R) {
uncover(j.H);
}
}
uncover(c);
}
};
const chooseColumn = h => {
let s = Number.POSITIVE_INFINITY;
let c = h;
for (let j = h.R; j != h; j = j.R) {
if (j.S < s) {
c = j;
s = j.S;
}
}
return c;
};
const cover = c => {
c.L.R = c.R;
c.R.L = c.L;
for (let i = c.D; i != c; i = i.D) {
for (let j = i.R; j != i; j = j.R) {
j.U.D = j.D;
j.D.U = j.U;
j.H.S = j.H.S - 1;
}
}
};
const uncover = c => {
for (let i = c.U; i != c; i = i.U) {
for (let j = i.L; i != j; j = j.L) {
j.H.S = j.H.S + 1;
j.U.D = j;
j.D.U = j;
}
}
c.L.R = c;
c.R.L = c;
};
const printSol = a => {
solution = a.reduce((p, c) => {
let [i, v] = c.V.split(':');
p[i * 1] = v;
return p;
}, new Array(a.length).fill('.'));
};
const gridMeta = s => {
const g = s.split('');
const cellCount = g.length;
const tokenCount = Math.sqrt(cellCount);
const N = Math.sqrt(tokenCount);
const g2D = g.map(e =>
isNaN(e * 1)
? new Array(tokenCount).fill(1).map((_, i) => i + 1)
: [e * 1]
);
return [cellCount, N, tokenCount, g2D];
};
const indexesN = n => i => {
let c = Math.floor(i / (n * n));
i %= n * n;
return [c, i, Math.floor(c / n) * n + Math.floor(i / n)];
};
const reduceGrid = puzString => {
const [
numCells, // The total number of cells in a grid (81 for a 9x9 grid)
N, // the 'n' value of the grid. (3 for a 9x9 grid)
U, // The total number of unique tokens to be placed.
g2D // A 2D array representation of the grid, with each element
// being an array of candidates for a cell. Known cells are
// single element arrays.
] = gridMeta(puzString);
const getIndex = indexesN(N);
const headRow = new Array(4 * numCells)
.fill('')
.map((_, i) => new DoX(`H${i}`));
let H = new DoX('ROOT');
headRow.reduce((p, c) => addRight(p, c), H);
for (let i = 0; i < numCells; i++) {
const [ri, ci, bi] = getIndex(i);
g2D[i].forEach(num => {
let id = `${i}:${num}`;
let candIdx = num - 1;
// The 4 columns that we will populate.
const A = headRow[i];
const B = headRow[numCells + candIdx + ri * U];
const C = headRow[numCells * 2 + candIdx + ci * U];
const D = headRow[numCells * 3 + candIdx + bi * U];
// The Row-Column Constraint
let rcc = addBelow(A.U, new DoX(id, A));
// The Row-Number Constraint
let rnc = addBelow(B.U, addRight(rcc, new DoX(id, B)));
// The Column-Number Constraint
let cnc = addBelow(C.U, addRight(rnc, new DoX(id, C)));
// The Block-Number Constraint
addBelow(D.U, addRight(cnc, new DoX(id, D)));
});
}
search(H, []);
};
var stringPuzzle = '';
for (var i = 0; i < puzzle.length; i++) {
puzzle[i].forEach(function(e) {
if (e == -1) stringPuzzle += '.';
else stringPuzzle += e;
});
}
reduceGrid(stringPuzzle);
var result = [];
for (var i = 0; i < 9; i++) {
result.push(solution.slice(i * 9, (i + 1) * 9).map(e => parseInt(e)));
}
return result;
}
```