First pass at md to html conversion
|
@ -1,9 +1,8 @@
|
|||
---
|
||||
title: Writing a Sudoku Solver
|
||||
title: "Writing a Sudoku Solver: Displaying the Grid"
|
||||
date: 2023-04-10
|
||||
---
|
||||
|
||||
# Writing a Sudoku Solver: Displaying the Grid
|
||||
|
||||
I previously dabbled with writing a [sudoku solver](https://gitlab.com/dgalbraith33/sudoku-solver)
|
||||
but got carried away early on by making crazy speed improvements rather than actually improving the
|
||||
solving ability. What I did enjoy about the project is making logical deductions rather than the
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
$-- Run with the following command:
|
||||
$-- pandoc -s --template=blog/pandoc.html -o public/blog/sudoku.html blog/2023-04-10-sudoku.md
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>$title$</title>
|
||||
<link rel="stylesheet" href="/css/styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1 class="page-title">$title$</h1>
|
||||
<div class="date">Published $date$</div>
|
||||
$body$
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 136 KiB |
After Width: | Height: | Size: 7.4 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 18 KiB |
|
@ -0,0 +1,237 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Writing a Sudoku Solver: Displaying the Grid</title>
|
||||
<link rel="stylesheet" href="/css/styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Writing a Sudoku Solver: Displaying the Grid</h1>
|
||||
<div class="date">Published 2023-04-10</div>
|
||||
<p>I previously dabbled with writing a <a
|
||||
href="https://gitlab.com/dgalbraith33/sudoku-solver">sudoku
|
||||
solver</a> but got carried away early on by making crazy speed
|
||||
improvements rather than actually improving the solving ability.
|
||||
What I did enjoy about the project is making logical deductions
|
||||
rather than the guess and backcheck method commonly employed.</p>
|
||||
<p>I want to take another crack at doing this except this time focus
|
||||
on the question “Given the current state what are any of the next
|
||||
possible deductions” without focusing on speed. Eventually I’d also
|
||||
like to take a crack at solving other types of sudokus (Chess
|
||||
Sudoku, Killer Sudoku, etc).</p>
|
||||
<p>One of the issues I had last time as I was debugging was
|
||||
displaying the current board state in a clean way so I could see
|
||||
what had gone wrong. So this time around I’m planning on writing a
|
||||
quick HTML/javascript board state display to be able to visualize
|
||||
the board. For now I don’t intend it to be interactive, however I’ll
|
||||
likely add that in the future.</p>
|
||||
<h2 id="creating-a-sudoku-grid">Creating a sudoku grid</h2>
|
||||
<p>I’m no front end dev so this may take some time. I literally just
|
||||
want to create an outline for the puzzle with nothing in it.</p>
|
||||
<div class="sourceCode" id="cb1"><pre
|
||||
class="sourceCode html"><code class="sourceCode html"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw"><div</span> <span class="er">class</span><span class="ot">=</span><span class="st">"container"</span><span class="kw">></span></span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> <span class="kw"><h1></span>Sudoku<span class="kw"></h1></span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="kw"><div</span> <span class="er">class</span><span class="ot">=</span><span class="st">"puzzle"</span><span class="kw">></span>nothing<span class="kw"></div></span></span>
|
||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="kw"></div></span></span></code></pre></div>
|
||||
<div class="sourceCode" id="cb2"><pre
|
||||
class="sourceCode css"><code class="sourceCode css"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="fu">.container</span> {</span>
|
||||
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">max-width</span>: <span class="dv">800</span><span class="dt">px</span><span class="op">;</span></span>
|
||||
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">margin</span>: <span class="bu">auto</span><span class="op">;</span></span>
|
||||
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>}</span>
|
||||
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="fu">.puzzle</span> {</span>
|
||||
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">border</span>: <span class="dv">1</span><span class="dt">px</span> <span class="dv">solid</span> <span class="cn">black</span><span class="op">;</span></span>
|
||||
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
|
||||
<figure>
|
||||
<img src="images/sudoku-1.png" alt="border" />
|
||||
<figcaption aria-hidden="true">border</figcaption>
|
||||
</figure>
|
||||
<p>I’m not joking when I say I’m going to have to do baby steps
|
||||
here.</p>
|
||||
<p>Next I’ll try to actually make a square grid. The best way to do
|
||||
this is probably with flexbox or something but I’m just gonna hard
|
||||
code some widths and heights.</p>
|
||||
<p>Ok lets make this thing a width divisible by 9 so we can divide
|
||||
it into equal portions. I chose 630 quite honestly because it was
|
||||
the first number below 800px that popped into my head divisible by
|
||||
9.</p>
|
||||
<p>Let’s focus on the 9 main boxes in the grid now before worrying
|
||||
about the cells. I’ll make each box 210 pixels tall and wide. And
|
||||
slap a big ole border on there. Let’s make it 2px because we will
|
||||
want a narrower one for the cells.</p>
|
||||
<pre><code>.puzzle {
|
||||
width: 630px;
|
||||
height: 630px;
|
||||
}
|
||||
|
||||
.box {
|
||||
border: 2px solid black;
|
||||
width: 210px;
|
||||
height: 210px;
|
||||
}</code></pre>
|
||||
<figure>
|
||||
<img src="images/sudoku-2.png" alt="boxes" />
|
||||
<figcaption aria-hidden="true">boxes</figcaption>
|
||||
</figure>
|
||||
<p>Reload that and… right div’s auto linebreak after them.</p>
|
||||
<p>I think we can “float: left” these bad boys and…</p>
|
||||
<figure>
|
||||
<img src="images/sudoku-3.png" alt="boxes2" />
|
||||
<figcaption aria-hidden="true">boxes2</figcaption>
|
||||
</figure>
|
||||
<p>Right, now I’m pretty sure the boxes are 210 + 4 pixels wide
|
||||
because the border isn’t included. While I’m tempted to just math my
|
||||
way out of this I recall that you can specify the border-box sizing
|
||||
to avoid this.</p>
|
||||
<p>Now this works! Now the astute of you may have noticed that there
|
||||
were 10 not 9 boxes in the screenshot with the 2 columns. That
|
||||
became even more obvious in the full grid.</p>
|
||||
<figure>
|
||||
<img src="images/sudoku-4.png" alt="boxes3" />
|
||||
<figcaption aria-hidden="true">boxes3</figcaption>
|
||||
</figure>
|
||||
<p>Ok now we can just recreate all of this with the cells and should
|
||||
be good to go right?</p>
|
||||
<p>Nope! The internal size of the boxes are now only 206x206 because
|
||||
of the border-box attribute. But I now realize I can just get rid of
|
||||
the puzzle sizing all together and go back to regular sizing on the
|
||||
boxes. This happens to work because 4 214px boxes won’t fit in the
|
||||
800px wide container. (Again just use flexbox).</p>
|
||||
<p>Finally this works!</p>
|
||||
<figure>
|
||||
<img src="images/sudoku-5.png" alt="grid" />
|
||||
<figcaption aria-hidden="true">grid</figcaption>
|
||||
</figure>
|
||||
<h2 id="displaying-a-puzzle">Displaying a puzzle</h2>
|
||||
<p>Next up is to actually get some numbers in this bad boy. Now this
|
||||
is where I relent and use flexboxes because <a
|
||||
href="https://stackoverflow.com/questions/2939914/how-do-i-vertically-align-text-in-a-div/13515693">this</a>
|
||||
StackOverflow answer convinced me.</p>
|
||||
<pre><code>.cell {
|
||||
...
|
||||
|
||||
font-size: 40px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}</code></pre>
|
||||
<figure>
|
||||
<img src="images/sudoku-6.png" alt="cell number" />
|
||||
<figcaption aria-hidden="true">cell number</figcaption>
|
||||
</figure>
|
||||
<h3 id="taking-the-puzzle-from-the-url">Taking the puzzle from the
|
||||
URL</h3>
|
||||
<p>Now to make it so I can get the page to display any puzzle I want
|
||||
easily from the solver, I’ll allow specifying it as a parameter in
|
||||
the URL. For now in a row-major string of 81 characters using a
|
||||
period to denote blank spaces.</p>
|
||||
<p>I’ll can just get all of the cells by class name and iterate over
|
||||
them in the same order as the puzzle string and it will display
|
||||
relatively easily.</p>
|
||||
<pre><code>window.onload = (event) => {
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
var puzzle = params.get("p");
|
||||
if (puzzle === null) {
|
||||
return;
|
||||
}
|
||||
if (puzzle.length != 81) {
|
||||
console.log("Failure: puzzle url len is " + puzzle.length);
|
||||
return;
|
||||
}
|
||||
var cells = document.getElementsByClassName("cell");
|
||||
if (cells.length != 81) {
|
||||
console.log("Failure: wrong number of cells: " + cells.length);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 81; i++) {
|
||||
if (puzzle[i] != '.') {
|
||||
cells[i].innerText = puzzle[i]
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
<p>And hooray it works super well!</p>
|
||||
<figure>
|
||||
<img src="images/sudoku-7.png" alt="bad puzzles" />
|
||||
<figcaption aria-hidden="true">bad puzzles</figcaption>
|
||||
</figure>
|
||||
<p>Oh wait… I didn’t think about the fact that the elements in the
|
||||
HTMLCollection from the document.getElementsByClassName call
|
||||
wouldn’t be in the row order of the puzzle (all of the cells in box
|
||||
1 come first).</p>
|
||||
<p>You can see the effect of this as there are 2 9s in column 2 of
|
||||
the puzzle. Oops.</p>
|
||||
<p>I’m going to just do the old fashioned brute force way and give
|
||||
each cell an id from 1-81 and insert those manually. I’m sure there
|
||||
is a better way but hey this works.</p>
|
||||
<p>Then with a quick update to the code.</p>
|
||||
<pre><code>for (i = 0; i < 81; i++) {
|
||||
if (puzzle[i] != '.') {
|
||||
document.getElementById(i+1).innerText = puzzle[i]
|
||||
}
|
||||
}</code></pre>
|
||||
<p>It works!</p>
|
||||
<figure>
|
||||
<img src="images/sudoku-8.png" alt="good puzzle" />
|
||||
<figcaption aria-hidden="true">good puzzle</figcaption>
|
||||
</figure>
|
||||
<p>Still some goofiness like the border on the outside being thinner
|
||||
than the interiors but I’m pretty happy with this for now.</p>
|
||||
<h2 id="showing-pencil-marks">Showing pencil marks</h2>
|
||||
<p>Now to really visualize the solver’s state, we’ll also need to
|
||||
see which pencil marks it has. These could be styled nicely but for
|
||||
now I just went with a span inside the cell div with the following
|
||||
style.</p>
|
||||
<pre><code>.cell > span {
|
||||
font-size: 10px;
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
letter-spacing: 6px;
|
||||
word-wrap: anywhere;
|
||||
}</code></pre>
|
||||
<p>The letter-spacing and wordwrap attributes let us just jam all of
|
||||
the pencil marks in as a single string and let the browser break
|
||||
them up into multiple lines for us.</p>
|
||||
<p>This comes out quite nicely:</p>
|
||||
<figure>
|
||||
<img src="images/sudoku-9.png" alt="pencil marks" />
|
||||
<figcaption aria-hidden="true">pencil marks</figcaption>
|
||||
</figure>
|
||||
<h3 id="reading-the-pencil-marks-from-the-url">Reading the pencil
|
||||
marks from the url</h3>
|
||||
<p>For this url trick we will add the pencil marks using a comma
|
||||
separated array like so:</p>
|
||||
<p>123,,,,456,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,</p>
|
||||
<p>Using the string above we can use the following javascript code
|
||||
to parse and insert them:</p>
|
||||
<pre><code> var marks_param = params.get("m");
|
||||
if (marks_param === null) {
|
||||
return;
|
||||
}
|
||||
var marks = marks_param.split(",");
|
||||
|
||||
if (marks.length != 81) {
|
||||
console.log("Failure: marks url len is " + marks.length);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 81; i++) {
|
||||
if (marks[i].length > 0) {
|
||||
var cell = document.getElementById(i+1);
|
||||
if (cell.innerHTML.trim().length > 0) {
|
||||
console.log("Pencil marks in cell with number: " + (i+1));
|
||||
} else {
|
||||
cell.innerHTML = "<span>" + marks[i] + "</span>";
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
<p>Which also comes out nicely:</p>
|
||||
<figure>
|
||||
<img src="images/sudoku-10.png" alt="full puzzle" />
|
||||
<figcaption aria-hidden="true">full puzzle</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|