12
\$\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\$
2
  • \$\begingroup\$ What is the solution to sem**actve, BTW? \$\endgroup\$ Commented Jan 25, 2013 at 1:56
  • \$\begingroup\$ @JoeZ. maybe sem***act*ve ==> semelfactive \$\endgroup\$ Commented Nov 2, 2015 at 8:07

8 Answers 8

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\$
2
  • \$\begingroup\$ Nice one (Ruby beating Perl, that's a not a familiar event in Code Golf ;-) \$\endgroup\$ Commented Jan 19, 2012 at 22:51
  • \$\begingroup\$ In my defense I didn't try that hard. Glad Ilmari Karonen had my back. \$\endgroup\$ Commented Feb 15, 2012 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\$
8
  • \$\begingroup\$ No cheating! It's 371 chars according to Notepad++. \$\endgroup\$ Commented Feb 4, 2011 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\$ Commented Feb 4, 2011 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\$ Commented Feb 4, 2011 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\$ Commented Feb 5, 2011 at 15:28
  • 1
    \$\begingroup\$ Can't you almost always replace newlines w/ semicolons or spaces? \$\endgroup\$ Commented Mar 20, 2011 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\$
1
+100
\$\begingroup\$

Python 3.8 (pre-release), 283 bytes

from random import* def f(w,s=0): for i in range(4,13):W=choice([t for t in w if len(t)==i]);C=sample([*range(i)],T:=i//3);print(f'''Level {i-3} ======= '''+''.join(I in C and'*'or c for I,c in enumerate(W)));print(['wrong','correct'][(Z:=input()==W)]+f'\nscore: {(s:=s+Z*10*T)}\n') 

Try it online!

I'm on Windows so it's hard to test. But there is a version here on a different interpreter site that uses a list of words compiled from here. (albeit only about 8000 words).

\$\endgroup\$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.