A player guesses letters that are part of a word!
If he has not guessed the complete word before making six (6) mistakes, he has lost!
_______
|/ |
| (_)
| \|/ It is a game over!
| |
| / \
|
___|___
⚫ Your Challenge
In a language of your choice, write a program that takes as its input (in some way) the target word (with blanks) and the letters that have been guessed already. It should then output the next letter to be guessed.
For example:
$ echo -n "p...s\npds" | ./guesser
e
You may assume the word to be guessed is an English word and contains only lowercaseASCIIletters.
Provide code and instructions if usage is not obvious. Consider using a tripcode to ease conversation about your entry.
Entries will be judged on GOODITUDE (defined as its win/loss ratio over twenty random games), on SPEED, and on CLEVERNESS.
Your deadline is 23:59:59 on Sunday, May 20th. Results will be posted the following day.
Also this sort of information is best given as two separate entries on the command line.
Name:
Anonymous2012-05-14 14:55
Algorithm: 1. Let I be the (random)th open space in input word 2. Read from file/data provider of 66common99 English words and insert them into a hash map where the hash is the I'th letter of the word 3. Let L be the set of all letters except the ones specified by program argument 4. For every element l in L count the successful matches of every word in entry l of hash map and let the higher count value specify the output letter 5. Return l for higher count value of matches with 66common99 English words
Now implement in C and optimize the matcher function in asm to win challenge
from string import *
import random
from hangman_lib import *
secret_word=get_random_word()
congrats=['Magnificient','Stupendous','That was EXPERT Quality','Marveloso','Fantabulous']
snide=['Don\'t worry 2/10 people fail to beat hangman','It\'s a hard game. It\'s not as \
though you have a list of letters you could guess with.','If that was you ,who just got hung,\
you\'d be a hung man. As in asphixiated']
def word_guessed():
my=[]
for i in secret_word:
if i in letters_guessed: my.append(True)
else: my.append(False)
return all(my)
def print_guessed():
m=[]
for i in secret_word:
if i in letters_guessed:
m.append(i)
else: m.append('-')
print join(m,' ')
##def main():
while True:
print 'You have %d guesses left' % (MAX_GUESSES-mistakes_made)
print_guessed()
print letters_guessed
guess_letter=lower(raw_input('Guess a letter\n'))
if guess_letter=='cheat':
print secret_word
while guess_letter in letters_guessed or guess_letter not in valid:
guess_letter=lower(raw_input('Letter already picked or invalid input.\
Pick something else.\n'))
letters_guessed.append(guess_letter)
if guess_letter not in secret_word:
mistakes_made+=1
print_hangman_image(mistakes_made)
if mistakes_made>=MAX_GUESSES:
print 'Game over.\n'
print 'The word was %s' %(secret_word)
print '%s' %(snide[randomnum(snide)])
break
if word_guessed():
print '%s ! You did it!\n' %(congrats[randomnum(congrats)])
print secret_word
break
print '\nArt created by sk'
Hangman Lib:
def print_hangman_image(mistakes = 6):
"""Prints out a gallows image for hangman. The image printed depends on
the number of mistakes (0-6)."""
import random
def get_random_word():
"""Returns a random word from the file word_list.txt in the same directory"""
input_file = open('word_list.txt','r')
word_list = [word.strip().lower() for word in input_file.readlines() if word.strip().isalpha() and len(word) > 4]
input_file.close()
import Data.List (sortBy)
import Data.List.Split (wordsBy)
import Data.Char (isSpace)
import qualified Data.Map as M
import qualified Data.Text as T
import qualified Data.Text.Read as T
import qualified Data.Text.IO as T
type PList = [(Char, Double)]
type LUT = M.Map String PList
sortPList :: PList -> PList
sortPList = sortBy (\x y -> snd y `compare` snd x)
filterPList :: String -> PList -> PList
filterPList s l = filter (\(x, y) -> not $ x `elem` s) l
splitFreqs :: Int -> [[a]] -> ([a], [[a]])
splitFreqs _ [] = ([], [])
splitFreqs l (x:xs)
| length x == l+1 = (p, x:pp)
| length x == l = if null p then (x, pp) else next
| otherwise = next
where next@(p, pp) = splitFreqs l xs
mkPMap :: [T.Text] -> (String, [Double])
mkPMap (x:xs) = (T.unpack x, case dbls of
Just d -> d
_ -> [])
where dbls = mapM toDbl xs
toDbl :: T.Text -> Maybe Double
toDbl t = case T.double t of
Right (d, t') -> if T.null t' then Just d else Nothing
_ -> Nothing
words' :: String -> [String]
words' s = if last s == '.' then w else init w
where w = wordsBy (== '.') s
findWordProbs :: Int -> LUT -> String -> PList
findWordProbs 0 _ _ = []
findWordProbs m lut s = case f of
Just i -> i
_ -> findWordProbs (l-1) lut s
where l = min (length s) m
f = M.lookup (reverse $ take l $ reverse s) lut
main = do
fc <- T.readFile "freqlist"
w <- getLine
used <- getLine
let (guess, lut, match) = mkFreqLookup fc
w' = words' w
plists = concatMap (findWordProbs match lut) w'
probs = sortPList $ filterPList used plists
next = if null probs
then fst $ head $ filterPList used guess
else fst $ head probs
>>31
It's almost as if considering trade-offs between reading an entire dictionary every time and using one-size-fits-all frequency tables is part of the challenge.
Name:
Anonymous2012-05-15 17:24
i like that vip cat thing. what is it called
Name:
Anonymous2012-05-15 17:33
IT'S CALLED "PLUG AND PLAY DETECTED AN ERROR FAULT EXPCSEXTION! WONT LET U INSTAL WINBLOWS UNLESS U UNPLUG UR EXTERNAL HDD!!!"
PLUG AND PLAY MY ANUS LOL!
Name:
Anonymous2012-05-15 17:40
>>35
oh and i am the proud ofner of a external hdd that makes windows BSOD instantly when I plug it in an USB port, (YES even when autoplay/autorun disabled)
import sys
import random
#two arguments needed
if(len(sys.argv) != 2):
print "Usage: n"
print "n - word to finish guessing"
else:
#get the guess
guess = sys.argv[1]
#to match the word
def match(word):
#get rid of extra whitespace!
word = word.strip()
#if the guess and the word have equal length
if(len(word) == len(guess)):
#for every character in both the guess and the word
for i in range(len(guess)):
#if the guess was made and the guess was incorrect
if(guess[i] != '.' and guess[i] != word[i]):
#no match
return False
#all guesses ok or not made - matches
return True
else:
#no length match - no match
return False
#get all matching words from the word list
l = filter(match, open("words.txt", "r"))
#if we have matching words
if(len(l) != 0):
#get a list of all the un-made guess characters
a = []
for i in range(len(guess)):
if(guess[i] == '.'):
a.append(i)
#pick a random word out of the word list, and then pick one of its random letters that corresponds to a un-made guess - BAD
random.seed()
print l[random.randint(0, len(l) - 1)][a[random.randint(0, len(a) - 1)]]
heres my shitty entry. didn't think much about how to actually pick what word to guess though.....
dictionary should be called words.txt and should be in same directory as this script. dictionary format should just be 1 word (lowercase) per line - used the lower case corncob list for testing http://www.mieliestronk.com/wordlist.html
Name:
Anonymous2012-05-15 20:57
>>37
also, no checking asides from # of cmd line args
:(
Name:
Anonymous2012-05-15 20:59
Code tags exist for a reason.
Name:
Anonymous2012-05-15 21:07
>>39
sorryyyyyyyyy
import sys
import random
#two arguments needed
if(len(sys.argv) != 2):
print "Usage: n"
print "n - word to finish guessing"
else:
#get the guess
guess = sys.argv[1]
#to match the word
def match(word):
#get rid of extra whitespace!
word = word.strip()
#if the guess and the word have equal length
if(len(word) == len(guess)):
#for every character in both the guess and the word
for i in range(len(guess)):
#if the guess was made and the guess was incorrect
if(guess[i] != '.' and guess[i] != word[i]):
#no match
return False
#all guesses ok or not made - matches
return True
else:
#no length match - no match
return False
#get all matching words from the word list
l = filter(match, open("words.txt", "r"))
#if we have matching words
if(len(l) != 0):
#get a list of all the un-made guess characters
a = []
for i in range(len(guess)):
if(guess[i] == '.'):
a.append(i)
#pick a random word out of the word list, and then pick one of its random letters that corresponds to a un-made guess - BAD
random.seed()
print l[random.randint(0, len(l) - 1)][a[random.randint(0, len(a) - 1)]]
>>45
Modern Operating Systems, 3rd edition - Andrew S. Tanenbaum
By reading it, you will learn to hate him. In part due to his pandering to the Uni money-grubbing book market, by inflating every sentence to fill a fucking page; mostly however, because he's stuck in the '90s and refuses to acknowledge that a micro kernel isn't THE ONE TRUE WAY IN 100% OF CASES
Name:
Anonymous2012-05-16 17:19
>>46
actually it is, it's just that he doesn't realizes that C is fucking shit.
$ echo -e "kangar..\nargnk" | ./hangman
hangman: Prelude.maximum: empty list
$ echo -e "p.ncre.s\nepsrcn" | ./hangman
hangman: Prelude.maximum: empty list
May just be the fact that I'm using GHC 6.12.1, though. I don't know enough Haskell anymore to tell.
Name:
Anonymous2012-05-16 20:03
>>37,40
You really need to take guessed letters into account. If the word isn't in your word list, it will guess wrong letters forever instead of eventually working its way to right ones.
>>49
It's a beginner's challenge. Be nice or constructive.
Name:
Anonymous2012-05-17 0:50
>>51
b-b-b-b-bbbbut how can we know what letters were already guessed if we only get the guess as input? >>49
ss-s-s-sorrrry anon-kun, i will do better next time!
Name:
Anonymous2012-05-17 1:10
>>53
OH NO
I DIDN'T READ
ahhhhh
sorry anon-kun. im slow. forgive me!
hangman: freqlist: openFile: does not exist (No such file or directory)
Name:
Anonymous2012-05-17 17:35
>>56
I only know what GHC 7.0 complains about. I could imagine a readFile function that would just return empty if the file didn't exist. But yes, I did write it with GHC 7.0.4 and I honestly don't know enough about haskell to know how to fix it.
Name:
Anonymous2012-05-17 18:01
>>57
I upgraded to GHC 7.4.1 (the most recent version), and it's still doing the same thing as in >>50. Are you sure it works for you?
Name:
Anonymous2012-05-17 18:49
>>58
Just copied it from here and pastebin and it works fine. $ echo -e "p.ncre.s\nepsrcn" | ./hangman
a
Maybe the freqlist file is improperly formatted on your end?
The first non-empty non-comment line is supposed to be the letters a-z with spaces. Followed by a line of 26 fp numbers, followed by a lot of lines like this: a 0.0002835 0.0228302 0.0369041 0.0426290 0.0012216 0.0075739 0.0171385 0.0014659 0.0372661 0.0002353 0.0110124 0.0778259 0.0260757 0.2145354 0.0005459 0.0195213 0.0001749 0.1104770 0.0934290 0.1317960 0.0098029 0.0306574 0.0088799 0.0009562 0.0233701 0.0018701
where the first column is the prefix
Name:
Anonymous2012-05-17 18:53
>>59
I removed the commented and empty lines at the start of the freqlist file, and now it seems to work. I don't know why that should matter if it doesn't on your end, but I guess the important thing is that it works now.
Name:
Anonymous2012-05-17 19:43
>>60
You know what, I bet you're on OSX. I just tried with classic Mac line endings (ie. '\r') and Windows (ie. "\r\n") and got the same error. It's probably getting the '\r' in each line and misinterpreting it as a key character.
Name:
Anonymous2012-05-17 20:01
>>61
Nope, Linux here.
I did wget the file rather than copy/paste it, so I thought I might have gotten bad line endings that way because that's happened before, but apparently not.
new entry. anon-kun, is this suitable?
import sys
validwords = filter(lambda tuplist : len(filter(lambda tup : tup[0] == '.' or tup[0] == tup[1], tuplist)) == len(tuplist), map(lambda word : zip(sys.argv[1], word), filter(lambda word : len(word) == len(sys.argv[1]), map(lambda word : word.strip(), open("words.txt", "r")))))
letters = {}
for word in validwords:
used = []
for guess, letter in word:
if letter in letters:
letters[letter] += 1
else:
letters[letter] = 1
if(len(sys.argv) == 3):
letters = dict((k, v) for k,v in letters.iteritems() if k not in sys.argv[2])
chosen = max(letters.iterkeys(), key=lambda k : letters[k] )
print chosen
sytnax - python <script name> <guess> <guessed letters in a list ie abcde>
use . to indicate unguessed letters
also, this fails if the word isn't in the word list
word list format is just 1 word per line in "words.txt" in the same directory as the script
Name:
Anonymous2012-05-19 16:37
and i forgot to remove used = [] :(((((((((
crap, anon-kun, i always screw up somehow
import sys
validwords = filter(lambda tuplist : len(filter(lambda tup : tup[0] == '.' or tup[0] == tup[1], tuplist)) == len(tuplist), map(lambda word : zip(sys.argv[1], word), filter(lambda word : len(word) == len(sys.argv[1]), map(lambda word : word.strip(), open("words.txt", "r")))))
letters = {}
for word in validwords:
for guess, letter in word:
if letter in letters:
letters[letter] += 1
else:
letters[letter] = 1
if(len(sys.argv) == 3):
letters = dict((k, v) for k,v in letters.iteritems() if k not in sys.argv[2])
chosen = max(letters.iterkeys(), key=lambda k : letters[k] )
print chosen
Name:
Anonymous2012-05-19 21:55
Against random words the best strategy is to maximize your expected chance of winning, but because the game tree grows exponentially you can't brute force every possibility and have to use a heuristic. ``Most used character'' is a very good heuristic, and ``most entropy in result for this turn'' is also pretty good but harder to compute. How many of the top heuristic choices to examine is a trade-off, but because of diminishing returns I like 2. Perhaps a dynamic choice would be best.
On another note, don't forget to filter out words that have characters that have already been guessed and found not be in the word.
#lang racket/base
;; Usage: racket -t hangman.rkt [word misses]
;; Input is taken from stdin if not given on command line
(define Hang 0)
(define Len 1)
(define File "hangman.txt")
(define Char 0)
(define Handle
(open-input-file File))
(define Word
(read-line Handle)); For time reasons i put one word in here :/
; Thought of making it read lines in a loop and the test being a random number of some sort with the last read line being the word
(while (and (if (= Hang 6)
(begin (display "LOST!\n") ; I wish i had time to make it draw a hanging man but i dont have it
#f))
(not (= (string-length Word)
Len)))
(set! Char
(read-char (current-input-port)))
(if (not (char=? Char #\nl)) ; Filter #\nl(\n) read when pressing enter
(if (not (char=? Char (string-ref Word
Len)))
(set! Hang
(+ 1 Hang))
(begin (set! Len
(+ 1 Len))
(display Char))))
A very simple and primitive implementation
Im made this sort of in a real rush, but i send it in anyway.
I wish i had the time to improve it.
Dont be hard on me since this is my first real scheme program.
It should work, i couldnt test i as much as i should.
Im glad OP took the time to make a programming contest, i missed those.
Name:
Anonymous2012-05-20 20:10
>>79
I hate to break this to you, VIPPER-kun, but that wasn't what was asked.
The winner in the category of GOODITUDE is therefore >>75-san. Congratulations, >>75-san!
And the winner in the category of SPEED is clearly >>30-san. Congratulations, >>30-san!
CLEVERNESS
This category was judged subjectively and capriciously.
None of the entries did anything particularly unexpected, therefore I am going to award this category to >>24-san, for being the shortest while still being quite respectful in the other categories. Congratulations, >>24-san!
Winners may collect their Sußcoins at the front desk. Non-winners are invited to try again next time (and so are winners)!
'-._ ___.....___
`.__ ,-' ,-.`-, THANK YOU
`''-------' ( p ) `._ FOR PLAYING
`-' \
\
. \
\---..,--'
................._ --...--,
`-.._ _.-'
`'-----''
Name:
Anonymous2012-05-21 16:09
All play and no work makes Jack a wise man.
Name:
Anonymous2012-05-22 22:32
Bump, because I don't think anyone saw the results.
Name:
Anonymous2012-05-23 0:29
Now that the contest is over, this is now a general Hangman solver thread. Post your shit code.
(define (char-range a b)
(map integer->char (range (char->integer a) (char->integer b))))
;; evaluates functions on a fixed input.
(define (evaluator x)
(lambda (f)
(f x)))
;; checks if a guess will match a fixed word.
(define (checker word)
(lambda (guess)
(equal? guess word)))
;; collects all indeces in which the letter matches a fixed word.
(define (matching-index-collector word)
(lambda (letter)
(letrec ((loop (lambda (i matches)
(cond ((>= i (string-length word))
matches)
((equal? (string-ref word i) letter)
(loop (+ i 1) (cons i matches)))
(else
(loop (+ i 1) matches))))))
(loop 0 '()))))
;; Sees how many times a letter will match a fixed word.
(define (scorer word)
(lambda (letter)
(letrec ((loop (lambda (i score)
(cond ((>= i (string-length word))
score)
((equal? (string-ref word i) letter)
(loop (+ i 1) (+ score 1)))
(else
(loop (+ i 1) score))))))
(loop 0 0))))
;; Sums the scores for a letter, recieved from a fixed list of scorers.
(define (sum-scorer scorers-list)
(lambda (letter)
(apply + (map (evaluator letter) scorers-list))))
;; evaluates to the element in domain-list that maximizes f.
(define (arg-max domain-list f)
(letrec ((loop (lambda (current-arg-max current-max domain-list)
(if (null? domain-list)
current-arg-max
(let* ((next-arg (car domain-list))
(next-value (f next-arg)))
(if (> next-value current-max)
(loop next-arg next-value (cdr domain-list))
(loop current-arg-max current-max (cdr domain-list))))))))
(loop (car domain-list) (f (car domain-list)) (cdr domain-list))))
(define result (hang-man words-list (matching-index-collector goal-word) (string-length goal-word) alphabet lives-count))
(display result) (newline)
give it:
"goal word"
("dictionary" "list" ...)
lives-count
as input, and it'll:
1. pick an unchosen letter that would yield the largest sum of discoveries in all considerable words left in the dictionary.
2. find all positions where the letter matches the goal word.
3. filter the dictionary with words that match the chosen letter, in the same positions.