11
\$\begingroup\$

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!

\$\endgroup\$
  • \$\begingroup\$ What is the solution to sem**actve, BTW? \$\endgroup\$ – Joe Z. Jan 25 '13 at 1:56
  • \$\begingroup\$ @JoeZ. maybe sem***act*ve ==> semelfactive \$\endgroup\$ – dev-masih Nov 2 '15 at 8:07
5
\$\begingroup\$

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

Edit 2: Turns out embedding literal newlines in the output strings saves a char over messing with $,.

\$\endgroup\$
5
\$\begingroup\$

Ruby (188)

takes the filename to read words from as argument.

q=*$<
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",""}
\$\endgroup\$
  • \$\begingroup\$ Nice one (Ruby beating Perl, that's a not a familiar event in Code Golf ;-) \$\endgroup\$ – ChristopheD Jan 19 '12 at 22:51
  • \$\begingroup\$ In my defense I didn't try that hard. Glad Ilmari Karonen had my back. \$\endgroup\$ – Joel Berger Feb 15 '12 at 2:57
3
\$\begingroup\$

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
read U
if [ x$U == x$W ]
then
echo correct
S=$(($S+$L/3*10))
else
echo wrong
fi
echo score: $S
done
\$\endgroup\$
  • \$\begingroup\$ No cheating! It's 371 chars according to Notepad++. \$\endgroup\$ – nyuszika7h Feb 4 '11 at 17:13
  • 6
    \$\begingroup\$ @Nyuszika7H: including 21 \r chars, isn't it? This is for Unix, where a newline is a single linefeed char. \$\endgroup\$ – ninjalj Feb 4 '11 at 18:34
  • \$\begingroup\$ @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/… \$\endgroup\$ – nyuszika7h Feb 4 '11 at 19:22
  • 10
    \$\begingroup\$ @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. \$\endgroup\$ – Joey Feb 5 '11 at 15:28
  • 1
    \$\begingroup\$ Can't you almost always replace newlines w/ semicolons or spaces? \$\endgroup\$ – barrycarter Mar 20 '11 at 4:19
2
\$\begingroup\$

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!

\$\endgroup\$
2
\$\begingroup\$

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")}
\$\endgroup\$
2
\$\begingroup\$

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
D=open(sys.argv[1]).read().split()
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
words = open(sys.argv[1]).read().split()
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
\$\endgroup\$
2
\$\begingroup\$

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]
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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