18
\$\begingroup\$

Given a permutation of the alphabet and an intended "word", determine if the word was guessed in a game of Hangman, where the permutation is the list of guesses.

For example, given ASTNORDYUVKFMCLWIHEBQGPJXZ as the permutation, and ASTRONAUT as the word, we know that the word was guessed. Only 2 letters (DY) were wrong before guessing U to complete the word. At the end of the game, the gallows look like

  |
  |
  |
  |
  |
  |
------

so the man wasn't hanged and the guesser wins.

However, if the word was PAYMENT, then there are 12 wrong guesses (SORDUVKFCLWI) before the word is complete (the "filled in" word looks like _AYM_NT at the end), so the guesser loses.

The full gallows takes 12 steps to finish:

                                      ------   ------   ------   ------   ------   ------   ------   ------
           |        |        |/       |/       |/   |   |/   |   |/   |   |/   |   |/   |   |/   |   |/   |
           |        |        |        |        |        |    O   |    O   |    O   |    O   |    O   |    O
           |        |        |        |        |        |        |    |   |   /|   |   /|\  |   /|\  |   /|\
           |        |        |        |        |        |        |        |        |        |   /    |   / \
           |        |        |        |        |        |        |        |        |        |        |
           |        |\       |\       |\       |\       |\       |\       |\       |\       |\       |\
------   ------   ------   ------   ------   ------   ------   ------   ------   ------   ------   ------

So 12 wrong guesses before the final correct letter is a loss and the final correct letter before 12 wrong guesses is a win.


You are to take 2 strings as input:

  • A 26 character long string, containing 26 unique letters in a consistent case i.e. a permutation of either the uppercase or lowercase alphabet
  • A string containing a maximum of 26 unique characters and a minimum of 1 character, in the same case as the permutation

You should then output 2 distinct values to indicate whether the word was guessed before 12 wrong guesses or not.

You may input and output in any convenient method. The length of the second input will never exceed your language's integer maximum.

This is so the shortest code in bytes wins.

Test cases

permutation, word -> output
ABCDEFGHIJKLMNOPQRSTUVWXYZ, CGCC -> 1
ABCDEFGHIJKLMNOPQRSTUVWXYZ, LAB -> 1
ABCDEFGHIJKLMNOPQRSTUVWXYZ, MOP -> 0
ABCDEFGHIJKLMNOPQRSTUVWXYZ, MNOPQRSTUVWXYZ -> 0
ABCDEFGHIJKLMNOPQRSTUVWXYZ, LMNOPQRSTUVWXYZ -> 1
NYLZCBTOAFEQMVJWRHKIUGDPSX, NYLON -> 1
NYLZCBTOAFEQMVJWRHKIUGDPSX, GOLF -> 0
DXAPMHBYRVNKOFQZCSWUEJLTGI, ABCDEFGHIJKLMNOPQRSTUVWXYZ -> 1
INRLVTXOZSAKWJYFBQDMGPHUCE, IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII -> 1
INRLVTXOZSAKWJYFBQDMGPHUCE, EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE -> 0
FICUJKXZYVDGEWRLMANBHOPSTQ, RDRYMUTSDOVSEHWT -> 0
ASTNORDYUVKFMCLWIHEBQGPJXZ, ASTRONAUT -> 1
ASTNORDYUVKFMCLWIHEBQGPJXZ, PAYMENT -> 0

Here is a Jelly program which automatically generates test cases in the form

permutation
word
output

Spoilers for anyone who understands Jelly

\$\endgroup\$
5
  • \$\begingroup\$ Brownie points for beating my 10 byte Jelly answer - the first line in the test case generator \$\endgroup\$ Apr 21, 2021 at 0:19
  • 2
    \$\begingroup\$ @Arnauld Added ABCDEFGHIJKLMNOPQRSTUVWXYZ, MNOPQRSTUVWXYZ -> 0 as a test case \$\endgroup\$ Apr 21, 2021 at 1:03
  • 1
    \$\begingroup\$ I'd suggest adding a testcase where exactly 11 wrong guesses are made (if I'm not mistaken, there isn't any at the moment), something like ABCDEFGHIJKLMNOPQRSTUVWXYZ, LMNO -> 1. This may help catch some off-by-1 errors. \$\endgroup\$
    – Delfad0r
    Apr 21, 2021 at 7:54
  • 1
    \$\begingroup\$ @Delfad0r Far too late, but added ABCDEFGHIJKLMNOPQRSTUVWXYZ, LMNOPQRSTUVWXYZ -> 1 as a test case \$\endgroup\$ Apr 24, 2021 at 22:37
  • \$\begingroup\$ Good thing my solution still works :) \$\endgroup\$
    – Delfad0r
    Apr 24, 2021 at 22:48

19 Answers 19

9
\$\begingroup\$

JavaScript (ES6),  43 41  40 bytes

Expects (alphabet)(word), where alphabet is an array of characters. Returns a Boolean value.

a=>w=>a.every(c=>w.match(c)?~a<11:a=~-a)

Try it online!

Commented

a =>             // a[] = alphabet, reused as a negative counter of errors
w =>             // w = word to guess
  a.every(c =>   // for each character c in a[]:
    w.match(c) ? //   if c appears at least once in the word:
      ~a < 11    //     make sure that there was less than 12 errors so far
                 //     (this is equivalent to a > -12)
                 //     NB: we only need to test the number of errors when a
                 //     correct character is found, for it means that the word
                 //     was not fully guessed yet
    :            //   else:
      a = ~-a    //     decrement a (always truthy)
  )              // end of every()
\$\endgroup\$
1
  • 5
    \$\begingroup\$ I got ninja'd and outgolfed by 38 bytes, today is not my day lol \$\endgroup\$ Apr 21, 2021 at 0:33
7
\$\begingroup\$

Python 3, 42 bytes

lambda a,s:max(map(a.find,s))-len({*s})<11

max(map(a.find,s)) gives us the index of the final correct letter. Subtracting this by the number of unique characters in \$ s \$, gives us the total number of incorrect guesses. Finally, ...<11 ensures that at most 11 incorrect guesses are made.

Try it online!

\$\endgroup\$
7
\$\begingroup\$

J, 21 19 bytes

12>1#.0=#:@#.@|.@e.

Try it online!

Consider:

echo 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' f 'CGCC'
  • e. Is each left char an element of the right string?

    0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    
  • |.@ Reverse

    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0
    
  • #:@#.@ We want to remove those leading zeroes, so we convert to decimal number #. and then back to a binary one #:

    1 0 0 0 1 0 0
    
  • 12>1#.0= Sum the remaining zeroes and check if there are less than 12.

\$\endgroup\$
6
\$\begingroup\$

Jelly, 8 bytes

iⱮṬ¬S<12

Try it online!

-1 byte thanks to caird coinheringaahing

Explanation

iⱮṬ¬S<12   Main Link
 Ɱ         For each element in the right argument (the word to guess)
i          Find its index in the left argument (the guess order)
  Ṭ        Array with 1s in those indices; removes duplicates and only leaves zeroes before the last one, so the number of zeroes is the number of wrong guesses before we guess the word
   ¬       Logical NOT; the 0s and 1s swap
    S      Sum (we could've also done "count zeroes" instead of "NOT -> sum")
     <12   Is the number of wrong guesses less than 12?
\$\endgroup\$
3
  • 2
    \$\begingroup\$ Ah, ṢṬ¬, clever! I had a failed solution that used instead \$\endgroup\$ Apr 21, 2021 at 0:26
  • 1
    \$\begingroup\$ is order-independent, so you can remove the : Try it online! \$\endgroup\$ Apr 21, 2021 at 0:33
  • \$\begingroup\$ @cairdcoinheringaahing Right; I only remembered Ṭ after I sorted and was trying to think of what to do from there :P thanks! \$\endgroup\$
    – hyper-neutrino
    Apr 21, 2021 at 0:35
4
\$\begingroup\$

Vim, 34 bytes

qf11llddqu:s/[^<C-r><C-w>]*$
:s/[<C-r><C-w>]//g
@f

Try it online! (falsey test, pangram test)

Takes the secret word followed by the permutation, comma separated.

qq11llddqu
qf      q          " define a macro named 'f'
  11l              "   go forward 11 characters (succeeds if it can move at least 1)
     l             "   and one more *exiting f if we can't*
      dd           "   delete the current line
         u         " undo the line deletion for now
:s/[^<C-r><C-w>]*$ " delete the maximal suffix of this line of characters not in the word
                   "   <C-r><C-w> inserts the word under the cursor (i.e. the secret word) into the expression
:s/[<C-r><C-w>]//g " delete all characters which are in the word
@f                 " call f

This will delete the (only) line in the buffer if there are at least 12 wrong guesses before the word is complete (falsey), or leave a ',' followed by some letters (i.e. the possibly empty set of wrongly guessed letters).

The f macro came out shorter than using the expression register:

C<C-r>=len("<C-r>"")<12

\$\endgroup\$
3
\$\begingroup\$

Ruby, 45 40 34 bytes

->g,s{!g[/.*[#{s}]/].tr(s,'')[12]}

Try it online!

-6 bytes thanks to "G B" for the "index into string to verify min length" trick!

I kinda liked the idea of solving it with a regex...

We just greedily match for a string ending in one of the chars from our target string, then remove the target string chars from that match, then check the size.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ 34 bytes: ->g,s{!g[/.*[#{s}]/].tr(s,'')[12]} \$\endgroup\$
    – G B
    Apr 21, 2021 at 12:12
  • \$\begingroup\$ @GB Nice trick, tyvm. \$\endgroup\$
    – Jonah
    Apr 21, 2021 at 13:22
3
\$\begingroup\$

JavaScript (Node.js), 39 bytes

a=>w=>!a.match(`(.*[^${w}]){12}[${w}]`)

Try it online!

\$\endgroup\$
3
\$\begingroup\$

R, 46 bytes

function(a,w)max(m<-which(a%in%w))-sum(m|1)<12

Try it online!

Input is two vectors of characters representing the alphabet (a) and the word (w). Outputs TRUE if I did not die.

Checks that the maximum index (which) of the elements of a that are in w is not 12 greater than the number m of those elements (which is the number of unique elements of w).

\$\endgroup\$
3
  • \$\begingroup\$ Doesn't this fail if the word w contains the same letter multiple times? If the word is 'aaaaab' you can only guess 14 letters, not 18. \$\endgroup\$
    – quarague
    Apr 22, 2021 at 7:35
  • \$\begingroup\$ @quarague - I think it's Ok - check this and tell me if I'm wrong. The important point is that we check for elements of a in w, not the other way around, so duplicated letters in w don't make any difference. \$\endgroup\$ Apr 22, 2021 at 7:41
  • \$\begingroup\$ I see, checking of a in w is what makes the difference. Thanks. \$\endgroup\$
    – quarague
    Apr 22, 2021 at 7:50
3
\$\begingroup\$

Husk, 10 9 bytes

Edit: -1 byte thanks to Leo

↓12-¹Σhġ€

Try it online!

Arg1 = word; Arg2 = alphabet; Outputs truthy if I did die (list of excess moves needed after hangman is already complete), falsy (empty list) if I did not die.

        ġ€    # group arg2 by whether each element is present in arg1
       h      # discard the last group (all the letters
              # after the last guess, or the last guess itself)
      Σ       # put groups back together into one list
    -¹        # get only letters not present in arg1
 ↓12          # remove the first 12 of them.
\$\endgroup\$
2
  • \$\begingroup\$ You can save one byte by returning an empty list (falsy) if you survive and a nonempty list (truthy) if you die: Try it online! \$\endgroup\$
    – Leo
    Apr 23, 2021 at 5:40
  • 1
    \$\begingroup\$ @Leo - Lovely! That's sneaky and clever! Thanks a lot! \$\endgroup\$ Apr 23, 2021 at 14:27
2
\$\begingroup\$

Charcoal, 17 bytes

‹LΦ…θ⌈Eη⌕θι¬№ηι¹²

Try it online! Link is to verbose version of code. Outputs a Charcoal boolean, i.e. - for a win, nothing for a loss. Explanation:

    θ               Input permutation
   …                Truncated to length
       η            Input word
      E             Map over characters
         θ          Input permutation
        ⌕           Find index of
          ι         Current character
     ⌈              Take the maximum
  Φ                 Filtered where
            №       Count of
              ι     Current character in
             η      Input word
           ¬        Is zero
 L                  Take the length
‹                   Is it less than
               ¹²   Literal `12`?
\$\endgroup\$
2
\$\begingroup\$

Japt, 10 bytes

ôoV ÔŬÊ<C

Try it online! or check all test cases

Explanation:

ôoV ÔŬÊ<C    
ô             # Remove characters from Input 1 where:
 oV           #  It appears in Input 2
              # And split where characters were removed
    Ô         # Reverse the resulting array
     Å        # Remove the first element
      ¬       # Join the remaining strings
       Ê      # Get the total length
        <C    # Return true if less than 12, false otherwise
\$\endgroup\$
2
\$\begingroup\$

K (ngn/k), 14 bytes

12>+/~2\2/|~^?

Try it online!

A straightforward port of @Jonah's J answer.

Implicitly takes a pair of args; x as the word, and y as the permutation.

  • ~^? check whether each letter in y is present in x (literally, not null x find y)
  • 2\2/| a port of @Jonah's logic to trim trailing 0's appearing after the last 1 (convert the reverse of the boolean list from base 2, then back to base 2; although the resulting list is reversed, this doesn't matter, as...)
  • 12>+/~ is 12 greater than the number of 0's in the trimmed list?
\$\endgroup\$
2
\$\begingroup\$

Haskell, 61 bytes

(12#)
(l#(h:t))w|elem h w=l>0&&(l#t)w|i<-l-1=i#t$w
(_#_)_=0<1

Try it online!

Standard recursive implementation. The relevant function is (12#), which takes as input the alphabet and the word as Strings and returns True for guessed, False for dead.

\$\endgroup\$
1
\$\begingroup\$

Retina 0.8.2, 35 bytes

(.*)(.).*(,.*\2)
$1$3
Dr`
^.{0,11},

Try it online! Link includes test cases. Explanation:

(.*)(.).*(,.*\2)
$1$3

Delete the permutation starting at the last correct letter.

Dr`

Remove all remaining correct letters from the permutation.

^.{0,11},

Check that there were no more than 11 incorrect letters left.

\$\endgroup\$
1
\$\begingroup\$

Zsh -ey, 40 bytes

for c (${1/// })((${2[(I)$c]}?e<12:++e))

Try it online! or verify all test cases

Takes input in command-line arguments (alphabet word) and outputs via status code (0 = survived, 1 = died). Uses @Arnauld's method.

Explanation:

  • ${1/// }: replace every empty string in the first input with a space. With -y, effectively splits into a list of characters.
  • for c () for each character $c:
    • (()): arithmetic expression; succeeds only if the result is non-zero
    • [(I)]: find the 1-based index of $c in ${2}: the second input. If there is no instance, returns 0.
    • ?:: if that was truthy (i.e. the character is present in the word), then return the 0/1 boolean value of e<12. Otherwise, increment e and return it ($e implicitly starts as 0)
  • -e flag: like a logical AND over the whole program, so the program will succeed only if every arithmetic expression also succeeded
\$\endgroup\$
1
\$\begingroup\$

Perl 5 -pl, 37 bytes

$b=<>;s/[^$b]/0/g;s/0*$//;$_=y/0//<12

Try it online!

Changes all non-target letters in the alphabet to 0, removes trailing 0s and then counts how many remain to determine if the limit has been reached before completing the target word.

\$\endgroup\$
1
\$\begingroup\$

C#, 78 bytes

(g,w)=>{return !w.Distinct().Where(p=>!g.Substring(0,12).Contains(p)).Any();};

returns TRUE if any character is NOT contained in the first 12 guesses, if TRUE then test does not pass, so success variable needs to be the opposite (FALSE). if FALSE then test passes, so success variable needs to be the opposite (TRUE).

Explanation:

 !                             # NOT
  w.Distinct()                 # Get distinct letters from the word to guess (w)
    .Where                     # find 
     p =>                      # each distinct letter to guess (w) into p
      !                        # NOT
       g.Substring(0, 12)      # first 12 characters of guess
        .Contains(p)           # is p contained in string
         .Any()                # returns true if any matched the condition
\$\endgroup\$
2
  • 3
    \$\begingroup\$ Welcome to Code Golf, and nice first answer! Be sure to check out our Tips for golfing in C# page for ways you can golf your program. This is currently a snippet, which we don't allow. However, you can turn it into a function by prepending(w,p)=>. You can also remove all the spaces to further reduce your byte count, and be sure to check out an online interpreter such as TIO so that others can run your code \$\endgroup\$ Apr 21, 2021 at 20:41
  • \$\begingroup\$ thank you for your feedback, changed it. \$\endgroup\$
    – Alex
    Apr 22, 2021 at 20:18
1
\$\begingroup\$

Julia, 37 bytes

a*b=findlast(a.∈b)-length(b∪b)<12

expects permutation*word with permutation a list of characters and word a String

b∪b is union(b,b) which is equivalent to unique(b)

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Bash/Zsh, 29 bytes

[[ $1 =~ (.*[^$2]){12}[$2] ]]

Try it online!

  • List of letters is given as first argument
  • Word to find is given as second argument
  • Exit status is 0 if dead and 1 if alive

This is the builtin equivalent to egrep -q "(.*[^$2]){12}[$2]" <<< $1

The idea is to build an extended regex that checks whether there are at least 12 letters not in the word to find (= wrong guesses) before any letter in that word (= guesses that came too late).

(initially 32 bytes, but enhanced with the help of this answer from @tsh who had the same idea long before me)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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