diff --git a/blog/2023-04-10-sudoku.md b/blog/2023-04-10-sudoku.md
new file mode 100644
index 0000000..101da96
--- /dev/null
+++ b/blog/2023-04-10-sudoku.md
@@ -0,0 +1,238 @@
+# Writing a Sudoku Solver
+
+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
+guess and backcheck method commonly employed.
+
+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).
+
+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.
+
+## Creating a sudoku grid
+
+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.
+
+```html
+
+```
+
+```css
+.container {
+ max-width: 800px;
+ margin: auto;
+}
+
+.puzzle {
+ border: 1px solid black;
+}
+```
+
+-- Screenshot: sudoku-1.png
+
+I'm not joking when I say I'm going to have to do baby steps here.
+
+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.
+
+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.
+
+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.
+
+```
+.puzzle {
+ width: 630px;
+ height: 630px;
+}
+
+.box {
+ border: 2px solid black;
+ width: 210px;
+ height: 210px;
+}
+```
+
+-- Screenshot: sudoku-2.png
+
+Reload that and... right div's auto linebreak after them.
+
+I think we can "float: left" these bad boys and...
+
+-- Screenshot: sudoku-3.png
+
+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.
+
+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.
+
+-- Screenshot: sudoku-4.png???
+
+Ok now we can just recreate all of this with the cells and should be good to go right?
+
+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).
+
+Finally this works!
+
+-- Screenshot: sudoku-5.png
+
+## Displaying a puzzle
+
+Next up is to actually get some numbers in this bad boy. Now this is where I relent and use
+flexboxes because
+[this](https://stackoverflow.com/questions/2939914/how-do-i-vertically-align-text-in-a-div/13515693)
+StackOverflow answer convinced me.
+
+```
+.cell {
+ ...
+
+ font-size: 40px;
+ font-weight: bold;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+```
+
+-- Screenshot: sudoku-6.png
+
+### Taking the puzzle from the URL
+
+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.
+
+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.
+
+
+```
+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]
+ }
+ }
+}
+```
+
+And hooray it works super well!
+
+-- Screenshot: sudoku-7.png
+
+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).
+
+You can see the effect of this as there are 2 9s in column 2 of the puzzle. Oops.
+
+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.
+
+Then with a quick update to the code.
+
+```
+for (i = 0; i < 81; i++) {
+ if (puzzle[i] != '.') {
+ document.getElementById(i+1).innerText = puzzle[i]
+ }
+}
+```
+
+It works!
+
+-- Screenshot: sudoku-8.png
+
+Still some goofiness like the border on the outside being thinner than the interiors but I'm pretty
+happy with this for now.
+
+## Showing pencil marks
+
+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.
+
+```
+.cell > span {
+ font-size: 10px;
+ font-weight: normal;
+ text-align: center;
+ letter-spacing: 6px;
+ word-wrap: anywhere;
+}
+```
+
+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.
+
+This comes out quite nicely:
+
+-- Screenshot: sudoku-9.png
+
+### Reading the pencil marks from the url
+
+For this url trick we will add the pencil marks using a comma separated array like so:
+
+123,,,,456,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+
+Using the string above we can use the following javascript code to parse and insert them:
+
+```
+ 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 = "" + marks[i] + "";
+ }
+ }
+ }
+```
+
+Which also comes out nicely:
+
+-- Screenshot: sudoku-10.png
diff --git a/blog/sudoku-1.png b/blog/sudoku-1.png
new file mode 100644
index 0000000..81ea383
Binary files /dev/null and b/blog/sudoku-1.png differ
diff --git a/blog/sudoku-10.png b/blog/sudoku-10.png
new file mode 100644
index 0000000..f92110a
Binary files /dev/null and b/blog/sudoku-10.png differ
diff --git a/blog/sudoku-2.png b/blog/sudoku-2.png
new file mode 100644
index 0000000..df09597
Binary files /dev/null and b/blog/sudoku-2.png differ
diff --git a/blog/sudoku-3.png b/blog/sudoku-3.png
new file mode 100644
index 0000000..7f4d02d
Binary files /dev/null and b/blog/sudoku-3.png differ
diff --git a/blog/sudoku-4.png b/blog/sudoku-4.png
new file mode 100644
index 0000000..85b7659
Binary files /dev/null and b/blog/sudoku-4.png differ
diff --git a/blog/sudoku-5.png b/blog/sudoku-5.png
new file mode 100644
index 0000000..837dcba
Binary files /dev/null and b/blog/sudoku-5.png differ
diff --git a/blog/sudoku-6.png b/blog/sudoku-6.png
new file mode 100644
index 0000000..9fe2174
Binary files /dev/null and b/blog/sudoku-6.png differ
diff --git a/blog/sudoku-7.png b/blog/sudoku-7.png
new file mode 100644
index 0000000..7fd59d2
Binary files /dev/null and b/blog/sudoku-7.png differ
diff --git a/blog/sudoku-8.png b/blog/sudoku-8.png
new file mode 100644
index 0000000..c98a3b6
Binary files /dev/null and b/blog/sudoku-8.png differ
diff --git a/blog/sudoku-9.png b/blog/sudoku-9.png
new file mode 100644
index 0000000..a67c63f
Binary files /dev/null and b/blog/sudoku-9.png differ