aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/App.svelte98
-rw-r--r--src/lib/Saving.ts25
-rw-r--r--src/lib/Sudoku.ts58
3 files changed, 157 insertions, 24 deletions
diff --git a/src/App.svelte b/src/App.svelte
index 9aab903..3a1a685 100644
--- a/src/App.svelte
+++ b/src/App.svelte
@@ -1,45 +1,99 @@
<script lang="ts">
- import { validate } from "./lib/Sudoku";
+ import { readGridFromFile, save } from "./lib/Saving";
+
+ import { validate, type Coord } from "./lib/Sudoku";
let selTile: HTMLDivElement | EventTarget;
+ let fileInput: HTMLInputElement;
const getSelTile = () => selTile as HTMLDivElement;
- const grid = (new Array(10)).fill((new Array(10)).fill(".")) as string[][];
+ const getCoord = (): Coord => ({
+ x: parseInt(getSelTile().dataset.i),
+ y: parseInt(getSelTile().dataset.j),
+ });
+ let grid = [] as string[][]; //new Array(9).fill(new Array(9).fill("."));
+ let immutableTiles = [] as Coord[]; //new Array(9).fill(new Array(9).fill("."));
+ const tiles = [] as HTMLDivElement[][]; //new Array(9).fill(new Array(9).fill("."));
+ for (let i = 0; i < 9; i++) {
+ grid.push([]);
+ tiles.push([]);
+ for (let j = 0; j < 9; j++) {
+ grid[i].push(".");
+ tiles[i].push(null);
+ }
+ }
function keyDownHandler(e: KeyboardEvent) {
- if(e.key === "Backspace") {
- setSelTile(".")
+ const foundImmu = immutableTiles.find(
+ (el) => el.x === getCoord().x && el.y === getCoord().y
+ );
+ console.log(immutableTiles);
+ console.log(foundImmu);
+ if (foundImmu) return;
+
+ if (e.key === "Backspace") {
+ setSelTile(".");
}
const num = parseInt(e.key);
- if(Number.isNaN(num) || num === 0) return;
- setSelTile(num)
- validate(grid)
- }
- function showTile(val: string) {
- return val === "." ? "" : val;
+ if (Number.isNaN(num) || selTile == null || num === 0) return;
+ setSelTile(num);
+ for (const tile of tiles.flat()) {
+ tile.classList.remove("err");
+ tile.classList.remove("good");
+ }
+ const bads = validate(grid);
+ for (const bad of bads) {
+ tiles[bad.x][bad.y].classList.add("err");
+ }
}
+ // function showTile(val: string) {
+ // return val === "." ? "" : val;
+ // }
function setSelTile(val: string | number) {
- grid[parseInt(getSelTile().dataset.i)][parseInt(getSelTile().dataset.j)] = val.toString();
- getSelTile().innerText = val === "." ? "" : val.toString();
+ grid[getCoord().x][getCoord().y] = val.toString();
+ // getSelTile().innerText = val === "." ? "" : val.toString();
+ }
+
+ async function load() {
+ const maybeGrid = await readGridFromFile(fileInput.files[0]);
+ if (!maybeGrid) {
+ alert("Error while loading file");
+ return;
+ }
+ for (const [i, row] of maybeGrid.entries()) {
+ for (const [j, tile] of row.entries()) {
+ if (tile === ".") continue;
+ immutableTiles.push({ x: i, y: j });
+ tiles[i][j].classList.add("const");
+ }
+ }
+ grid = maybeGrid;
+ fileInput.value = null;
}
</script>
-<!-- <svelte:body on:keydown|preventDefaultstopPropagation={keyDownHandler} /> -->
+<!-- <svelte:body on:keydown|preventDefault|stopPropagation={keyDownHandler} /> -->
<svelte:body on:keydown={keyDownHandler} />
<main>
<div class="grid">
- {#each {length: 9} as _, i}
- {#each {length: 9} as _, j}
- <div
- class="tile"
+ {#each grid as row, i}
+ {#each row as tile, j}
+ <div
+ class="tile"
class:br={j % 3 === 2 && j !== 8}
class:bb={i % 3 === 2 && i !== 8}
- on:click|self={e => selTile = e.target}
+ on:click|self={(e) => (selTile = e.target)}
data-i={i}
data-j={j}
- on:keypress={null}>{grid[i][j] === "." ? "" : grid[i][j]}</div>
+ bind:this={tiles[i][j]}
+ on:keypress={null}
+ >
+ {tile === "." ? "" : tile}
+ </div>
{/each}
{/each}
</div>
+ <button on:click={() => save(grid)}>Save</button>
+ <input type="file" on:change={load} bind:this={fileInput} />
</main>
<style>
@@ -70,4 +124,10 @@
.br {
border-right: 3px solid black;
}
+ :global(.err) {
+ background-color: rgba(150, 0, 0, 0.6) !important;
+ }
+ :global(.const) {
+ color: rebeccapurple;
+ }
</style>
diff --git a/src/lib/Saving.ts b/src/lib/Saving.ts
new file mode 100644
index 0000000..0d71057
--- /dev/null
+++ b/src/lib/Saving.ts
@@ -0,0 +1,25 @@
+import type { Grid } from "./Sudoku";
+
+export function save(grid: Grid) {
+ const a = document.createElement("a");
+ const fileParts = [JSON.stringify(grid)];
+ const blob = new Blob(fileParts, { type: 'application/json' }); // the blob
+ a.href = URL.createObjectURL(blob);
+ a.download = "sudoku-save.json";
+ a.click();
+}
+export function readGridFromFile(f: File): Promise<string[][] | null> {
+ return new Promise(res => {
+ let reader = new FileReader();
+ reader.onload = e => {
+ try {
+ //@ts-expect-error
+ const json = JSON.parse(e.target.result);
+ res(json)
+ } catch (error) {
+ res(null)
+ }
+ };
+ reader.readAsText(f);
+ })
+}
diff --git a/src/lib/Sudoku.ts b/src/lib/Sudoku.ts
index 0da0d77..94b972e 100644
--- a/src/lib/Sudoku.ts
+++ b/src/lib/Sudoku.ts
@@ -1,9 +1,57 @@
-import sudoku from "sudoku-umd";
+export type Grid = Array<Array<string>>;
+export type Coord = { x: number; y: number };
-type Grid = Array<Array<string>>;
+export function validate(board: Grid) {
+ const bads = [] as Coord[];
+ for (let i = 0; i < 9; i++) {
+ for (let j = 0; j < 9; j++) {
+ const value = board[i][j];
+ if (value !== '.') {
+ if (!validateRow(board, i, j, value) || !validateColumn(board, i, j, value) || !validateBox(board, i, j, value)) {
+ bads.push({ x: i, y: j })
+ }
+ }
+ }
+ }
+ return bads;
+};
-export function validate(grid: Grid) {
- const list = sudoku.board_grid_to_string(grid)
+function validateRow(board: Grid, row: number, col: number, value: string) {
+ for (let j = 0; j < 8; j++) {
+ if (j !== col) {
+ if (board[row][j] === value) {
+ return false;
+ }
+ }
+ }
- return true
+ return true;
+}
+
+function validateColumn(board: Grid, row: number, col: number, value: string) {
+ for (let i = 0; i < 8; i++) {
+ if (i !== row) {
+ if (board[i][col] === value) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+function validateBox(board: Grid, row: number, col: number, value: string) {
+ const startRow = row - (row % 3), startCol = col - (col % 3);
+
+ for (let i = startRow; i < startRow + 3; i++) {
+ for (let j = startCol; j < startCol + 3; j++) {
+ if (i !== row && j !== col) {
+ if (board[i][j] === value) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
}