{"id":7732,"date":"2022-01-20T10:19:23","date_gmt":"2022-01-20T10:19:23","guid":{"rendered":"https:\/\/www.blopig.com\/blog\/?p=7732"},"modified":"2022-02-08T16:40:28","modified_gmt":"2022-02-08T16:40:28","slug":"solving-wordle-with-grep","status":"publish","type":"post","link":"https:\/\/www.blopig.com\/blog\/2022\/01\/solving-wordle-with-grep\/","title":{"rendered":"Solving WORDLE with grep"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">People seem to have become obsessed with <a href=\"https:\/\/www.powerlanguage.co.uk\/wordle\/\">wordle<\/a>, just like they became obsessed with sudoku.  After my initial burst of &#8220;oh a new game!&#8221; had waned, I was left thinking &#8220;my time is precious and this is exactly what we have computers for&#8221;.  With this in mind, below is my quick and dirty way of solving these.  I&#8217;m sure the regexp gurus amongst you will have a more elegant solution.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><em>Step 1<\/em><\/strong>: Make sure you&#8217;ve got <code>\/usr\/share\/dict\/words<\/code> installed.  This is just a huge list of words in a specific language and for me, this required installing the British words list.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">sudo apt-get install wbritish<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><em>Step 2<\/em><\/strong>: Go to wordle <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-medium\"><a href=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/01\/image-3.png?ssl=1\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"256\" height=\"300\" loading=\"lazy\" src=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/01\/image-3.png?resize=256%2C300&#038;ssl=1\" alt=\"\" class=\"wp-image-7733\" srcset=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/01\/image-3.png?resize=256%2C300&amp;ssl=1 256w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/01\/image-3.png?w=523&amp;ssl=1 523w\" sizes=\"auto, (max-width: 256px) 100vw, 256px\" \/><\/a><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><em>Step 3<\/em><\/strong>: Pick a random 5-letter word as your starting point.  This is where grep and \/usr\/share\/dict\/words comes in:<\/p>\n\n\n\n<!--more-->\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">grep -iE \"^[a-z]{5}$\" \/usr\/share\/dict\/words<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Whilst this does somewhat look like a cat has slept on your keyboard, let&#8217;s break it down:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">grep -modifier-flags \"starts-with [pattern-of-letters] {repeated n times} ends-with\" search-in-this-file<\/pre>\n\n\n\n<ul class=\"wp-block-list\"><li>The <code>-i<\/code> flag makes grep search in a case-<strong>i<\/strong>nsensitive manner<\/li><li>The -E flag says extend grep&#8217;s normal regular expressions to support repeats<\/li><li>The <code>^<\/code> means the pattern has to be at the beginning of the word<\/li><li><code>[a-z]<\/code> means search for all letters from a to z<\/li><li><code>{5}<\/code> means that pattern we just saw (i.e. a to z), repeat it 5 times.   This is the equivalent of doing <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">^[a-z][a-z][a-z][a-z][a-z]$<\/code><\/li><li><code>$ <\/code>means the pattern needs to be at the end of a word too. <\/li><li>Finally, we&#8217;re specifying where we want to look for our pattern of characters<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">After all of that, I piped the output to head, to only see a few results, otherwise I&#8217;d get a screenful of every 5-letter word in the dictionary, all 6071 of them.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The first word in my list, Aaron isn&#8217;t in wordle&#8217;s list, so I need another one, in this case, I picked &#8220;ACTION&#8221;.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><a href=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/01\/image-4.png?ssl=1\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"505\" height=\"260\" loading=\"lazy\" src=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/01\/image-4.png?resize=505%2C260&#038;ssl=1\" alt=\"\" class=\"wp-image-7734\" srcset=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/01\/image-4.png?w=505&amp;ssl=1 505w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/01\/image-4.png?resize=300%2C154&amp;ssl=1 300w\" sizes=\"auto, (max-width: 505px) 100vw, 505px\" \/><\/a><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Result!  I&#8217;ve got an O in the right place, the word contains a T (but it&#8217;s in the wrong place) and it does not contain an A C or N.  <\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><em>Step 4<\/em><\/strong>: Modify grep <\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">grep -iE \"^[a-z]{3}o[a-z]$\" \/usr\/share\/dict\/words | grep --invert-match [a,c,n] | grep t<\/pre>\n\n\n\n<p class=\"has-text-align-left wp-block-paragraph\">Grep is now searching for three letters, followed by an o, followed by another letter.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We then pass the results of this (222 words) into another grep but this time feeding grep the <code>--invert-match flag<\/code>.  This does what it says on the tin.  It only gives you results that <em>do not <\/em>contain the letters you&#8217;ve specified.  In this case, we know our word doesn&#8217;t contain an A, C or N.  Finally, since we know there&#8217;s a T, the final grep takes our 222 words and only finds us ones that contain a T, dropping our number of words down to 24.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Picking another random word out of my list, I went for DIVOT.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><a href=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/01\/image-5.png?ssl=1\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"513\" height=\"330\" loading=\"lazy\" src=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/01\/image-5.png?resize=513%2C330&#038;ssl=1\" alt=\"\" class=\"wp-image-7735\" srcset=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/01\/image-5.png?w=513&amp;ssl=1 513w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/01\/image-5.png?resize=300%2C193&amp;ssl=1 300w\" sizes=\"auto, (max-width: 513px) 100vw, 513px\" \/><\/a><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Progress.  I now know the word ends in OT and does not contain A,C, N, D, I or V.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><em>Step 5<\/em><\/strong>: Modify grep again<\/p>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\">grep -iE &#8220;^[a-z]{3}<strong>ot<\/strong>$&#8221; \/usr\/share\/dict\/words |grep &#8211;invert-match [a,c,n,<strong>d,i,v<\/strong>]<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This gave me the last seven words: Corot, Perot, begot, besot, helot, robot and shoot .<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><a href=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/01\/image-6.png?ssl=1\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"507\" height=\"399\" loading=\"lazy\" src=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/01\/image-6.png?resize=507%2C399&#038;ssl=1\" alt=\"\" class=\"wp-image-7736\" srcset=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/01\/image-6.png?w=507&amp;ssl=1 507w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2022\/01\/image-6.png?resize=300%2C236&amp;ssl=1 300w\" sizes=\"auto, (max-width: 507px) 100vw, 507px\" \/><\/a><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Having somewhat arbitrarily picked robot from that list, that&#8217;s all folks. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><em>Postscript<\/em><\/strong>: In order to get the most bang for our buck in our initial search, we ideally want to search for a word where each character is unique.  We could do this by using the lookahead function:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>grep -P '^([a-z])(?!\\1)([a-z])(?!\\1|\\2)([a-z])(?!\\1|\\2|\\3)([a-z])(?!\\1|\\2|\\3|\\4)([a-z])$' \/usr\/share\/dict\/words<\/code>  <\/p>\n","protected":false},"excerpt":{"rendered":"<p>People seem to have become obsessed with wordle, just like they became obsessed with sudoku. After my initial burst of &#8220;oh a new game!&#8221; had waned, I was left thinking &#8220;my time is precious and this is exactly what we have computers for&#8221;. With this in mind, below is my quick and dirty way of [&hellip;]<\/p>\n","protected":false},"author":15,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"nf_dc_page":"","wikipediapreview_detectlinks":true,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"ngg_post_thumbnail":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[348,296,14],"tags":[],"ppma_author":[507],"class_list":["post-7732","post","type-post","status-publish","format-standard","hentry","category-bash","category-hints-and-tips","category-howto"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"authors":[{"term_id":507,"user_id":15,"is_guest":0,"slug":"eoin","display_name":"Eoin Malins","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/e91a9cf8b77625a1bc34e56f5dc36439a1f61476804b087e5b47554425879210?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts\/7732","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/comments?post=7732"}],"version-history":[{"count":4,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts\/7732\/revisions"}],"predecessor-version":[{"id":7789,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts\/7732\/revisions\/7789"}],"wp:attachment":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/media?parent=7732"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/categories?post=7732"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/tags?post=7732"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=7732"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}