xxxxxxxxxx
211
const original = [
9,0,0, 0,5,0, 0,6,0,
0,5,3, 7,0,0, 0,8,0,
4,0,0, 0,0,0, 0,0,3,
0,9,0, 0,0,0, 0,0,0,
0,8,5, 0,6,0, 0,0,1,
0,0,0, 4,0,0, 6,0,0,
0,6,1, 0,4,0, 0,0,8,
0,0,0, 0,0,2, 0,7,0,
3,0,0, 0,0,0, 0,0,0
];
let state = [];
const gridSize = 3;
const numCells = gridSize * gridSize;
let cellSize;
let drawPartialState = true;
function setup() {
createCanvas(600, 600);
cellSize = min(width, height)/numCells;
createState();
textAlign(CENTER, CENTER);
}
function draw() {
background(220);
collapseNext();
drawGrid();
}
function drawGrid() {
strokeWeight(1);
for(let j = 0; j < numCells; j ++) {
for(let i = 0; i < numCells; i ++) {
square(i * cellSize, j * cellSize, cellSize);
const possible = Array.from(getCell(i, j).values());
const cx = (i + 0.5) * cellSize;
const cy = (j + 0.5) * cellSize;
if(possible.length === 1) {
textSize(cellSize/2);
text(possible[0], cx, cy);
} else if(drawPartialState) {
textSize(cellSize/numCells);
for(let k = 0; k < possible.length; k ++) {
let x = k % gridSize;
x = cx + x * cellSize/gridSize - cellSize/gridSize;
let y = (k / gridSize) | 0;
y = cy + y * cellSize/gridSize - cellSize/gridSize;
text(possible[k], x, y);
}
}
}
}
// thick borders
strokeWeight(3);
const interval = cellSize * gridSize;
for(let i = 0; i <= gridSize; i ++) {
line(i * interval, 0, i * interval, height);
line(0, i * interval, width, i * interval);
}
}
function createState() {
state = [];
for(let i = 0; i < original.length; i ++) {
const v = original[i];
const possible = new Set();
if(v) {
possible.add(v);
} else {
for(let n = 1; n <= gridSize * gridSize; n ++) {
possible.add(n);
}
}
state.push(possible);
}
propagateToAll();
}
function collapseNext() {
let fewestOptsIdx = -1;
let fewestOptsNum = Infinity;
for(let i = 0; i < state.length; i ++) {
const num = state[i].size;
if(num === 0) {
// should never have 0 options
// restart
console.log("fuck!");
createState();
} else if(num > 1 && num < fewestOptsNum) {
fewestOptsIdx = i;
fewestOptsNum = num;
}
}
if(fewestOptsIdx != -1) {
const opts = Array.from(state[fewestOptsIdx].values());
const collapsed = new Set();
collapsed.add(random(opts));
state[fewestOptsIdx] = collapsed;
}
propagateToAll();
}
function propagateToAll() {
for(let j = 0; j < numCells; j ++) {
for(let i = 0; i < numCells; i ++) {
propagate(i, j);
}
}
}
function propagate(x, y) {
let impossible = superCell(x, y);
impossible = union(impossible, column(x));
impossible = union(impossible, row(y));
const cell = getCell(x, y);
if(cell.size === 1) {
return;
}
impossible.forEach(v => cell.delete(v));
}
function superCell(x, y) {
const set = new Set();
x = ((x / gridSize) | 0) * gridSize;
y = ((y / gridSize) | 0) * gridSize;
for(let j = 0; j < gridSize; j ++) {
for(let i = 0; i < gridSize; i ++) {
const cell = getCell(x + i, y + j);
if(cell.size > 1) {
continue;
}
cell.forEach(c => set.add(c));
}
}
return set;
}
function column(i) {
const set = new Set();
for(let j = 0; j < numCells; j ++) {
const cell = getCell(i, j);
if(cell.size > 1) {
continue;
}
cell.forEach(c => set.add(c));
}
return set;
}
function row(j) {
const set = new Set();
for(let i = 0; i < numCells; i ++) {
const cell = getCell(i, j);
if(cell.size > 1) {
continue;
}
cell.forEach(c => set.add(c));
}
return set;
}
function getCell(x, y) {
return state[x + y * numCells];
}
// Set functions
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
function union(setA, setB) {
const _union = new Set(setA);
for (const elem of setB) {
_union.add(elem);
}
return _union;
}