{"id":94,"date":"2021-07-16T12:00:44","date_gmt":"2021-07-16T12:00:44","guid":{"rendered":"https:\/\/crosswordnexus.com\/blog\/?p=94"},"modified":"2022-04-08T15:20:05","modified_gmt":"2022-04-08T15:20:05","slug":"creating-acrostic-puzzles","status":"publish","type":"post","link":"https:\/\/crosswordnexus.com\/blog\/2021\/07\/16\/creating-acrostic-puzzles\/","title":{"rendered":"Creating Acrostic Puzzles"},"content":{"rendered":"<p>The <a href=\"https:\/\/crosswordnexus.com\/solve\/\">Crossword Nexus Solver<\/a> has supported <a href=\"https:\/\/crosswordnexus.com\/blog\/2021\/07\/09\/puzzle-5-live-aid-acrostic\/\">acrostic puzzles<\/a> for a while now, but acrostic puzzles remain relatively uncommon in the indie puzzle community.\u00a0 This is a shame, because acrostic puzzles are very fun, and I for one want to see more of them.\u00a0 So what&#8217;s holding constructors back?<\/p>\n<p>Constructors may not know how to create a JPZ of an acrostic puzzle, but there&#8217;s good news there.\u00a0 <a href=\"https:\/\/jpd236.github.io\/kotwords\/\">Jeff Davidson&#8217;s kotwords site<\/a> has an <a href=\"https:\/\/jpd236.github.io\/kotwords\/acrostic.html\">acrostic puzzle JPZ creation tool<\/a>, which is very user-friendly.\u00a0 Just plug in your values and you&#8217;ve got a JPZ ready to make available on your site, or even <a href=\"https:\/\/crosswordnexus.com\/embed\/\">embedded on your site<\/a>.<\/p>\n<p>Potentially a bigger challenge, though, comes with the creation of an acrostic puzzle.\u00a0 There&#8217;s no easily available tool to help with the creation of these things, and though it&#8217;s not too hard by hand, that may be a barrier to entry for new constructors.\u00a0 Well, we&#8217;ve got good news there too!\u00a0 Say hello to the <a href=\"https:\/\/github.com\/crosswordnexus\/variety-tools\/blob\/main\/acrostic\/acrostic_ilp.py\">Acrostic Generator<\/a>, a Python script that will take your quote, author, and work, and spit out an acrostic for you, usually in under a minute.\u00a0 Don&#8217;t like one of the words in the result?\u00a0 Tell the generator that and it will make another one for you with that word excluded.\u00a0 You can use your own word list for this process and set the minimum score threshold within.<\/p>\n<p>I don&#8217;t generally like releasing tools in Python, though, as it presents a barrier to entry for some people.\u00a0 I&#8217;ve tried writing this script in JavaScript but it was too slow for general use.\u00a0 But thanks to the magic of <a href=\"https:\/\/www.pythonanywhere.com\">python anywhere<\/a>, now anyone with a web browser can generate acrostic puzzles in this way.<\/p>\n<p><a href=\"https:\/\/boisvert42.pythonanywhere.com\/\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-95\" src=\"https:\/\/crosswordnexus.com\/blog\/wp-content\/uploads\/2021\/07\/Screen-Shot-2021-07-14-at-8.09.26-AM-300x280.png\" alt=\"\" width=\"300\" height=\"280\" srcset=\"https:\/\/crosswordnexus.com\/blog\/wp-content\/uploads\/2021\/07\/Screen-Shot-2021-07-14-at-8.09.26-AM-300x280.png 300w, https:\/\/crosswordnexus.com\/blog\/wp-content\/uploads\/2021\/07\/Screen-Shot-2021-07-14-at-8.09.26-AM-768x718.png 768w, https:\/\/crosswordnexus.com\/blog\/wp-content\/uploads\/2021\/07\/Screen-Shot-2021-07-14-at-8.09.26-AM.png 916w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p><a href=\"https:\/\/boisvert42.pythonanywhere.com\/\">Head on over to this link<\/a> to leverage the Python script for yourself.\u00a0 It&#8217;s very user-friendly and will generally spit out a solution to your acrostic in well under a minute.\u00a0 In addition to the solution, it will also give you inputs to Jeff&#8217;s JPZ generator, so you can just copy\/paste the data into that site.\u00a0 We&#8217;ll be making more puzzles like this soon, and we hope you do too.\u00a0 Enjoy!<\/p>\n<p>Too many people to thank here, but let&#8217;s start with <a href=\"https:\/\/twitter.com\/xor\/\">Parker<\/a> supplying a first take on a solution to this problem, <a href=\"https:\/\/twitter.com\/jeremyhorwitz\">Jeremy<\/a> for being a sounding board for ideas, and <a href=\"https:\/\/twitter.com\/joonpahk\/\">Joon<\/a> for collaborating on getting acrostics into the JPZ format in the first place.<\/p>\n<p>Most of you can stop reading here but if you want to know the technical nitty-gritty about how this got done, read on &#8230;<\/p>\n<hr \/>\n<p>I tried several ways to get an efficient acrostic generator but nothing worked.\u00a0 Nearing the end of my rope, I ran across <a href=\"https:\/\/www.reddit.com\/r\/dailyprogrammer\/comments\/7xyi2w\/20180216_challenge_351_hard_star_battle_solver\/ducasgv\/?utm_source=reddit&amp;utm_medium=web2x&amp;context=3\">this Redditor&#8217;s solution to the star battle problem<\/a> in which they cast the problem as an <a href=\"https:\/\/en.wikipedia.org\/wiki\/Integer_programming\">integer linear programming<\/a> (ILP) one and simply applied an existing ILP solver.\u00a0 Now, integer programming is NP-complete, but that doesn&#8217;t mean there aren&#8217;t good heuristics for solving them, so I figured if I could simply cast this problem as an ILP one, I could leverage an existing solver just like the star battle solution did.<\/p>\n<p>Now about ILP: my math brain likes to think of these problems as &#8220;maximize <code>c<sup>T<\/sup>x<\/code> subject to <code>Ax=b<\/code>&#8221; but I realize that&#8217;s not everyone&#8217;s cup of tea.\u00a0 Instead, you can think of an ILP problem like this: you have a large set of variables from which you want to choose only those that meet some constraint.\u00a0 Then within those that meet that constraint, you want to maximize some value.<\/p>\n<p>How does this work in our case?\u00a0 Let&#8217;s set the variables to be the words in our word list, and the constraints are (1) the number of letters in the word, and (2) the starting letter of the word.\u00a0 You can visualize this like so:<\/p>\n<pre>[\r\n  {\r\n    \"word\": \"theater\"\r\n  , \"a\": 1\r\n  , \"e\": 2\r\n  , \"h\": 1\r\n  , \"r\": 1\r\n  , \"t\": 2\r\n  , \"t_first\": 1\r\n  \/\/ all other variables 0\r\n  }\r\n, {\r\n    \"word\": \"help\"\r\n  , \"e\": 1\r\n  , \"h\": 1\r\n  , \"l\": 1\r\n  , \"p\": 1\r\n  , \"h_first\": 1\r\n  \/\/ all other variables 0\r\n  }\r\n  ...\r\n]\r\n<\/pre>\n<p>In our case,we have two constraints: the total sum of our letters must match the letter counts from the quote, and the first letter counts must match the letter counts from the source.\u00a0 So the constraints might look like<\/p>\n<pre>{\r\n  \"a\": 4\r\n, \"b\": 2\r\n...\r\n, \"a_first\": 2\r\n, \"b_first: 0\r\n...\r\n}\r\n<\/pre>\n<p><em>Side note: this might be how the <a href=\"https:\/\/wordsmith.org\/anagram\/\">Internet Anagram Server<\/a> works?<\/em><\/p>\n<p>That&#8217;s basically it. Construct those variables, plug them in to an ILP solver and you&#8217;re done.\u00a0 But wait &#8212; we&#8217;re not maximizing anything!\u00a0 All we&#8217;re doing here is taking any old solution that works, but we could be maximizing score (from our word list), or minimizing deviation from the mean word length, or any number of things.\u00a0 This is an obvious extension to our code, and I hope someone jumps on it.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Crossword Nexus Solver has supported acrostic puzzles for a while now, but acrostic puzzles remain relatively uncommon in the indie puzzle community.\u00a0 This is a shame, because acrostic puzzles are very fun, and I for one want to see more of them.\u00a0 So what&#8217;s holding constructors back? Constructors may not know how to create&#8230;<\/p>\n<p class=\"more-link-wrap\"><a href=\"https:\/\/crosswordnexus.com\/blog\/2021\/07\/16\/creating-acrostic-puzzles\/\" class=\"more-link\">Read More<span class=\"screen-reader-text\"> &ldquo;Creating Acrostic Puzzles&rdquo;<\/span> &raquo;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-94","post","type-post","status-publish","format-standard","hentry","category-crossword-tools"],"_links":{"self":[{"href":"https:\/\/crosswordnexus.com\/blog\/wp-json\/wp\/v2\/posts\/94","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/crosswordnexus.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/crosswordnexus.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/crosswordnexus.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/crosswordnexus.com\/blog\/wp-json\/wp\/v2\/comments?post=94"}],"version-history":[{"count":7,"href":"https:\/\/crosswordnexus.com\/blog\/wp-json\/wp\/v2\/posts\/94\/revisions"}],"predecessor-version":[{"id":354,"href":"https:\/\/crosswordnexus.com\/blog\/wp-json\/wp\/v2\/posts\/94\/revisions\/354"}],"wp:attachment":[{"href":"https:\/\/crosswordnexus.com\/blog\/wp-json\/wp\/v2\/media?parent=94"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/crosswordnexus.com\/blog\/wp-json\/wp\/v2\/categories?post=94"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/crosswordnexus.com\/blog\/wp-json\/wp\/v2\/tags?post=94"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}