10
\$\begingroup\$

In Keep Talking and Nobody Explodes, players are tasked with defusing bombs based on information from their "experts" (other people with a manual). Each bomb is made up of modules, one of which can be passwords, where the expert is given this list of possible passwords, all five letters long:

about   after   again   below   could
every   first   found   great   house
large   learn   never   other   place
plant   point   right   small   sound
spell   still   study   their   there
these   thing   think   three   water
where   which   world   would   write

And the player is given a list of 6 possible letters for each place in the password. Given the possible letter combinations, output the correct password. Input can be in any reasonable format (2D array, string separated by newline, etc.) You may discount the code which you use to compress/generate the list/string/array/whatever of passwords. (Thanks @DenkerAffe)

NOTE: Passwords are case insensitive. You may assume that input will only solve for one password.

Examples / Test Cases

Input here will be represented as a array of strings.

["FGARTW","LKSIRE","UHRKPA","TGYSTG","LUOTEU"] => first
["ULOIPE","GEYARF","SHRGWE","JEHSDG","EJHDSP"] => large
["SHWYEU","YEUTLS","IHEWRA","HWULER","EUELJD"] => still
\$\endgroup\$
  • \$\begingroup\$ Related. \$\endgroup\$ – Rɪᴋᴇʀ May 23 '16 at 0:17
  • 8
    \$\begingroup\$ I suggest allowing the list of possible passwords as input to the program. Otherwise this comes down to which language has the best string compression. \$\endgroup\$ – Denker May 23 '16 at 0:22
  • 5
    \$\begingroup\$ It's fine if you change it; I wouldn't mind (the bulk of my submission would remain unchanged). \$\endgroup\$ – Doorknob May 23 '16 at 0:30
  • 4
    \$\begingroup\$ I agree with DenkerAffe - having the possible passwords be given as input rather than a static list makes for a much more interesting challenge. \$\endgroup\$ – Mego May 23 '16 at 0:48
  • 5
    \$\begingroup\$ It might simplify things if you use the list of strings as a second input, as well, since it makes it clear which bytes count. I wasn't sure whether to count the < in my Bash solution, for example. \$\endgroup\$ – Doorknob May 23 '16 at 1:00
5
\$\begingroup\$

Pyth, 13 bytes

:#%*"[%s]"5Q0c"ABOUTAFTERAGAINBELOWCOULDEVERYFIRSTFOUNDGREATHOUSELARGELEARNNEVEROTHERPLACEPLANTPOINTRIGHTSMALLSOUNDSPELLSTILLSTUDYTHEIRTHERETHESETHINGTHINKTHREEWATERWHEREWHICHWORLDWOULDWRITE"5

Test suite.

 #             filter possible words on
:           0  regex match, with pattern
  %        Q   format input as
    "[%s]"     surround each group of letters with brackets (regex char class)
   *      5    repeat format string 5 times for 5 groups of letters
\$\endgroup\$
  • \$\begingroup\$ You forgot to update your first code block :P \$\endgroup\$ – Downgoat May 23 '16 at 1:27
  • \$\begingroup\$ @Downgoat What did I forget to update? It looks right to me. \$\endgroup\$ – Doorknob May 23 '16 at 1:42
  • \$\begingroup\$ Odd, the first code block seems to not match the example (it appears to be an old revision?) \$\endgroup\$ – Downgoat May 23 '16 at 1:56
  • 1
    \$\begingroup\$ 8 bytes \$\endgroup\$ – Leaky Nun May 23 '16 at 11:01
6
\$\begingroup\$

Bash, 22 bytes

grep `printf [%s] $@`< <(echo ABOUTAFTERAGAINBELOWCOULDEVERYFIRSTFOUNDGREATHOUSELARGELEARNNEVEROTHERPLACEPLANTPOINTRIGHTSMALLSOUNDSPELLSTILLSTUDYTHEIRTHERETHESETHINGTHINKTHREEWATERWHEREWHICHWORLDWOULDWRITE | sed 's/...../&\n/g')

Run like so:

llama@llama:~$ bash passwords.sh FGARTW LKSIRE UHRKPA TGYSTG LUOTEU
FIRST
      printf [%s] $@    surround all command line args with brackets
grep `              `   output all input lines that match this as a regex
                     <  use the following file as input to grep
\$\endgroup\$
  • \$\begingroup\$ It makes no difference to your score, but I still couldn't resist this golf: fold -5<<<ABOUTAFTERAGAINBELOWCOULDEVERYFIRSTFOUNDGREATHOUSELARGELEARNNEVEROTHERPLACEPLANTPOINTRIGHTSMALLSOUNDSPELLSTILLSTUDYTHEIRTHERETHESETHINGTHINKTHREEWATERWHEREWHICHWORLDWOULDWRITE|grep `printf [%s] $@` \$\endgroup\$ – Digital Trauma May 23 '16 at 20:54
2
\$\begingroup\$

JavaScript (ES6), 62 bytes

(l,p)=>p.find(w=>l.every((s,i)=>eval(`/[${s}]/i`).test(w[i])))

53 bytes on Firefox 48 or earlier:

(l,p)=>p.find(w=>l.every((s,i)=>~s.search(w[i],"i")))

Would have been 49 bytes if not for that case insensitivity requirement:

(l,p)=>p.find(w=>l.every((s,i)=>~s.search(w[i])))

f=
  (l,p)=>p.find(w=>l.every((s,i)=>eval(`/[${s}]/i`).test(w[i])))
;
p=["about","after","again","below","could","every","first","found","great","house","large","learn","never","other","place","plant","point","right","small","sound","spell","still","study","their","there","these","thing","think","three","water","where","which","world","would","write"];
o1.value=f(["FGARTW","LKSIRE","UHRKPA","TGYSTG","LUOTEU"],p)
o2.value=f(["ULOIPE","GEYARF","SHRGWE","JEHSDG","EJHDSP"],p)
o3.value=f(["SHWYEU","YEUTLS","IHEWRA","HWULER","EUELJD"],p)
<input id=o1><input id=o2><input id=o3>

\$\endgroup\$
2
\$\begingroup\$

Brachylog, 25 bytes

:@laL,["about":"after":"again":"below":"could":"every":"first":"found":"great":"house":"large":"learn":"never":"other":"place":"plant":"point":"right":"small":"sound":"spell":"still":"study":"their":"there":"these":"thing":"think":"three":"water":"where":"which":"world":"would":"write"]:Jm.'(:ImC,L:Im'mC)

The uncounted bytes are the array of words, including the square brackets.

Explanation

:@laL                          Unifies L with the input where each string is lowercased
     ,[...]:Jm.                Unifies the Output with one of the words
               '(            ) True if what's in the parentheses is false,
                               else backtrack and try another word
                 :ImC          Unify C with the I'th character of the output
                     ,L:Im'mC  True if C is not part of the I'th string of L
\$\endgroup\$
2
\$\begingroup\$

Ruby, 48 42 39 bytes

Now that it's done, it's very similar to the Pyth solution, but without %s formatting to the point where it's basically a direct port now.

If you only output the result with puts, you don't need the [0] at the end since puts will deal with that for you.

->w,l{w.grep(/#{'[%s]'*l.size%l}/i)[0]}

With test cases:

f=->w,l{w.grep(/#{'[%s]'*l.size%l}/i)[0]}

w = %w{about after again below could
every first found great house
large learn never other place
plant point right small sound
spell still study their there
these thing think three water
where which world would write}

puts f.call(w, ["FGARTW","LKSIRE","UHRKPA","TGYSTG","LUOTEU"]) # first
puts f.call(w, ["ULOIPE","GEYARF","SHRGWE","JEHSDG","EJHDSP"]) # large
puts f.call(w, ["SHWYEU","YEUTLS","IHEWRA","HWULER","EUELJD"]) # still
\$\endgroup\$
1
\$\begingroup\$

JavaScript (ES6), 71 bytes

w=>l=>w.filter(s=>eval("for(b=1,i=5;i--;)b&=!!~l[i].indexOf(s[i])")[0])

Usage:

f=w=>l=>w.filter(s=>eval("for(b=1,i=5;i--;)b&=!!~l[i].indexOf(s[i])")[0])
f(array_of_words)(array_of_letters)
\$\endgroup\$
1
\$\begingroup\$

Python, 64 60 57 bytes

Code to create word list w as string, words are space-separated (bytes are discounted from solution code length):

w="about after again below could every first found great house large learn never other place plant point right small sound spell still study their there these thing think three water where which world would write"

Current solution (57 bytes): saved 3 bytes thanks to @RootTwo

import re;f=lambda a:re.findall("(?i)\\b"+"[%s]"*5%a,w)[0]

This function takes a tuple (no list!) of exactly 5 strings which represent the possible letters for each password character as input.

See this code running on ideone.com


Second version (60 bytes):

import re;f=lambda a:re.findall("\\b"+"[%s]"*5%a+"(?i)",w)[0]

This function takes a tuple (no list!) of exactly 5 strings which represent the possible letters for each password character as input.

See this code running on ideone.com

First version (64 bytes):

import re;f=lambda a:re.findall("\\b["+"][".join(a)+"](?i)",w)[0]

This function takes any iterable (e.g. list or tuple) of exactly 5 strings which represent the possible letters for each password character as input.

See this code running on ideone.com

\$\endgroup\$
  • 1
    \$\begingroup\$ Save three bytes by using this regex: "(?i)\\b"+"[%s]"*5%a \$\endgroup\$ – RootTwo May 23 '16 at 19:54
  • \$\begingroup\$ Of course, what an obvious "mistake" from my side... Thank you for pointing this out @RootTwo, I edited my answer and gave you credits. \$\endgroup\$ – Byte Commander May 23 '16 at 20:34
  • \$\begingroup\$ @ByteCommander I don't see any credit at all. \$\endgroup\$ – Erik the Outgolfer May 24 '16 at 8:06
  • \$\begingroup\$ @ΈρικΚωνσταντόπουλος Right below the w=... code line: "The actual solution (57 bytes, saved 3 bytes thanks to @RootTwo):" \$\endgroup\$ – Byte Commander May 24 '16 at 8:10
  • \$\begingroup\$ @ByteCommander Maybe I previewed an earlier version after waking my pc up from hibernation. \$\endgroup\$ – Erik the Outgolfer May 24 '16 at 8:15
0
\$\begingroup\$

Hoon, 125 bytes

|=
r/(list tape)
=+
^=
a
|-
?~
r
(easy ~)
;~
plug
(mask i.r)
(knee *tape |.(^$(r t.r)))
==
(skip pass |*(* =(~ (rust +< a))))

Ungolfed:

|=  r/(list tape)
=+  ^=  a
|-
  ?~  r
    (easy ~)
  ;~  plug
    (mask i.r)
    (knee *tape |.(^$(r t.r)))
  ==
(skip pass |*(* =(~ (rust +< a))))

Hoon doesn't have regex, only a parser combinator system. This makes it pretty complicated to get everything working: (mask "abc") roughly translates to regex's [abc], and is the core of the parser that we are building.

;~(plug a b) is a monadic bind of two parsers under ++plug, which has to parse the first and then second or else it fails.

++knee is used to build a recursive parser; we give it a type (*tape) of the result, and a callback to call to generate the actual parser. In this case, the callback is "call the entire closure again, but with the tail of the list instead". The ?~ rune tests is the list is empty, and gives (easy ~) (don't parse anything and return ~) or adds on another mask and recurse again.

Having built the parser, we can get to using it. ++skip removes all elements of the list for which the function returns yes for. ++rust tries to parse the element with our rule, returning a unit which is either [~ u=result] or ~ (our version of Haskell's Maybe). If it's ~ (None, and the rule either failed to parse or didn't parse the entire contents), then the function returns true and the element is removed.

What's left over is a list, containing only the word where each letter is one of the options in the list given. I'm assuming that the list of passwords is already in the context under the name pass.

> =pass %.  :*  "ABOUT"  "AFTER"   "AGAIN"   "BELOW"   "COULD"
   "EVERY"   "FIRST"   "FOUND"   "GREAT"   "HOUSE"
   "LARGE"   "LEARN"   "NEVER"   "OTHER"   "PLACE"
   "PLANT"   "POINT"   "RIGHT"   "SMALL"   "SOUND"
   "SPELL"   "STILL"   "STUDY"   "THEIR"   "THERE"
   "THESE"   "THING"   "THINK"   "THREE"   "WATER"
   "WHERE"   "WHICH"   "WORLD"   "WOULD"   "WRITE"
   ~  ==  limo
> %.  ~["SHWYEU" "YEUTLS" "IHEWRA" "HWULER" "EUELJD"]
  |=
  r/(list tape)
  =+
  ^=
  a
  |-
  ?~
  r
  (easy ~)
  ;~
  plug
  (mask i.r)
  (knee *tape |.(^$(r t.r)))
  ==
  (skip pass |*(* =(~ (rust +< a))))
[i="STILL" t=<<>>]
\$\endgroup\$
0
\$\begingroup\$

Python 3, 81 bytes

from itertools import*
lambda x:[i for i in map(''.join,product(*x))if i in l][0]

An anonymous function that takes input of a list of strings x and returns the password.

The list of possible passwords l is defined as:

l=['ABOUT', 'AFTER', 'AGAIN', 'BELOW', 'COULD',
   'EVERY', 'FIRST', 'FOUND', 'GREAT', 'HOUSE',
   'LARGE', 'LEARN', 'NEVER', 'OTHER', 'PLACE',
   'PLANT', 'POINT', 'RIGHT', 'SMALL', 'SOUND',
   'SPELL', 'STILL', 'STUDY', 'THEIR', 'THERE',
   'THESE', 'THING', 'THINK', 'THREE', 'WATER',
   'WHERE', 'WHICH', 'WORLD', 'WOULD', 'WRITE']

This is a simple brute force; I was interested to see how short I could get this without regexes.

How it works

from itertools import*  Import everything from the Python module for iterable generation
lambda x                Anonymous function with input list of strings x
product(*x)             Yield an iterable containing all possible passwords character by
                        character
map(''.join,...)        Yield an iterable containing all possible passwords as strings by
                        concatenation
...for i in...          For all possible passwords i...
i...if i in l           ...yield i if i is in the password list
:[...][0]               Yield the first element of the single-element list containing the
                        correct password and return

Try it on Ideone

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.