163 lines
4.7 KiB
JavaScript
163 lines
4.7 KiB
JavaScript
|
|
const EMPTY = -1;
|
||
|
|
|
||
|
|
const tableauOne = [
|
||
|
|
[0, 5, 1, 3, 2, 2, 3, 1],
|
||
|
|
[0, 5, 5, 0, 5, 2, 4, 6],
|
||
|
|
[4, 3, 0, 3, 6, 6, 2, 0],
|
||
|
|
[0, 6, 2, 3, 5, 1, 2, 6],
|
||
|
|
[1, 1, 3, 0, 0, 2, 4, 5],
|
||
|
|
[2, 1, 4, 3, 3, 4, 6, 6],
|
||
|
|
[6, 4, 5, 1, 5, 4, 1, 4]
|
||
|
|
];
|
||
|
|
|
||
|
|
const tableauTwo = [
|
||
|
|
[6, 4, 2, 2, 0, 6, 5, 0],
|
||
|
|
[1, 6, 2, 3, 4, 1, 4, 3],
|
||
|
|
[2, 1, 0, 2, 3, 5, 5, 1],
|
||
|
|
[1, 3, 5, 0, 5, 6, 1, 0],
|
||
|
|
[4, 2, 6, 0, 4, 0, 1, 1],
|
||
|
|
[4, 4, 2, 0, 5, 3, 6, 3],
|
||
|
|
[6, 6, 5, 2, 5, 3, 3, 4]
|
||
|
|
];
|
||
|
|
|
||
|
|
class Domino {
|
||
|
|
constructor(aOne, aTwo) {
|
||
|
|
this.one = Math.min(aOne, aTwo);
|
||
|
|
this.two = Math.max(aOne, aTwo);
|
||
|
|
}
|
||
|
|
|
||
|
|
equals(other) {
|
||
|
|
return this.one === other.one && this.two === other.two;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class Point {
|
||
|
|
constructor(aX, aY) {
|
||
|
|
this.x = aX;
|
||
|
|
this.y = aY;
|
||
|
|
}
|
||
|
|
|
||
|
|
equals(other) {
|
||
|
|
return this.x === other.x && this.y === other.y;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class Pattern {
|
||
|
|
constructor(tableau, dominoes, points) {
|
||
|
|
this.tableau = tableau;
|
||
|
|
this.dominoes = dominoes;
|
||
|
|
this.points = points;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function firstEmptyCell(tableau) {
|
||
|
|
for (let row = 0; row < tableau.length; ++row) {
|
||
|
|
for (let col = 0; col < tableau[0].length; ++col) {
|
||
|
|
if (tableau[row][col] === EMPTY) {
|
||
|
|
return row * tableau[0].length + col;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return EMPTY;
|
||
|
|
}
|
||
|
|
|
||
|
|
function printLayout(pattern) {
|
||
|
|
const output = Array(2 * pattern.tableau.length)
|
||
|
|
.fill()
|
||
|
|
.map(() => Array(2 * pattern.tableau[0].length - 1).fill(' '));
|
||
|
|
|
||
|
|
for (let i = 0; i < pattern.points.length - 1; i += 2) {
|
||
|
|
const x1 = pattern.points[i].x;
|
||
|
|
const y1 = pattern.points[i].y;
|
||
|
|
const x2 = pattern.points[i + 1].x;
|
||
|
|
const y2 = pattern.points[i + 1].y;
|
||
|
|
const n1 = pattern.tableau[x1][y1];
|
||
|
|
const n2 = pattern.tableau[x2][y2];
|
||
|
|
|
||
|
|
output[2 * x1][2 * y1] = String.fromCharCode('0'.charCodeAt(0) + n1);
|
||
|
|
output[2 * x2][2 * y2] = String.fromCharCode('0'.charCodeAt(0) + n2);
|
||
|
|
|
||
|
|
if (x1 === x2) {
|
||
|
|
output[2 * x1][2 * y1 + 1] = '+';
|
||
|
|
} else if (y1 === y2) {
|
||
|
|
output[2 * x1 + 1][2 * y1] = '+';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
for (const line of output) {
|
||
|
|
console.log(line.join(''));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function findPatterns(tableau) {
|
||
|
|
const nRows = tableau.length;
|
||
|
|
const nCols = tableau[0].length;
|
||
|
|
const dominoCount = (nRows * nCols) / 2;
|
||
|
|
|
||
|
|
const emptyTableau = Array(nRows)
|
||
|
|
.fill()
|
||
|
|
.map(() => Array(nCols).fill(EMPTY));
|
||
|
|
|
||
|
|
let patterns = [new Pattern(emptyTableau, [], [])];
|
||
|
|
|
||
|
|
while (true) {
|
||
|
|
const nextPatterns = [];
|
||
|
|
|
||
|
|
for (const pattern of patterns) {
|
||
|
|
const nextTableau = pattern.tableau.map(row => [...row]);
|
||
|
|
const dominoes = [...pattern.dominoes];
|
||
|
|
const points = [...pattern.points];
|
||
|
|
|
||
|
|
const index = firstEmptyCell(nextTableau);
|
||
|
|
if (index === EMPTY) continue;
|
||
|
|
|
||
|
|
const row = Math.floor(index / nCols);
|
||
|
|
const col = index % nCols;
|
||
|
|
|
||
|
|
// Check down
|
||
|
|
if (row + 1 < nRows && nextTableau[row + 1][col] === EMPTY) {
|
||
|
|
const domino = new Domino(tableau[row][col], tableau[row + 1][col]);
|
||
|
|
if (!dominoes.some(d => d.equals(domino))) {
|
||
|
|
const finalTableau = nextTableau.map(row => [...row]);
|
||
|
|
finalTableau[row][col] = tableau[row][col];
|
||
|
|
finalTableau[row + 1][col] = tableau[row + 1][col];
|
||
|
|
|
||
|
|
const nextDominoes = [...dominoes, domino];
|
||
|
|
const nextPoints = [...points, new Point(row, col), new Point(row + 1, col)];
|
||
|
|
|
||
|
|
nextPatterns.push(new Pattern(finalTableau, nextDominoes, nextPoints));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check right
|
||
|
|
if (col + 1 < nCols && nextTableau[row][col + 1] === EMPTY) {
|
||
|
|
const domino = new Domino(tableau[row][col], tableau[row][col + 1]);
|
||
|
|
if (!dominoes.some(d => d.equals(domino))) {
|
||
|
|
nextTableau[row][col] = tableau[row][col];
|
||
|
|
nextTableau[row][col + 1] = tableau[row][col + 1];
|
||
|
|
|
||
|
|
const nextDominoes = [...dominoes, domino];
|
||
|
|
const nextPoints = [...points, new Point(row, col), new Point(row, col + 1)];
|
||
|
|
|
||
|
|
nextPatterns.push(new Pattern(nextTableau, nextDominoes, nextPoints));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (nextPatterns.length === 0) break;
|
||
|
|
patterns = nextPatterns;
|
||
|
|
if (patterns[0].dominoes.length === dominoCount) break;
|
||
|
|
}
|
||
|
|
|
||
|
|
return patterns;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Main execution
|
||
|
|
for (const tableau of [tableauOne, tableauTwo]) {
|
||
|
|
const patterns = findPatterns(tableau);
|
||
|
|
console.log(`Layouts found: ${patterns.length}`);
|
||
|
|
if (patterns.length > 0) {
|
||
|
|
printLayout(patterns[0]);
|
||
|
|
}
|
||
|
|
}
|