# ASCII Hangman in Progress

(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

• the wrong letters must preserve the input order? – Rod Jul 26 '17 at 18:33
• @Rod No, don't need to preserve the order of the incorrect guesses. – AdmBorkBork Jul 26 '17 at 18:35
• Please add a test case where all the letters are correctly guesses and one where all have been guessed – Mr. Xcoder Jul 26 '17 at 18:37
• @Mr.Xcoder I've added test case #5 where the person successfully guessed "BOAT" right away. – AdmBorkBork Jul 26 '17 at 20:49
• 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. – Justin Mariner Jul 30 '17 at 4:35

# Python 2, 215192184 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!

• 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. – Raphaël Côté Jul 27 '17 at 2:06
• hmm, could you link the changes? I only managed to reach 184 bytes – Rod Jul 27 '17 at 11:19
• 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/… – Raphaël Côté Jul 27 '17 at 12:15
• I believe you should be showing the body piece (|) instead of the left arm (/) when there are 2 wrong letters: Try it online – Justin Mariner Jul 30 '17 at 3:58
• "\\/" is equal to "\/". – Jonathan Frech Sep 27 '17 at 17:56

# Charcoal, 8369 68 bytes

Ｆη¿№θι⁰«ι→⊞υι»←⸿Ｆθ«⎇№ηιι_→»←⸿×=⁸↖=←↑⁵←+←³↓+|ＦＬυ≡ι⁰↓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:

Ｆη              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.

Ｆθ«             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.

ＦＬυ             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 \.

• this language...it scares me. – Sergey Grinev Jul 26 '17 at 21:30
• @SergeyGrinev D: why is it so scary – ASCII-only Jul 27 '17 at 0:47
• @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! – Neil Jul 27 '17 at 8:05
• @ASCII-only hehe, it's a great idea for a language, but scripts looks like something Lovecraft would use to summon Cthulhu spell. – Sergey Grinev Jul 27 '17 at 8:27
• @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 – ASCII-only Jul 27 '17 at 10:35

# 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

• nice idea for the "replace" with numbers :) – V. Courtois Jul 26 '17 at 18:29
• @V.Courtois Thanks :) I was going to use translate but that turned out to be longer lol. – HyperNeutrino Jul 26 '17 at 18:29
• 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 :) – Raphaël Côté Jul 27 '17 at 0:06
• @RaphaëlCôté Nice golf. Thanks! – HyperNeutrino Jul 27 '17 at 0:11
• c just became useless. Just use len(y) and save 4 bytes! We rock! – Raphaël Côté Jul 27 '17 at 0:15

# 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
“...’                       - 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:
“...‘         -       literal [36,34,28,26,27,19]
®       -         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

• This fails on the BOAT and ATOB test case. Try it online! – fireflame241 Jul 26 '17 at 22:13
• Ah thanks for pointing that out, I shall fix it for 2 bytes... just writing an explanation. – Jonathan Allan Jul 26 '17 at 22:53
• done, and make that 1 byte. – Jonathan Allan Jul 26 '17 at 23:24
• Note: The past tense for "hang" when it comes to people is "hanged", not "hung". Just a nitpick so have +1 for compensation :) – HyperNeutrino Jul 27 '17 at 0:25
• @Ηγρεŗ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). – Jonathan Allan Jul 27 '17 at 0:36

# Japt v2, 949183 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

• 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. – ETHproductions Jul 30 '17 at 1:13
• @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. – Justin Mariner Jul 30 '17 at 2:30

# 05AB1E, 83 bytes

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


Try it online!

# 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


# 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.


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.

• 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 – Justin Mariner Jul 30 '17 at 3:54

# 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
¢                          - 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 “=========”
,œ-                 - 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

• This draws the man in the wrong order; the torso should come after the head, before the left arm. – Shaggy Aug 3 '17 at 13:50

# 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");

}
}


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;}  • You can replace g.Select(c=>!w.Contains(c)?c+"":"") with g.Where(c=>!w.Contains(c)). – raznagul Jul 27 '17 at 15:13 • @raznagul Thanks! – TheLethalCoder Jul 27 '17 at 15:16 # JavaScript (ES6), 203196187186185184180177 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> • 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). – Justin Mariner Aug 2 '17 at 20:51 • Oops, dunno how I did that. Thanks for pointing it out, @JustinMariner – Shaggy Aug 2 '17 at 21:23 # 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! # 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