## Hangman wordgame golf

14

4

Inspired by reddit.

Write a program which plays Hangman.

• The program chooses a random word from a list of N words, where N > 2.
• The word list can be provided to the program in any way you choose.
• At each iteration

• Print out the state of the game using underscores for letters not yet discovered:

H _ N _ _ _ N

• Print the number of remaining attempts

10

• Read a letter from stdin, and update the state of the game, subtracting an attempt if they guess an incorrect letter.

A (input)

H A N _ _ A N

10

• Repeat until all letters are guessed or attempts reaches 0
• Use any language
• Fewest number of characters wins.
• Drawing the gallows is not necessary, but will earn you upvotes and kudos.

Can I let each word in the list be the same number of characters? – Peter Olson – 2011-04-23T15:04:41.133

Do the letters in the output have to be separated by spaces? – Lowjacker – 2011-04-23T15:44:09.343

@Peter Of The Corn: you should assume that the word list is arbitrary – drspod – 2011-04-23T16:28:22.993

@Lowjacker: the spaces improve the legibility of consecutive underscores, otherwise it's hard to count how many letters they represent. – drspod – 2011-04-23T16:29:46.817

6

## Ruby 1.9, 134132120117108 107

Word list provided in ARGV. The words and the entered letters must match in case.

r=w=$*.sample t=10 loop{puts [*w.tr(r,?_).chars]*' ',t t>0&&r>''?w[l=STDIN.gets[0]]?r=r.tr(l,''):t-=1:exit}  8 Python 3. from random,sys import * w=choice(*argv) L=set(w) a=10 while L and a: print(" ".join("_"if x in L else x for x in w),a) try:L-=set(input()[0]) except:a-=1  I prefer this one though: longer but nicer. import random w=random.choice(list(open("/usr/dict/words")))[:-1] L=set(w) a=10 while L and a: print(" ".join("_"if x in L else x for x in w),a) try:L.remove(input()[0]) except:a-=1 print w  If I didn't have to print a as well, I could use the * twice: print(*("_"if x in L else x for x in w)) – badp – 2011-04-28T10:28:50.330 8 Darn, I thought it said "fewest number of lines wins." I'm not going to win any fewest-character contests here, but this Common Lisp program is only one line. (let ((words (list "that" "help" "rent" "chair" "octopus" "monitor" "manual" "speakers" "onomatopoeia" "regardless" "irresponsible" "cornerstone"))) (let ((word (nth (random (length words)) words))) (format t "~a~%" (funcall (defun play (word current remaining-attempts) (progn (if (not (find #\_ current)) (return-from play "You win!")) (if (equalp remaining-attempts 0) (return-from play "You lose!")) (format t "~a~%~d~%" current remaining-attempts) (let ((guess (char (read-line) 0)) (index 0) (found nil)) (loop for letter across word do (if (equalp guess letter) (progn (setf (char current index) letter) (setf found t))) (setf index (+ index 1))) (if found (play word current remaining-attempts) (play word current (- remaining-attempts 1)))))) word (map 'string #'(lambda (c) #\_) word) 10))))  1I'm upvoting you because I'm pretty sure you're being intentionally humorous :-) – Dr. Pain – 2011-04-29T19:25:59.937 4 c++ (-headers) struct h{h(char a):b(a){}char operator()(char c,char d){return d!='_'?d:c==b?c:'_';}char b;}; int main(int a,char**b){ srand(time(0));string c=*(b+rand()%(a-1)+1),d(c.size(),'_'),e; char f=10,g; while(f){ cout<<"> ";cin>>g;e=d; transform(c.begin(),c.end(),d.begin(),d.begin(),h(g));if(e==d)--f; cout<<d<<endl<<(int)f<<endl;if(d==c)break; }return 0;}  cat /usr/dict/words | xargs hangman The "> " prompt for input is not necessary for the solution, I just added it in the question to indicate that it was input, as many languages provide a prompt such as this. – drspod – 2011-04-23T16:54:21.873 @drspod You should edit the question to reflect that, then. – Lowjacker – 2011-04-23T19:24:58.700 edited to clarify – drspod – 2011-04-23T22:49:48.007 2 ## Python import random DEFAULT_ATTEMPTS = 10 def print_word(word, uncovered): for c in word: if c not in uncovered: c = '_' print c, print '' def get_letter(): letter = None while letter is None: letter = raw_input('> ') if len(letter) != 1: print 'Letters must be 1 character. Try again.' letter = None return letter if __name__ == '__main__': import sys if len(sys.argv) != 2: sys.exit(1) with open(sys.argv[1], 'r') as f: words = [word.strip() for word in f.readlines() if word.strip()] word = random.choice(words) uncovered = set([' ']) attempts = DEFAULT_ATTEMPTS while attempts > 0 and any(letter not in uncovered for letter in word): print_word(word, uncovered) print attempts letter = get_letter() if letter in uncovered: print 'You have already tried that letter.' elif letter in word: print 'You got it!' else: print 'Wrong!' attempts -= 1 uncovered.add(letter) if attempts == 0: print 'You lose!', else: print 'You win!' print 'The phrase was "%s".' % word  I didn't really try for the fewest characters, just wanted to make it as small as possible without sacrificing anything. @user: You may be interested in George Edison's wonderful user script for this site which puts your code (as copied here by badp) at 1225 characters. – dmckee --- ex-moderator kitten – 2011-04-23T14:36:50.297 I think that's cause I was using tabs and they were converted to spaces here. wc says it's 1034 with tabs. – Sergey G – 2011-04-23T14:43:35.520 @user: Yes. A well known difficulty with python submissions. – dmckee --- ex-moderator kitten – 2011-04-23T14:47:41.540 2 Perl, 112 char. I feel like I can do better - perhaps I'll try again later $_=$ARGV[rand@ARGV];$a=10;while($a&&/[a-z]/){print map/[A-Z]/?$_:'_',split'';$x=<STDIN>;chop$x;s/$x/$x/ig||$a--}  Words are given on the command line, letters typed upper case Down to 107 $_=$ARGV[rand@ARGV];$a=10;while($a&&/[a-z]/){$y=$_;$y=~y/a-z/_/;print$y;$x=<STDIN>;chop$x;s/$x/$x/ig||$a--} – None – 2011-04-23T21:54:04.460

1This doesn't display the number of remaining attempts. – Lowjacker – 2011-04-23T22:27:05.370

2

Clojure

This is 400 bytes gzipped, which is still quite a lot, probably because of how Clojure handles mutable state.

(def m ["will" "work" "for" "food"])
(def w (nth m (rand-int (count m))))
(def *s* (atom (replicate (count w) "_")))
(def *a* (atom 10))

(defn g [s a]
(str (apply str (interpose " " s)) "\n" a))

(if (some (set n) w)
(swap! *s* (fn [s]
(map
(fn [i]
(if (= n (str (nth w i)))
n
(nth s i)))
(range 0 (count s)))))
(swap! *a* dec))

(println (g (deref *s*) (deref *a*)))

(if (and (< 0 (deref *a*)) (some #{"_"} (deref *s*)))


2

C# 370

using System;namespace h{class P{static void Main(string[]a){int c=10,d,l;char y=' ';string w=a[new Random().Next(a.Length)];l=w.Length;char[]x=new char[l];for(d=-1;++d<l;x[d]='-');while(c>0){for(d=-1;++d<l;x[d]=(y==w[d]||x[d]!='-')?w[d]:x[d]);Console.WriteLine(new string(x)+" "+c);if(w==new string(x))return;y=Console.ReadKey(true).KeyChar;if(!w.Contains(y+""))c--;}}}


wordlist as argument

1

# VB.NET

I haven't tried shrinking it yet, but:
First shrinking:
Second shrinking (3759 characters):

Module Hangman
Sub Main()
Dim m As Int32, w = "banana|apple|pear|dog|cat|orange|monkey|programming|hangman".Split("|")(New Random().Next(9)), g = "", e = "", x, c As Char, f As Boolean, r = Sub(z) Console.Write(z), p = Sub(y, h) Console.SetCursorPosition(y, h), a = Sub() Console.Clear(), q = Function() Console.ReadKey(1), d = Sub()
r("       +--------+S       |        |S                |S                |S                |S                |S                |S                |S                |S                |S                |S                |S                |S                |S                |S                |S                |S                |S                |S                |S                |S                |S                |S   ---------------------".Replace("S", vbCrLf))
p(0, 2)
r(String.Join(vbCrLf, "    /------\S    | O   O|S    \  ... /S     ------ S        |   S        |   S        |   S        |   S -------+-------S        |   S        |   S        |   S       / \  S      /   \  S     /     \  S    /       \  ".Split("S").Take(m * 4)))
End Sub
Console.CursorVisible = 0
Do
a()
d()
p(30, 10)
f = 0
For Each x In w
If g.Contains(x) Then
r(x)
Else
r(" ")
f = 1
End If
Console.CursorTop += 1
Console.CursorLeft -= 1
r("_")
Console.CursorTop -= 1
r(" ")
Next
If Not f Then
a()
d()
p(30, 10)
r("You win! Press any key to close.")
q()
End
End If
p(30, 13)
r(e)
Do
c = q().KeyChar
Loop Until Char.IsLetter(c)
If g.Contains(c) Then
e = "You have already guessed that letter."
Else
g &= c
If w.Contains(c) Then
e = "There is a" & If("aehilmnorsx".Contains(c), "n", "") & " """ & c & """ in the word."
Else
e = "There is no """ & c & """ in the word. Try again."
m += 1
End If
End If
Loop Until m = 4
a()
d()
p(30, 10)
r("You lose! Press any key to close.")
q()
End Sub
End Module


Is all the indentation really required? – Lowjacker – 2011-04-24T00:19:49.083

it makes it easier to read, doesn't it? – Nate Koppenhaver – 2011-04-24T00:33:45.617

As in blocks? No, it's not required, but I don't count it as characters. – Ry- – 2011-04-24T02:32:18.450

0

# Powershell, 125 bytes

$w=$h=$args|random|% t*y for($n=10){$w-replace"[$h]",'_'-join' ';$n if(!$h+!$n){break}$n-=($c=Read-Host)-notin$h
$h=$h-ne$c}  Less golfed test script: $f = {

$word=$hidden=$args|random|% toCharArray # let$word and $hidden are a random word chars #$word                                      # uncomment this to cheating
for($n=10){ # forever for with init section$word-replace"[ $hidden]",'_'-join' ' # display the word with hidden letters$n                                      # display $n if(!$hidden+!$n){break} # break loop if hidden array is empty or n equal to 0$n-=($c=Read-Host)-notin$hidden         # input $c from user, decrease$n if $c does not in$hidden array
$hidden=$hidden-ne$c # recreate$hidden array with removed $c } }$words = gc .\wordlist.txt
&$f$words


Output example when the guessing player has lost:

_ _ _ _ _ _ _ _
10
i
_ _ _ _ _ _ _ _
9
e
_ _ e _ _ _ _ e
9
o
o _ e _ _ o _ e
9
a
o _ e _ _ o _ e
8
q
o _ e _ _ o _ e
7
q
o _ e _ _ o _ e
6
q
o _ e _ _ o _ e
5
q
o _ e _ _ o _ e
4
q
o _ e _ _ o _ e
3
q
o _ e _ _ o _ e
2
q
o _ e _ _ o _ e
1
q
o _ e _ _ o _ e
0


Output example when the guessing player has win:

_ _ _ _ _ _ _ _ _ _
10
e
_ _ _ _ e _ _ _ _ _
10
o
_ o _ _ e _ _ _ _ _
10
i
_ o _ _ e _ _ i _ _
10
a
_ o _ _ e _ _ i a _
10
l
_ o _ _ e _ _ i a l
10
c
c o _ _ e _ c i a l
10
m
c o m m e _ c i a l
10
t
c o m m e _ c i a l
9
r
c o m m e r c i a l
9