freeCodeCamp/curriculum/challenges/ukrainian/10-coding-interview-prep/rosetta-code/sudoku.md

322 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

---
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;
}
```