Sudoku

A Sudoku puzzle game built with Preact.

by remarkablemark

HTML

<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/preact/8.2.6/preact.min.js"></script>

CSS

body {
  font-family: 'Lucida Grande', Helvetica, sans-serif;
}

/* Sudoku */
table {
  border: 1px solid #666;
  border-collapse: collapse;
}

td {
  padding: 0;
}

table input {
  font-size: 14px;
  height: 30px;
  text-align: center;
  width: 30px;
}

table input:not([readonly]) {
  font-weight: bold;
}

tr:nth-child(3n):not(:last-child) > td {
  border-bottom: 1px solid #666;
}

td:nth-child(3n):not(:last-child) {
  border-right: 1px solid #666;
}

/* difficulty */
label input {
  width: 50px;
}

Babel + JSX

const { h, render, Component } = preact; /** @jsx h */

// Sudoku uses numbers 1-9
const SIZE = 9;

/**
 * Generates an array with values.
 *
 * @param  {Number}   len
 * @param  {Function} [callback]
 * @return {Array}
 */
const generateArray = (len, callback = () => {}) =>
	Array.apply(null, { length: len }).map(callback);

// [1, 2, 3, 4, 5, 6, 7, 8, 9]
const NUMBERS = generateArray(SIZE, (_, index) => index + 1);

/**
 * Shuffles an array.
 *
 * @param  {Array}   array
 * @param  {Boolean} [shouldMutate=false]
 * @return {Array}
 */
const shuffleArray = (array = [], shouldMutate = false) => {
	const arr = shouldMutate ? array : array.slice();
	for (let i = arr.length - 1; i > 0; i--) {
		const j = Math.floor(Math.random() * (i + 1));
		const temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
	return arr;
};

/**
 * Generates row.
 *
 * @return {Array}
 */
const generateRow = () => shuffleArray(NUMBERS);

/**
 * Given output, checks if row is usable.
 *
 * @param  {Number}  index
 * @param  {Array}   row
 * @param  {Array}   output
 * @return {Boolean}
 */
const isRowUsable = (index, row = [], output = []) => {
	let rowIndex = output.length - 1;
	for (; rowIndex > -1; rowIndex--) {
		let columnIndex = output[rowIndex].length - 1;
		for (; columnIndex > -1; columnIndex--) {
			// check if row value exists in output column
			const rowValue = row[columnIndex];
			if (rowValue === output[rowIndex][columnIndex]) return false;

			let rowStart = 6;
			if (index < 3) {
				rowStart = 0;
			} else if (index < 6) {
				rowStart = 3;
			}

			let columnStart = 6;
			if (columnIndex < 3) {
				columnStart = 0;
			} else if (columnIndex < 6) {
				columnStart = 3;
			}

			let section = [];
			for (i = 0; i < 3; i++) {
				if (output[rowStart + i] instanceof Array) {
					section = section.concat(
						output[rowStart + i].slice(columnStart, columnStart + 3)
					);
				}
			}

			// check if row value exists in output 3x3 section
			if (section.indexOf(rowValue) !==...