23
\$\begingroup\$

(inspired by a question over on Code Review)

Suppose two people are playing Hangman, but you've only overheard the game and want to draw the current status.

Given two words as input, where the words each match [A-Z]+ or [a-z]+ (your choice), output the current state of the hangman game as ASCII art, following the below rules.

  • The first word is the word to be guessed, and the second word is the already-guessed letters. These can be taken as input in any order.
  • The word to be guessed is guaranteed non-empty, but the already-guessed letters may be empty (i.e., as if it's the start of the game).
  • The game will always be a valid hangman game (i.e., guessed letters won't be duplicated, letters won't be guessed past the end of the game, you'll only receive letters as input, etc.).
  • Below the hangman drawing must be the word to be guessed, with _ in place of letters yet unknown, separated by spaces. For example, if the word to be guessed was BOAT, then below the hangman drawing must be _ _ _ _. If the word was BOAT with A guessed, then below the drawing must be _ _ A _.
  • Below the word to be guessed must be letters already guessed that are not in the word. These can be in any order, and can be separated by any non-alphabetical separator, if so desired.

Here are the states of the hangman game, from initial start to game end. Each wrongly guessed letter advances the state by one. So the first wrongly guessed letter makes the head O appear, the next makes the body | appear, etc.

  +---+
  |   |
      |
      |
      |
      |
=========

  +---+
  |   |
  O   |
      |
      |
      |
=========

  +---+
  |   |
  O   |
  |   |
      |
      |
=========

  +---+
  |   |
  O   |
 /|   |
      |
      |
=========

  +---+
  |   |
  O   |
 /|\  |
      |
      |
=========

  +---+
  |   |
  O   |
 /|\  |
 /    |
      |
=========

  +---+
  |   |
  O   |
 /|\  |
 / \  |
      |
=========

Input

  • Two strings in any convenient format, with the first guaranteed non-empty.
  • You can take the input in either order (e.g., word to guess and then guessed letters, or vice versa). Please state in your submission the input order.

Output

The resulting ASCII art representation of the hangman game in progress, as described above, again in any convenient format.

Rules

  • Leading or trailing newlines or whitespace are all optional, so long as the characters themselves line up correctly.
  • Either a full program or a function are acceptable. If a function, you can return the output rather than printing it.
  • If possible, please include a link to an online testing environment so other people can try out your code!
  • Standard loopholes are forbidden.
  • This is so all usual golfing rules apply, and the shortest code (in bytes) wins.

Examples

#1

BOAT and ATG

  +---+
  |   |
  O   |
      |
      |
      |
=========
_ _ A T
G

#2

ZEPPELIN and

  +---+
  |   |
      |
      |
      |
      |
=========
_ _ _ _ _ _ _ _

#3

ZEPPELIN and EATOLINSHR

  +---+
  |   |
  O   |
 /|\  |
 / \  |
      |
=========
_ E _ _ E L I N
A T O S H R

#4

RHYTHM and ABCDE

  +---+
  |   |
  O   |
 /|\  |
 /    |
      |
=========
_ _ _ _ _ _
EDCBA

#5

BOAT and ATOB

  +---+
  |   |
      |
      |
      |
      |
=========
B O A T

#6

AIRPLANE and AJKEI

  +---+
  |   |
  O   |
  |   |
      |
      |
=========
A I _ _ _ A _ E
KJ
\$\endgroup\$
6
  • \$\begingroup\$ the wrong letters must preserve the input order? \$\endgroup\$
    – Rod
    Jul 26, 2017 at 18:33
  • \$\begingroup\$ @Rod No, don't need to preserve the order of the incorrect guesses. \$\endgroup\$ Jul 26, 2017 at 18:35
  • 2
    \$\begingroup\$ Please add a test case where all the letters are correctly guesses and one where all have been guessed \$\endgroup\$
    – Mr. Xcoder
    Jul 26, 2017 at 18:37
  • \$\begingroup\$ @Mr.Xcoder I've added test case #5 where the person successfully guessed "BOAT" right away. \$\endgroup\$ Jul 26, 2017 at 20:49
  • \$\begingroup\$ I've added a test case that has only 2 incorrect letters to distinguish between the correct building order and building top-to-bottom/left-to-right. \$\endgroup\$ Jul 30, 2017 at 4:35

13 Answers 13

10
\$\begingroup\$

Python 2, 215 192 184 183 bytes

-8 bytes thanks to Raphaël Côté
-1 byte thanks to Jonathan Frech

a,b=input()
j=' '.join
s=b-set(a)
print"""  +---+
  |   |
  %s   |
 %s%s%s  |
 %s %s  |
      |
=========
"""%tuple('O/|\/\\'[:len(s)].ljust(6)),j(['_',i][i in b]for i in a),'\n',j(s)

Try it online!

\$\endgroup\$
5
  • \$\begingroup\$ By converting all \n to newlines and using a multiline string with """, and also by using " any convenient format " of input and setting the set calls back into the input, I was able to drop to 172 bytes. \$\endgroup\$ Jul 27, 2017 at 2:06
  • \$\begingroup\$ hmm, could you link the changes? I only managed to reach 184 bytes \$\endgroup\$
    – Rod
    Jul 27, 2017 at 11:19
  • \$\begingroup\$ 184 is good: removing the sets from the code actually broke the output, so that did not work. Changing the \n so they became newlines did help but I actually only removed 3 bytes to 189.tio.run/… \$\endgroup\$ Jul 27, 2017 at 12:15
  • 1
    \$\begingroup\$ I believe you should be showing the body piece (|) instead of the left arm (/) when there are 2 wrong letters: Try it online \$\endgroup\$ Jul 30, 2017 at 3:58
  • \$\begingroup\$ "\\/" is equal to "\/". \$\endgroup\$ Sep 27, 2017 at 17:56
8
\$\begingroup\$

Charcoal, 83 69 68 bytes

Fη¿№θι⁰«ι→⊞υι»←⸿Fθ«⎇№ηιι_→»←⸿×=⁸↖=←↑⁵←+←³↓+|FLυ≡ι⁰↓O¹←|²/|³\⁴⸿ /⁵ \«

Try it online! Link is to verbose version of code. Edit: Saved 14 bytes by switching to switch. Saved 1 byte by printing the single | as a literal. Note: At the time the question was set, switch didn't work at all in Verbose mode and needed a trailing « in Succinct mode (the current version on TIO has neither bug, so it shows the Succinct translation as 67 bytes), while Map's bugs prevented me from using Print(Join(Map(q, Ternary(Count(h, i), i, "_")), " "));. Fortunately I managed to come up with a kludge for the same length (and indeed I also tried switching the other loop to a Map but it too came out at the same length). Explanation:

Fη              For each letter in the guess,
  ¿№θι⁰«        if the word to be guessed does not contain the letter,
        ι→      print the failed guess, leave a gap,
          ⊞υι»  and push the letter to the array.

←⸿              Move to the start of the previous line.

Fθ«             For each letter in the word to be guessed,
   ⎇№ηιι        if the letter has been guessed then print it
        _       otherwise print a _.
         →»     Either way, leave a gap.

←⸿              Move to the start of the previous line.

×=⁸             Print 8 =s
   ↖=←          Print a 9th =, moving into position to
      ↑⁵        print 5 |s upwards,
        ←+←³    a + and 3 -s left,
            ↓+| and a + and a | down.

FLυ             Loop once for each incorrect guess.
   ≡ι           Choose what to print based on the loop index.
     ⁰↓O        For the first incorrect guess, print an O.
     ¹←|        For the second incorrect guess, print a |.
     ²/         For the third incorrect guess, print a /.
     ³|\        For the fourth incorrect guess, print a \.
     ⁴⸿ /       For the fifth incorrect guess, print a / on the next line.
     ⁵ \        For the sixth incorrect guess, print another \.
\$\endgroup\$
9
  • 2
    \$\begingroup\$ this language...it scares me. \$\endgroup\$ Jul 26, 2017 at 21:30
  • \$\begingroup\$ @SergeyGrinev D: why is it so scary \$\endgroup\$
    – ASCII-only
    Jul 27, 2017 at 0:47
  • \$\begingroup\$ @ASCII-only I noticed you fixed Map(string, expression) but Map(array, expression) is still buggy - it alters the original array when used as an expression rather than as a command. Try it online! \$\endgroup\$
    – Neil
    Jul 27, 2017 at 8:05
  • \$\begingroup\$ @ASCII-only hehe, it's a great idea for a language, but scripts looks like something Lovecraft would use to summon Cthulhu spell. \$\endgroup\$ Jul 27, 2017 at 8:27
  • \$\begingroup\$ @Neil That's intended behavior, mostly so it modifies the canvas when mapping the Cells datatype, but I guess yeah you'd often need to use the original data after the map, it should be fixed by tomorrow \$\endgroup\$
    – ASCII-only
    Jul 27, 2017 at 10:35
7
\$\begingroup\$

Python 2, 220 bytes

x,y=input()
x=[['_',k][k in y]for k in x]
y-=set(x)
s='''  +---+
  |   |
  0   |
 213  |
 4 5  |
      |
'''
for i in range(6):s=s.replace(`i`,[' ','O|/\\/\\'[i]][len(y)>i])
print s+'='*9+'\n'+' '.join(x)+'\n'+''.join(y)

Try it online!

-35 bytes thanks to Raphaël Côté
-20 bytes using sets
-1 byte thanks to micsthepick

\$\endgroup\$
9
  • 3
    \$\begingroup\$ nice idea for the "replace" with numbers :) \$\endgroup\$ Jul 26, 2017 at 18:29
  • \$\begingroup\$ @V.Courtois Thanks :) I was going to use translate but that turned out to be longer lol. \$\endgroup\$
    – hyper-neutrino
    Jul 26, 2017 at 18:29
  • \$\begingroup\$ Hi @HyperNeutrino, good job with the submission! I think that the 2 loops at the end could be put into one, using this for i in range(7):s=s.replace(`i`,'O|/\\/\\'[i] if i<c else ' ').It gives you a single loop and you just switch out the replace if you are over c. You can lower to 251 bytes this way :) \$\endgroup\$ Jul 27, 2017 at 0:06
  • \$\begingroup\$ @RaphaëlCôté Nice golf. Thanks! \$\endgroup\$
    – hyper-neutrino
    Jul 27, 2017 at 0:11
  • \$\begingroup\$ c just became useless. Just use len(y) and save 4 bytes! We rock! \$\endgroup\$ Jul 27, 2017 at 0:15
5
\$\begingroup\$

Jelly,  72  73 bytes

+1 fixing an ace game bug that showed the full hanged person (changed LN to Lạ6 near the end)

e€a⁸o”_$,ḟ@©K€Y,@“¥[$⁼Ż⁸½c¤ṫȷṃl®ḌvNṂeL©?Ḥ’ṃ“ -¶|O/\=+”¤Y⁶“$"÷ȷñŒ‘ḣ®Lạ6¤¤¦

A dyadic link taking the word on the left and the (unique and within-game) letters on the right and returning a list of characters, or a full program taking the input as command line arguments and printing the result.

Try it online!

How?

Firstly:

“¥[$⁼Ż⁸½c¤ṫȷṃl®ḌvNṂeL©?Ḥ’ - base 250 number
                            = 305169639782226039115281574830092231403740634016078676

Is the numeric value of the full hanged person in base 9, where each of the 9 digits represent one of the characters: <space>, <newline>, -, |, O, /, \, =, or +.

the rest of the program:

e€a⁸o”_$,ḟ@©K€Y,@“...’ṃ“...”¤Y⁶“...‘ḣ®Lạ6¤¤¦ - Main link word, letters
e€                                           - exists in letters for €ach char in word
  a⁸                                         - and with word (word with 0 at un-guessed)
    o”_$                                     - or with '_' (word with _ at un-guessed)
         ḟ@                                  - filter remove (incorrect guesses)
           ©                                 - copy the result to the register and yield
        ,                                    - pair
            K€                               - join €ach with spaces
              Y                              - join with (a) newlines
                            ¤                - nilad followed by link(s) as a nilad:
                 “...’                       - the number described above
                       “...”                 - list of chars " -¶|O/\=+" (¶ = a newline)
                      ṃ                      - base decompress using the chars as digits
               ,@                            - pair (using swapped @rguments)
                             Y               - join with (a) newlines
                                           ¦ - sparse application:
                              ⁶              -   of: a space character
                                             -   to indexes:
                                          ¤  -     nilad followed by links as a nilad:
                               “...‘         -       literal [36,34,28,26,27,19]
                                         ¤   -       another nilad chain:
                                     ®       -         recall from register
                                      L      -         length (# of bad guesses)
                                       ạ6    -         absolute difference with 6
                                    ḣ        -       head (get the indexes to "erase"
                                             -             by applying the space char)
                                             - as a full program: implicit print
\$\endgroup\$
7
  • \$\begingroup\$ This fails on the BOAT and ATOB test case. Try it online! \$\endgroup\$ Jul 26, 2017 at 22:13
  • \$\begingroup\$ Ah thanks for pointing that out, I shall fix it for 2 bytes... just writing an explanation. \$\endgroup\$ Jul 26, 2017 at 22:53
  • \$\begingroup\$ done, and make that 1 byte. \$\endgroup\$ Jul 26, 2017 at 23:24
  • \$\begingroup\$ Note: The past tense for "hang" when it comes to people is "hanged", not "hung". Just a nitpick so have +1 for compensation :) \$\endgroup\$
    – hyper-neutrino
    Jul 27, 2017 at 0:25
  • \$\begingroup\$ @ΗγρεŗN̛ευτŗιͷo Heh, I had hung in one place and hanged in another and changed the latter. (I also said "fully", as if the incomplete person had not been completely hanged too). \$\endgroup\$ Jul 27, 2017 at 0:36
3
\$\begingroup\$

Japt v2, 94 91 83 81 bytes

-3 bytes from some ideas from @ETHproductions' approach to this.
-8 bytes by using multiline string rotation.
-2 bytes by using v2.

["+|||||
-
-
-  35
+|01
   24
"r\d_¨VkU l ?S:"O|/\\/\\"gZÃz '=³³¡VøX ?X:'_øVkU]·

Takes both word inputs as arrays of characters, with the guessing word first and guessed letters second. Incorrect letters are shown separated by ,s. When there are no incorrect letters, the last line is blank (meaning output contains an extra trailing newline).

Try it online!

Explanation

Implicit: U and V are input char arrays.

["..."

Start an array and push the hanging man format string, rotated left 90°.

r\d_

Replace (r) every digit (\d) with the following function:

¨VkU l ?S:"O|/\\/\\"gZÃ

If the digit is >= (¨) the amount of wrong guesses (VkU l), a space (S), otherwise, get the appropriate body part for that digit ("..."gZ).

z '=³³

Rotate the hanging man right 90° and push = repeated 3*3 (³³) times to the array.

¡VøX ?X:'_Ã

Push the word-to-guess, with letters mapped (¡) to either themself (X) if contained in V (VøX), or _ if not, and joined with spaces (¸), to the array.

VkU]·

Push the guessed-letters, with the letters in the word-to-guess removed (k), to the output array. Close the array and join with newlines (·).

Rotation visualized:

+|||||      +---+
-           |   |
-      ->   0   |
-  35      213  |
+|01       4 5  |
   24             
\$\endgroup\$
2
  • \$\begingroup\$ I had something similar: ethproductions.github.io/japt/… (though now I notice I have the middle three segments put in in the wrong order). I see some parts in yours that are shorter than how I did it, maybe our answers can combine to something even shorter. \$\endgroup\$ Jul 30, 2017 at 1:13
  • \$\begingroup\$ @ETHproductions I don't think your idea of incrementing W can work since the body parts don't appear left-to-right/top-to-bottom. I was able to save a few bytes from your version, though. \$\endgroup\$ Jul 30, 2017 at 2:30
2
\$\begingroup\$

05AB1E, 83 bytes

•LO„Ÿ¼Ì‘Šη…ÔÆ#δʒΣ•6B4ÝJ"+ -|="‡²¹SK©Ùg"O/|\/\"s£v5y.;}7ô»„==«5ð:¹D²SKDg'_ׇSðý®Sðý»

Try it online!


The Bitmap:

05AB1E, 18 bytes

•LO„Ÿ¼Ì‘Šη…ÔÆ#δʒΣ• # Push number described below in base-10.

Try it online!

This pushes the following bitmap plan:

1102220
1131113
1151113
1555113
1515113
1111113
4444444

Where the following additional bytes:

05AB1E, 13 bytes

6B            # Convert to base-6.
  4ÝJ         # Push 01234.
     "+ -|="  # Push that string.
            ‡ # Replace numbers with those letters.

Try it online!

Replace the pieces of the bitmap with the appropriate characters, leaving the 5's for replacing the pieces of the hangman later:

  +---+
  |   |
  5   |
 555  |
 5 5  |
      |
=======

The Hanged Man:

Next, we calculate how many times the user guessed wrong by grabbing the letters that are in the second input, but not in the first input:

05AB1E, 6 bytes

²¹SK   # Get wrong guesses.
    ©Ù # Store them, and get unique wrong letters.

Try it online!


Finally, we use a secondary bitmap to substitute in the hanged man, separating by newlines and preparing it for the final print:

05AB1E, 26 bytes

g                           # Get the number of "messups".                       
 "O/|\/\"s£                 # Only that many chars of the hanged "bitmap".
           v5y.;}           # Replace 5's with "bitmap".
                 7ô»        # Split into rows.
                    „==«5ð: # Remove additional 5's.

Try it online!

This results in the first pieces, the only remaining pieces being outputting the two words at the bottom in a diff format...


The Words Below:

Print the first word without the missing guesses:

05AB1E, 15 bytes

¹D²SK          # Word without the missing guesses.
     Dg'_ׇ    # Replace missing guesses with "_".
           Sðý # Join by spaces.

Try it online!


05AB1E, 5 bytes

®     # Print stored missing guesses.
 Sðý  # Separated by spaces.
    » # Print everything in stack with newlines.

Try it online!

Print the calculated missed guesses from earlier we stored in a register.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ I really like the bitmap idea (trying to implement it in my own answer, even), but your answer places the left arm (/) before the body (|). Two wrong letters should result in the head and body pieces showing. Try it online \$\endgroup\$ Jul 30, 2017 at 3:54
1
\$\begingroup\$

Jelly, 86 bytes

3ȷ6Dẋ6Ḍ+“Ȧṇ⁹c’
œ-Lḣ@“Ñæçðøþ‘⁵*$€×“µI,’D¤¤S+¢Dị“+-|/\O ”Us7Y,”=x9¤Y;⁷,œ-ðjɓi@€ị³;”_¤K;⁷

Try it online!

Whew... this was fun. I've never used so many ¤ characters.

How it Works

3ȷ6Dẋ6Ḍ+“Ȧṇ⁹c’ (1) the literal 300000030000003000000300000030003001222100
3ȷ6              - literal 3*10^6 = 3000000
   D             - digits
    ẋ6           - repeat six times
      Ḍ          - return to integer: 300000030000003000000300000030000003000000
       +         - add
        “Ȧṇ⁹c’   - literal 2998222100

œ-Lḣ@“Ñæçðøþ‘⁵*$€×“µI,’D¤¤S+¢Dị“+-|/\O ”Us7Y,”=x9¤Y,œ-;⁷ð,ɓi@€ị³;”_¤K;⁷
œ-Lḣ@“Ñæçðøþ‘⁵*$€×“µI,’D¤¤S - representation of the body parts
œ-L                           - wrong letters length
   ḣ@                         - get that many elements from the start of
                        ¤¤    - the literal:
     “Ñæçðøþ‘                   - [16, 22, 23, 24, 29, 31]
             ⁵*$€               - 10 to the power of each of them
                 ×              - multiplies by
                  “µI,’D        - the list [6, 4, 3, 5, 4, 5]
                          S   - sum
+¢Dị“+-|/\O ”Us7Y,”=x9¤;⁷  - complete the man
+                           - add
 ¢                          - the literal 3000000...1222100 calculated by link 1
  D                         - digits
   ị“+-|/\O ”               - index into the string “+-|/\O ”
             Us7Y           - reverse, split into lines of 7, join by linefeeds
                 ,          - append
                  ”=x9¤;⁷     - the string “=========”
                       ;⁷    - add a newline
,œ-                 - append missed letters:
,                      - append
 œ-                    - set difference
ð,ɓi@€ị³;”_¤K;⁷     - append the blanks        
ð,ɓ                   - append
   i@€ị³;”_¤            - each letter if it is included in guesses, _ otherwise
            K         - join by spaces  
             ;⁷       - add a newline
\$\endgroup\$
1
  • 1
    \$\begingroup\$ This draws the man in the wrong order; the torso should come after the head, before the left arm. \$\endgroup\$
    – Shaggy
    Aug 3, 2017 at 13:50
1
\$\begingroup\$

C#, 305 296 bytes

using System.Linq;w=>g=>{var r=string.Concat(g.Where(c=>!w.Contains(c)));var n=r.Length;return$@"  +---+
  |   |
  {(n>0?"O":" ")}   |
 {(n>2?"/":" ")+(n>1?"|":" ")+(n>3?"\\":" ")}  |
 {(n>4?"/":" ")} {(n>5?"\\":" ")}  |
      |
=========
{string.Join(" ",w.Select(c=>g.Contains(c)?c:'_'))}
"+r;}

Svaed 9 bytes thanks to @raznagul.

Try it online!

Full/Formatted Version:

using System;
using System.Linq;

class P
{
    static void Main()
    {
        Func<string, Func<string, string>> f = w=>g=>
        {
            var r = string.Concat(g.Select(c => !w.Contains(c) ? c + "" : ""));
            var n = r.Length;

            return $@"  +---+
  |   |
  {(n > 0 ? "O" : " ")}   |
 {(n > 2 ? "/" : " ") + (n > 1 ? "|" : " ") + (n > 3 ? "\\" : " ")}  |
 {(n > 4 ? "/" : " ")} {(n > 5 ? "\\" : " ")}  |
      |
=========
{string.Join(" ", w.Select(c => g.Contains(c) ? c : '_'))}
" + r;
        };
    
        Console.WriteLine(f("BOAT")("ATG") + "\n");
        Console.WriteLine(f("ZEPPELIN")("") + "\n");
        Console.WriteLine(f("ZEPPELIN")("EATOLINSHR") + "\n");
        Console.WriteLine(f("RHYTHM")("ABCDE") + "\n");
        Console.WriteLine(f("BOAT")("ATOB") + "\n");

        Console.ReadLine();
    }
}

This also works for 314 bytes (could probably be shorter still):

using System.Linq;w=>g=>{var r=string.Concat(g.Select(c=>!w.Contains(c)?c+"":""));var s=$@"  +---+
  |   |
  0   |
 213  |
 4 5  |
      |
=========
{string.Join(" ",w.Select(c=>g.Contains(c)?c:'_'))}
"+r;for(int i=0;i<6;++i)s=s.Replace(i+"",i<r.Length?i<1?"O":i<2?"|":i<3?"/":i<4?"\\":i<5?"/":"\\":" ");return s;}
\$\endgroup\$
1
  • \$\begingroup\$ You can replace g.Select(c=>!w.Contains(c)?c+"":"") with g.Where(c=>!w.Contains(c)). \$\endgroup\$
    – raznagul
    Jul 27, 2017 at 15:13
1
\$\begingroup\$

JavaScript (ES6), 203 196 187 186 185 184 180 177 176 bytes

Takes input as 2 arrays of individual characters in currying syntax.

a=>g=>`  +---+
  |   |
  1   |
 324  |
 5 6  |
      |
=========
${a.map(x=>g[s="includes"](x)?x:"_")}
`.replace(/\d|,/g,m=>" O|/\\/\\"[!!w[~-m]*~~m],w=g.filter(x=>!a[s](x)))+w

Try Play it

o.innerText=(f=
a=>g=>`  +---+
  |   |
  1   |
 324  |
 5 6  |
      |
=========
${a.map(x=>g[s="includes"](x)?x:"_")}
`.replace(/\d|,/g,m=>" O|/\\/\\"[!!w[~-m]*~~m],w=g.filter(x=>!a[s](x)))+w)([...i.value="ZEPPELIN"])([...j.value=""])
oninput=_=>o.innerText=f([...i.value.toUpperCase()])([...j.value.toUpperCase()])
label,input{font-family:sans-serif;font-size:14px;height:20px;line-height:20px;vertical-align:middle}input{margin:0 5px 0 0;width:100px;}
<label for=i>Word: </label><input id=i type=password><label for=j>Guesses: </label><input id=j><pre id=o>

\$\endgroup\$
2
  • \$\begingroup\$ The middle "body" piece should come second and the left arm third, so the numbers part of your string should be 1, 324, 5 6 (see last test case). \$\endgroup\$ Aug 2, 2017 at 20:51
  • \$\begingroup\$ Oops, dunno how I did that. Thanks for pointing it out, @JustinMariner \$\endgroup\$
    – Shaggy
    Aug 2, 2017 at 21:23
1
\$\begingroup\$

Vim, 118 bytes

jYk:s/[^<C-r>0]/_/g
:s/./& /g
Yj:s/[<C-r>0]//g
oO|/\/\ <esc>ka <esc>jv$r dd{P|i | 
 <esc>la 
<esc>xpla
<esc>lxpo   <esc>:0,s/.*/ &  |/
o<esc>9i=<esc>{O  +---+

Try it online!

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

Batch 853 748 736 bytes

Run from the command line with 2 args:

%1 = word, %2 = "doublequoted,delimited,list,of,letters"

edit: requires Windows 10 / Virtual terminal support

Echo off&cls
Set "$=Set "
%$%O=Echo(&%$%F=For /L %%i in (&%$%P=^<nul Set/P &%$%"C=|findstr "
%f:L=f%'%O%prompt $E^|cmd')do %$%\=%%i[
%$%n=^


Setlocal EnableDelayedExpansion
%F:/L=%"e1=3;3HO" "e2=4;3H|" "e3=4;2H/" "e4=4;4H\" "e5=5;2H/" "e6=5;4H\" "D= +---+!n!  |   |!n!")Do %$%%%i
%F%1 1 5)Do %$%D=!D!      ^|!n!
%O%!D!=========!n!&If "%~2"=="" Exit /b
%$%W=%~1&%F:/L=%%~2)Do (%$%/A i+=1
%$%G!i!=%%i&%$%G=!G!/ic:"%%i" )
%F%30,-1,0)Do if not "!W:~%%i,1!"=="" If "!#!"=="" %$%"#=%%i"
%O%%\%10;2H&%F%0 1 !#!)Do (%$%/A X=%%i+2
%P%"=%\%10;!X!H."&%O%"!W:~%%i,1!"%C%!G! >nul &&%P%"=%\%1D!W:~%%i,1!")
%P%"=%\%11;2H"&%F%1 1 !i!)Do %O%!W!%C%/ic:"!G%%i!" >nul||(%P%"=!G%%i!"&%$%/A e+=1)
%F%1 1 !e!)Do %P%"=%\%!e%%~i!"
%O%%\%11;1H

How? macros are used for repeated commands

  • Set Variable assignment %$%
  • For /L %%i in ( loops %F%
    • Substring modification is used to recycle the macro as for /f (%F:L=f%) or basic for loops (%F:L=%)
  • Echo( (output type 1) %O%
  • < Nul Set /P (output type 2) %P%
  • Findstr (String comparison used in testing guesses against letters in word) %C%

The remarked ungolfed version:

@Echo off
 cls

:# define VT escape character 0x027
 For /f %%i in ('Echo(prompt $E^|cmd')do Set ESC=%%i[

:# define linefeed. empty lines required. must be expanded with delayed expansion
(Set \n=^


%= ABOVE EMPTY LINES REQUIRED =%)
:# enable environment to allow use of linefeed; modification of variables during code blocks and parsing of nested variables to emulate arrays
Setlocal EnableDelayedExpansion

:# define array of bodypart location and character representation 'incorrect.#'; define top 2 lines of Gallows
 For %%i in ("incorrect.1=3;3HO" "incorrect.2=4;3H|" "incorrect.3=4;2H/" "incorrect.4=4;4H\" "incorrect.5=5;2H/" "incorrect.6=5;4H\" "Gallows= +---+!\n!  |   |!\n!")Do Set %%i

:# define and output the remaining elements of the Gallows
 For /L %%i in (1 1 5)Do Set "Gallows=!Gallows!      |!\n!"
 Echo(!Gallows!=========!\n!

:# Exit script if second argument empty [ no letters guessed ]
 If "%~2"=="" Exit /b

:# assign word variable to facilitate substring assessment of word
 Set "Word=%~1"
 For %%i in (%~2)Do (                              %= For each delimited letter in argument =%
  Set /A "Guess.index+=1"                            %= Increment count                     =%
  Set "Guess.letter!Guess.index!=%%i"                %= Assign letter to Guess.letter array =%
  Set "Guess.letters=!Guess.letters!/ic:"%%i" "      %= Build list of findstr search values =%
 )

:# Calculate word string length [ 0 indexed ]
 For /L %%i in (30,-1,0)Do if not "!Word:~%%i,1!"=="" If "!Word.Length!"=="" Set "Word.Length=%%i"

:# move cursor to line 10 column 2 in advance of correct guess result output
 Echo(%ESC%10;2H

 For /L %%i in (0 1 !Word.Length!)Do (                   %= For each character in word                       =%
  Set /A "Xpos=%%i+2"                                    %= Assign X position offset for '.' output          =%
  <nul Set/P "=%ESC%10;!Xpos!H."                         %= Output '.' denoting unguessed letter spaces      =%
  Echo("!Word:~%%i,1!"| findstr !Guess.letters! >nul &&( %= Test letter in word against guessed letters list =%
   <nul Set/P "=%ESC%1D!Word:~%%i,1!"                    %= On match shift cursor left; overwrite unguessed marker '.' with matched letter =%
  )
 )

:# move cursor to line 11 column 2 in advance of incorrect guess result output
 <nul Set/P "=%ESC%11;2H"

 For /L %%i in (1 1 !Guess.index!)Do (                %= For each guessed letter                         =%
  Echo(!Word!|findstr /ic:"!Guess.letter%%i!" >nul||( %= Test index of guess array for a match in word   =%
   <nul Set/P "=!Guess.letter%%i!"                    %= On NO match output incorrectly guessed letter - =%
   Set /A "incorrect.guess.count+=1"                  %= and increment incorrect.guess.count             =%
  )
 )

:# For each index in incorrect.guess.count output incorrect.# array value - [ Y;Xcharacter ]
 For /L %%i in (1 1 !incorrect.guess.count!)Do <nul Set/P "=%ESC%!incorrect.%%~i!"
 Echo(%ESC%11;1H
``
\$\endgroup\$
0
\$\begingroup\$

Scala, 392 389 bytes

This might still be heavily golfable.

This is inside a function taking s and t as parameters, with s the word to guess and t the string containing already tried letters.

var f=s.map(x=>if(t contains x)x else"_") mkString " "
var o="""  +---+
  |   |
  0   |
 213  |
 4 5  |
      |
=========
"""
var c=0
var g=t.filter(x=>if(s contains x){false}else{c match{case 0=>o=o.replace("0","o")
case 1=>o=o.replace("1","|")
case y if y==2|y==5=>o=o.replace(y+"","\\")
case y if y==3|y==4=>o=o.replace(y+"","/")
case _=>()}
c+=1
true})
o.replaceAll("\\d"," ")+f+"\n"+g

EDIT:
-1 byte: t.contains(x) -> t contains x
-1 byte: s.contains(x) -> s contains x
-1 byte: .mkString(" ") -> mkString " "

Try it online!

\$\endgroup\$
0
\$\begingroup\$

PHP 7, 246 bytes

for($t="  +---+
  |   |
  1   |
 324  |
 5 6  |
      |
=========
";$c=($w=$argv[1])[$i++];)$t.=strstr($g=$argv[2],$c)?"$c ":"_ ";for($t.="
";$c=$g[$k++];)strstr($w,$c)?:$t.=$c.!++$n." ";for(;$p++<6;)$t=strtr($t,$p," O|/\/\\"[$p>$n?0:$p]);echo$t;

takes input from command line arguments. Run with -nr or try it online.

for($t="  +---+\n  |   |\n  1   |\n 324  |\n 5 6  |\n      |\n=========\n";
    $c=($w=$argv[1])[$i++]; # 1. loop $c through word
)
    $t.=strstr($g=$argv[2],$c)  # if guessed,
        ?"$c ":"_ ";                # then append letter, else append underscore
for($t.="\n";$c=$g[$k++];)  # 2. loop through guesses
    strstr($w,$c)?:             # if not in word
        $t.=$c.!++$n." ";           # add to output, increment $n
for(;$p++<6;)               # 3. loop through possible false guesses
    $t=strtr($t,$p," O|/\/\\"[  # replace digit:
        $p>$n                   # if above no. of wrong guesses
            ?0:$p                   # then with space, else with hangman character
    ]);
echo$t;                     # 4. print
\$\endgroup\$

Your Answer

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

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