# Build a nine-level word guessing game

## The basics:

You'll need to provide a nine-level word guessing game in the fewest characters possible (in your language of choice).

## The metrics:

• Provide a word-list (one word per line, seperated by a newline) (e.g. /usr/share/dict/words or similar could do). It's fine to pipe a filename or the wordlist itself into your solution.
• Provide 9 levels with incrementing word length (words with 4 characters -> 12 characters):
Level 1:  a random word from the wordlist containing 4 characters
Level 2:  a random word from the wordlist containing 5 characters
...                                                  ...
Level 8:  a random word from the wordlist containing 11 characters
Level 9:  a random word from the wordlist containing 12 characters

• In every level, obfuscate a randomly chosen word from the list (with a specific word length of course) and replace a certain number of characters by the asterisk (*). The number of characters to replace: current_word_length / 3 (round down). Randomize which characters to replace.
• Let the player 'guess' the word (only one try per level), give feedback (correct or wrong) and give points accordingly. When correct, the player gains number_of_obfuscated_characters * 10 points.
• Print the current score at the end of each level.

## The format (& sample I/O):

Make sure you follow the following formatting scheme:

Level 1     # level header
=======     #
g*ek        # obfuscated word
geek        # user input
correct     # guess validation
score: 10   # print score
#
Level 2
=======
l*nux
linux
correct
score: 20

Level 3
=======
ran**m
random
correct
score: 40

...

Level 9
=======
sem***act*ve
semiinactive
wrong
score: 90


## Winner:

Shortest solution (by code character count). Have fun golfing!

• What is the solution to sem**actve, BTW? Jan 25 '13 at 1:56
• @JoeZ. maybe sem***act*ve ==> semelfactive Nov 2 '15 at 8:07

## Perl, 180 chars

@w=<>;for$n(4..12){@x=grep/^.{$n}$/,@w;$_=$w=$x[rand@x];vec($_,rand$n,8)=42while($==$n/3)>y/*//;print"Level @{[$n-3]} =======$_";say<>eq$w?($@+=$=)&& correct:wrong," score:$@0
"}


Ruby beating Perl? That will not do! :-)

Like jsvnm's Ruby solution, but unlike Joel Berger's Perl code, this script takes the filename of a word list as a command line parameter. That is, you should run it like this:

perl -M5.010 guessword.pl /usr/share/dict/words


Here's a de-golfed version:

@w = <>;
for $n (4..12) { @x = grep /^.{$n}$/, @w;$_ = $w =$x[rand@x];
vec($_, rand$n, 8) = 42 while ($= =$n/3) > y/\*//;
print "Level @{[ $n-3 ]}\n=======\n$_";
say <> eq $w ? ($@ += $=) && correct : wrong, "\nscore:$@0\n";
}


The statement vec($_, rand$n, 8) = 42 while ($= =$n/3) > y/*// contains a few interesting tricks. First, 42 is the ASCII code of an asterisk; it turns out that using vec to modify single chars in a string is shorter than doing it with substr. Second, the variable $= takes only integer values, so using it to store the number of hidden letters saves me an int. Finally, y/*// is a short way to count the number of asterisks in a string using the transliteration operator. Edit: Saved 7 chars by using $@ to store the score divided by 10 and appending a zero to it during output (which, come to think of it, would've been shorter than the previous version even if I'd used a normal variable).

s=0
4.upto(12){|n|o=''+w=q.grep(/^#{?.*n}$/).sample [*0..n-1].sample(c=n/3).map{|i|o[i]=?*} puts"Level #{n-3}",?=*7,o puts STDIN.gets==w ?(s+=c;"correct"):"wrong","score: #{s}0",""}  • Nice one (Ruby beating Perl, that's a not a familiar event in Code Golf ;-) Jan 19 '12 at 22:51 • In my defense I didn't try that hard. Glad Ilmari Karonen had my back. Feb 15 '12 at 2:57 # Bash, 350 chars S=0 for L in {4..12} do echo -e Level$(($L-3))\\n======= W=$(grep -E ^.{$L}$ /usr/share/dict/words|shuf|tail -1)
G=$W while [ sed 's/[^*]//g'<<<$G|wc -c -le $(($L/3)) ]
do
P=$(bc<<<$RANDOM*$L/32767) G=$(sed "s/$$.\{P\}$$./\1*/"<<<$G) done echo$G
if [ x$U == x$W ]
then
echo correct
S=$(($S+$L/3*10)) else echo wrong fi echo score:$S
done

• No cheating! It's 371 chars according to Notepad++. Feb 4 '11 at 17:13
• @Nyuszika7H: including 21 \r chars, isn't it? This is for Unix, where a newline is a single linefeed char. Feb 4 '11 at 18:34
• @ninjalj: Yeah, but keep in your mind that not everyone uses the Unix line break format. We have to be fair. meta.codegolf.stackexchange.com/questions/167/… Feb 4 '11 at 19:22
• @Nyuszika7H: If you can use it, then by all means you should in a code golf. If your language has two equivalent ways of doing something and one is shorter, do you use the longer because some people might not know the shorter one? As for line breaks, if you have a languages that requires CRLF, then you're out of luck, but I'm not aware of any such language.
– Joey
Feb 5 '11 at 15:28
• Can't you almost always replace newlines w/ semicolons or spaces?
– user503
Mar 20 '11 at 4:19

# Perl: 266

@ARGV='/usr/share/dict/words';@w=<>;$"='';while($l<9){$o=1+int++$l/3;@s=grep{$l+4==length}@w;@g=split//,$t=$s[rand$#s+1];my%r;$r{rand$#g}++while keys%r<$o;$g[$_]='*'for keys%r;print"Level$l\n=======\n@g";print<>eq$t?do{$p+=$o*10;"Correct"}:"Wrong","\nScore:$p\n"}


or with a little more white space

@ARGV='/usr/share/dict/words';
@w=<>;
$"=''; while($l<9){
$o=1+int++$l/3;
@s=grep{$l+4==length}@w; @g=split//,$t=$s[rand$#s+1];
my%r;
$r{rand$#g}++while keys%r<$o;$g[$_]='*'for keys%r; print"Level$l\n=======\n@g";
print<>eq$t?do{$p+=$o*10;"Correct"}:"Wrong","\nScore:$p\n"
}


and I think with a little work it could get even better!

## R, 363 chars

w=tolower(scan("/usr/share/dict/words",what="c"));l=nchar(w);score=0;for(i in 1:9){mw=sample(w[l==i+3],1);cat("Level",i,"\n=======\n",replace(strsplit(mw,"")[[1]],sample(nchar(mw),floor(nchar(mw)/3)),"*"),"\n");v=scan(what="c",n=1,quiet=T);if(length(v)!=0&&v==mw){score=score+10*floor(nchar(mw)/3);cat("correct\n")} else cat("wrong\n");cat("score:",score,"\n\n")}


# Python 335

I know I'm a bit late to the party, but python's not represented, so I figured what the heck:

import sys
import random
random.shuffle(D)
z=0
for L in range(1,10):
M=L+3;N=M/3;w=[c for c in D if len(c)==M][0];U=list(w)
for i in[random.randint(0,M-1)for i in range(N)]:U[i]='*'
print"\nLevel %d\n=======\n"%L+''.join(U);k=raw_input()==w;z+=[0,N*10][k];print["wrong","correct"][k]+"\nscore:",z


And semi-ungolfed:

import sys
import random
random.shuffle(words)
score=0
for L in range(1,10):
M=L+3
N=M/3
w=[c for c in words if len(c)==M][0]
obfus=list(w)
for i in [random.randint(0,M-1) for i in range(N)]: obfus[i]='*'
obfus=''.join(obfus)
print"\nLevel %d\n=======\n"%L+obfus
correct=raw_input()==w
score+=[0,N*10][correct]
print["wrong","correct"][correct]+"\nscore:",score


# K, 198

Assumes a dictionary d in the current working directory.

{O:{@[x;(-_c%3)?c:#x;:;"*"]}',/W:{1?x@&y=#:'x}[_0:d]'4+!9;i:1+S:0;while[#O;-1"Level ",$i;-1"=======";-1@*O;$[(**W)~0:0;[-1"correct";S+:10*+/"*"=*O];-1"wrong"];-1"score: ",$S;-1"";W:1_W;O:1_O;i+:1]}  Ungolfed: { /W = wordlist; O = obfuscated O:{@[x;(-_c%3)?c:#x;:;"*"]}',/W:{1?x@&y=#:'x}[_0:d]'4+!9; i:1+S:0; while[#O; -1"Level ",$i;
-1"=======";
-1@*O;
$[(**W)~0:0; /Read user input and compare to the first word [-1"correct"; S+:10*+/"*"=*O]; /if correct, increment score -1"wrong"]; -1"score: ",$S;
-1"";
W:1_W;                    /knock one off the top of both word lists
O:1_O;
i+:1]
}