{"id":37055,"date":"2017-02-28T06:00:21","date_gmt":"2017-02-28T11:00:21","guid":{"rendered":"http:\/\/www.shamusyoung.com\/twentysidedtale\/?p=37055"},"modified":"2017-02-28T13:14:53","modified_gmt":"2017-02-28T18:14:53","slug":"pseudoku-this-game-needs-filler","status":"publish","type":"post","link":"https:\/\/www.shamusyoung.com\/twentysidedtale\/?p=37055","title":{"rendered":"Pseudoku: This Game Needs Filler"},"content":{"rendered":"<p>Last time I made a solver to test puzzles for me. Once that was done, I could make puzzles like so:<\/p>\n<ol>\n<li>Fill in the board with tiles.\n<li>Pull tiles off one at a time while the solver looks at what remains. If I pull off a tile and the solver says it&#8217;s stuck, then put the tile back and remove a different one.\n<li>Keep doing step 2 until I have a puzzle of the desired difficulty.\n<li>Lock down all of the remaining tiles.\n<li>Done.\n<\/ol>\n<p>This is how I produced all of the puzzles in the builds I&#8217;ve released. Once this was done I shelved the project for about a year. But now that I&#8217;m back on it, I have to say step 1 is now the major roadblock to creating new puzzles.<\/p>\n<p>It takes <em>time<\/em> to fill in a board. Filling in the first 8 \/ 9<sup>ths<\/sup>  of the board is trivial, but getting the last ninth into place can be tricky. Take this example:<\/p>\n<p><!--more--><br \/>\n<div class='imagefull'><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/pseudoku1-1.jpg' width=100% alt='You can&apos;t place the remaining 1 tile without violating the rules.' title='You can&apos;t place the remaining 1 tile without violating the rules.'\/><\/div><div class='mouseover-alt'>You can&apos;t place the remaining 1 tile without violating the rules.<\/div><\/p>\n<p>This is what it&#8217;s like when you get down to the end. I need to add another 1 to the board, but there aren&#8217;t any valid spaces for a 1. So I&#8217;ll swap a couple of tiles around to make the 1 fit, but now maybe I can&#8217;t get the last 2 on the board. So I fix that but then 4 is a problem, and so on. It&#8217;s trivial to fix on 4&#215;4 puzzles like the one above, but on a 9&#215;9 this can actually take a while to sort out.<\/p>\n<p>In the past I didn&#8217;t mind. Creating a filled-in board is basically a puzzle in itself. It was fun to do. But it&#8217;s also time-consuming and often not what I want to be working on at the moment. If you played some of my test builds, you may have spotted a few puzzles like this one:<\/p>\n<p><div class='imagefull'><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/pseudoku2-1.jpg' width=100% alt='You might not notice the repeating patterns right away if I didn&apos;t highlight them. But once you do see them, you can&apos;t UN-see them.' title='You might not notice the repeating patterns right away if I didn&apos;t highlight them. But once you do see them, you can&apos;t UN-see them.'\/><\/div><div class='mouseover-alt'>You might not notice the repeating patterns right away if I didn&apos;t highlight them. But once you do see them, you can&apos;t UN-see them.<\/div><\/p>\n<p>I don&#8217;t know if I had any that were quite this flagrant, but this is a good example of a lazy puzzle layout. Rather than make a properly randomized puzzle, I just added things according to a nice orderly little system. The benefit is that you can fill in a 9&#215;9 puzzle in less than a minute. The downside is that if the player notices the <a href=\"https:\/\/www.youtube.com\/watch?v=k8Iidlj5GzM\">repeating patterns<\/a>, it trivializes the entire puzzle. Sudoku puzzles are <strong>not<\/strong> supposed to look like this. I circled a couple of repeating patterns for you, but the whole board is filled with groupings like this. I filled in the top row with the digits 1-9 in numeric order, and then changed as little as possible with each subsequent row.<\/p>\n<p>I did this a year ago to quickly fill in boards for testing. I figured I&#8217;d replace them with proper puzzles if the project ever got off the ground. Then I forgot I&#8217;d done this, so when I returned to the project this year I ended up releasing these lazy boards to the public. <\/p>\n<p>Whoops. Oh well. Crappy puzzles are a content problem, and generally content problems are easier to solve than technology problems.<\/p>\n<p>For the record, a proper sudoku layout should look like this:<\/p>\n<p><div class='imagefull'><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/pseudoku2-2.jpg' width=100% alt='Ha! I&apos;ve spotted a pattern: All of these squares contain the digits 1-9.' title='Ha! I&apos;ve spotted a pattern: All of these squares contain the digits 1-9.'\/><\/div><div class='mouseover-alt'>Ha! I&apos;ve spotted a pattern: All of these squares contain the digits 1-9.<\/div><\/p>\n<p>That&#8217;s a nice random layout. But it takes time to make those by hand. I need a way to fill in a board automatically.<\/p>\n<p>I assumed there was some mathematical trick for doing this, but no. It turns out that board layouts are made through trial-and-error. <Humans do it that way. Computers do it that way. Everyone does it that way.\n\n\n\n<h3>Trial and Error<\/h3>\n<p><div class='imagefull'><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/pseudoku2-3.jpg' width=100% alt='I feel that mathematicians have overlooked the impact of Badonk Blockades on the game of sudoku.' title='I feel that mathematicians have overlooked the impact of Badonk Blockades on the game of sudoku.'\/><\/div><div class='mouseover-alt'>I feel that mathematicians have overlooked the impact of Badonk Blockades on the game of sudoku.<\/div><\/p>\n<p>I know the code should be simple to write, but I have no idea how long it will take to run. My hope is that I can get it under five seconds or so. Now that I&#8217;ve released my test builds to the public, the #1 requested feature<span class='snote' title='1'>Aside from a &#8220;next puzzle&#8221; button, which I&#8217;ve already done.<\/span> is for a way for the game to generate random puzzles. If I can fill in the board in just a few seconds, then I&#8217;ll have everything I need to generate puzzles. But if it takes 30 seconds then I&#8217;ll just shelve the idea until later.<\/p>\n<p>The rules are simple:<\/p>\n<ol>\n<li>Working left-to-right, top-to-bottom, pass over the board looking for empty squares. (Instead of starting with a blank board, it can handle pre-existing tiles. This means I can make a puzzle that spells out &#8220;A BADONK BLOCKADE&#8221; using the letter tileset if I want to.)\n<li>When it finds an empty square, it randomly places a new tile there that doesn&#8217;t violate the rules.\n<li>If there is no valid tile for that space, then the puzzle is stuck. Back up to the previously placed tile, remove it, and try something different. If THAT one gets stuck, then it will back up to the previous, and so on.\n<li>Keep doing this until the board is full.\n<\/ol>\n<p>It takes about four minutes to fill in a blank 16&#215;16 board. That&#8217;s way too long. Although to be fair, I&#8217;m deliberately throttling this code. Instead of having the program lock up until it finds an answer, it just works on it a little bit each frame while keeping the program running. It&#8217;s even animating stuff, so I can see tiles flying all over the screen at hyperspeed. I&#8217;m doing this because I want to watch the process work.<\/p>\n<p><div class='imagefull'><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/pseudoku2-4.jpg' width=100% alt='It works! The puzzle-filler successfully integrated a Badonk Blockade into a puzzle.' title='It works! The puzzle-filler successfully integrated a Badonk Blockade into a puzzle.'\/><\/div><div class='mouseover-alt'>It works! The puzzle-filler successfully integrated a Badonk Blockade into a puzzle.<\/div><\/p>\n<p>Sure, I could make the search run faster by having it run exclusively and halting rendering and animation until it&#8217;s over, but I&#8217;ve got a better idea&#8230;<\/p>\n<p>When the auto-fill code places a tile, it hands the resulting board off to the solver code I wrote last year. The solver will reply with all of the forced moves. As in, &#8220;Based on the tiles currently in play, here are moves you&#8217;ll HAVE to make.&#8221; This doesn&#8217;t do much early in the process, but it&#8217;s a huge boost to the latter stages of filling the board. It lets the fill code spot doomed layouts far in advance, instead of needing to work through all of the permutations before giving up. It also means there will be less permutations to test later in the process, since more of the board will be filled in.<\/p>\n<p>Now it takes almost exactly 30 seconds to fill in one of these 16&#215;16 monster puzzles. A traditional 9&#215;9 is done in under 5. <\/p>\n<p>I now have the two major pieces needed to automatically generate puzzles. It can fill a board, and then pull as many pieces as possible off of it.<\/p>\n<p>There&#8217;s still the matter of balancing the system. Right now it can only gauge puzzle difficulty by how many tiles are on the board at the start. I&#8217;ll need to come up with a way to appraise difficulty if I wanted to make a random puzzle generator. But that&#8217;s a problem for later in the project when I&#8217;ve got a group of playtesters to work with. In the meantime I have a bunch of annoying technology problems to solve.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last time I made a solver to test puzzles for me. Once that was done, I could make puzzles like so: Fill in the board with tiles. Pull tiles off one at a time while the solver looks at what remains. If I pull off a tile and the solver says it&#8217;s stuck, then put [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[66],"tags":[],"class_list":["post-37055","post","type-post","status-publish","format-standard","hentry","category-programming"],"_links":{"self":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/posts\/37055","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=37055"}],"version-history":[{"count":0,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/posts\/37055\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=37055"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=37055"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=37055"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}