7
\$\begingroup\$

Generate math problems (addition, subtraction, or multiplication) using numbers 0-10. Provide feedback on whether the user was right or wrong and show a score.

Specifics:

  • Must generate addition, subtraction, or multiplication problems
  • Numbers used must be 0-10
  • Each problem must be equally likely
  • If user is correct, must print "correct!" (with the exclamation point)
  • If user is wrong, must print "wrong!" (with the exclamation point)
  • After providing correct or wrong feedback, must show score with these specifications:

    • Starts with "Score:"
    • Shows number correct and then "correct"
    • Pipe (|) separation
    • Shows number wrong and then "wrong"
    • 2 newlines for separation
  • Must repeat forever

For counting characters, the Text Mechanic counter will be used.

Sample session:

1-7=-6
correct!
Score: 1 correct | 0 wrong

9+3=12
correct!
Score: 2 correct | 0 wrong

4*5=20
correct!
Score: 3 correct | 0 wrong

7-8=3
wrong!
Score: 3 correct | 1 wrong

1*1=3
wrong!
Score: 3 correct | 2 wrong

7+6=
\$\endgroup\$
  • 1
    \$\begingroup\$ can we assume there is only one operator per problem? \$\endgroup\$ – ardnew Mar 8 '13 at 2:23

11 Answers 11

6
\$\begingroup\$

Post-mortem update:

Perl 130 bytes

Combining techniques from dan1111's excellent solution with my own, I was able to squeeze one more byte:

@b=qw(Score: 0 correct | 0 wrong);$b[$#x=eval^<>?4:1]++while print"$b[@x]!
@b

"x/./,$_=(0|rand 11).chr(41^2+rand 3).~~rand 11,'='

There's a few things that might not be immediately obvious. If @x is an array, then $#x (the largest index of @x) will be one smaller than the length of @x. In this way, I can use $#x to point to the appropriate counting variable, and the length of @x to the corresponding message in a single assignment, without having to +1. The score string is repeating by /./, which will return 1 if an only if $_ is non-empty.


Perl 131 bytes

Here's my Perl attempt, which is more or less a direct translation of my PHP solution below.

@r=correct,${_^($n=eval^<>?z:r)}++while@z=wrong,print"@$n!
Score: $- @r | $% @z

"x@r,$_=(0|rand 11).chr(41^2+rand 3).~~rand 11,'='

$- and $% are used for counting variables as they default to 0, alleviating the need for a printf, and at the same time allowing me to combine the print statements into one. The score string is not printed the first iteration because @r has not yet been defined, and therefore x@r (repeat by the length of the array @r) repeats the string zero times, resulting in an empty string.

Once again using chr(41^2+rand 3) to generate +*-, as well as a bitwise xor _^ to switch between r- and z%. I would have liked to use a type glob for *n=eval^<>?z:r, saving a byte @$n@n, but unfortunately typed as a string this comes back as either *main::r or *main::z, which isn't very useful.

</bandwagon>


PHP 157 (155) bytes

Just to get a smattering of languages:

<?for($X=$Y=+$x=correct;$y=wrong;)echo$q=rand(0,10).chr(rand(2,4)^41).rand(0,10),'=',eval("\${_&\$n=$q^fgets(STDIN)?y:x}++;"),$$n,"!
Score: $X $x | $Y $y

";

The initial $X=$Y=+ is necessary, because undefined variables print as an empty string, instead of 0. Unfortunate, but still shorter than using a printf. One thing to notice is the 'magic formula' chr(rand(2,4)^41). 2^41 = 43 (+), 3^41 = 42 (*) and 4^41 = 45 (-). chr(rand(3,5)^46) would also work, but in a different order.

This can be made 2 bytes shorter by using a few binary characters:

<?for($‡=$†=+$x=correct;$y=wrong;)echo$q=rand(0,10).chr(rand(2,4)^41).rand(0,10),~Â,eval("\${~\$n=$q^fgets(STDIN)?y:x}++;"),$$n,"!
Score: $‡ $x | $† $y

";

where , and  are characters 134, 135 and 194 respectively.

\$\endgroup\$
  • 1
    \$\begingroup\$ Perl beats APL! Well done! \$\endgroup\$ – tomsmeding Mar 10 '13 at 6:58
  • \$\begingroup\$ +1, I especially like your use of the while loop to get a single print statement. \$\endgroup\$ – user7486 Mar 11 '13 at 12:48
4
\$\begingroup\$

APL 146 145

In index origin zero:

o←'+-×'                          
s←0 0                            
t←'wrong' 'correct'              
l:⍞←(e←(⍕?11),o[?3],(⍕?11)),'=' 
r←(⍎e)=⍎⍞                        
s[r]←s[r]+1                      
(∊t[r]),'!'                      
'Score: ',s[1],t[1],'|',s[0],t[0]
' '                              
' '                              
→l 


10×8=80
correct!
 Score:  1 correct | 0 wrong


2×6=16
wrong!
 Score:  1 correct | 1 wrong


2+5=           
\$\endgroup\$
4
\$\begingroup\$

Perl, 144 characters

@b=qw/+ - * Score: correct 0 | wrong 0/;sub _{print@_;~~rand 11}{_$_=_.$b[rand 3]._,'=';_$b[$x=eval==<>?4:7];$b[$x+1]++;_"!\n@b[3..8]\n\n";redo}

Updated (thanks ardnew)

\$\endgroup\$
  • \$\begingroup\$ very nice. you can save 2 chars by replacing int rand 10 with ~~rand 10 (well technically you should be using ~~rand 11...) \$\endgroup\$ – ardnew Mar 8 '13 at 23:57
3
\$\begingroup\$

Perl 154 chars

$x=correct;$y=wrong;R:$_=join qw|+ - *|[rand 3],map~~rand 11,0,0;print"$_=";$c+=$b=<>==eval;printf"%s!$/Score: %d $x | %d $y$/$/",$b?$x:$y,$c,$.-$c;goto R

with some newlines:

$x=correct;
$y=wrong;
R:
  $_=join qw|+ - *|[rand 3],map~~rand 11,0,0;
  print"$_=";
  $c+=$b=<>==eval;
  printf"%s!$/Score: %d $x | %d $y$/$/",$b?$x:$y,$c,$.-$c;
  goto R
\$\endgroup\$
3
\$\begingroup\$

Python 2, 180 176

from random import*
r=randrange
a='correct'
b='wrong'
c=w=0
while 1:e=`r(11)`+'+-*'[r(3)]+`r(11)`;x=input(e+'=')==eval(e);c+=x;w+=1-x;print(b,a)[x]+'!\nScore:',c,a,'|',w,b+'\n'

That counter says it's only 171 chars, but I've counted new lines since that's what we normally do in code golf.

Thanks to flornquake for some improvements.

Ungolfed:

from random import *
num_correct = num_wrong = 0
while 1:
    expression = str(randrange(11)) + '+-*'[randrange(3)] + str(randrange(11))
    is_correct = input(expression + '=') == eval(expression)
    num_correct += is_correct
    num_wrong += 1 - is_correct
    print ('wrong', 'correct')[is_correct] + '!\nScore:', num_correct, 'correct', '|', num_wrong, 'wrong\n'
\$\endgroup\$
  • \$\begingroup\$ I tried that code in IDLE and nothing happened. EDIT: Never mind, works in a file. +1 \$\endgroup\$ – Doorknob Mar 8 '13 at 2:46
  • \$\begingroup\$ Didn't think of using c+=x;w+=1-x, had c[x]+=1 instead and some string formatting. \$\endgroup\$ – beary605 Mar 8 '13 at 2:58
  • \$\begingroup\$ Any Chance of an un-golfed version? Thanks. \$\endgroup\$ – Ari Porad Jul 22 '14 at 0:11
  • \$\begingroup\$ @AriPorad I've added one. \$\endgroup\$ – grc Jul 22 '14 at 1:19
2
\$\begingroup\$

CJam, 90 bytes

Seems like I'm a little late to this question... as is my language, so per site rules, this answer can't officially be selected as the winner. But I had completed my answer for a recent question that was marked as a duplicate of this question and didn't want to let it go to waste, so I modified it a bit for this question.

{Bmr3mr"+-*"=Bmr]_o'=o~\~li=:R["correct":C"wrong":W?'!N"Score:"SUR+:USCS'|SVR!+:VSWNN]o1}g

Due to the interactive nature of the program, the online interpreter cannot be used. You must use the Java interpreter.

I normally post a lengthy explanation, but the code works in about as straightforward of a manner as you can get. That's not to say that I banged this answer out in all of a couple of minutes, though, as there was a fair amount of time spent searching for and making small optimizations.

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

Javascript 169 chars

Here's a solution that doesn't use the console (does that break the rules?) but works via alert boxes (yeah I know...):

for(c=w=0;r=Math.random;){prompt(x=~~(r()*9+1)+"+-*"[~~(r()*3)]+~~(r()*9+1))==eval(x)?(m="correct",c++):(m="wrong",w++);alert(m+"!\nScore: "+c+" correct | "+w+" wrong")}

The attempts at golfing are quite weak, but this was just for fun right? :)

EDIT: Ungolfed version follows. I expanded variable names and split up the assignment of x into a, op and b. The logic is the same. Bear in mind that ~~(X) == Math.floor(X) for positive X. This is just easier to type.

correct=wrong=0;
rand=Math.random;
while(1){
  a=~~(rand()*9+1);
  op="+-*"[~~(rand()*3)];
  b=~~(rand()*9+1);
  x=a+op+b;
  if(prompt(x)==eval(x)){msg="correct";correct++}
  else{msg="wrong";wrong++}
  alert(msg+"!\nScore: "+c+" correct | "+w+" wrong");
}
\$\endgroup\$
  • \$\begingroup\$ do you have an un-golfed version by chance? Thanks \$\endgroup\$ – Ari Porad Jul 22 '14 at 0:11
  • \$\begingroup\$ @AriPorad See my edit. \$\endgroup\$ – tomsmeding Jul 23 '14 at 8:06
  • 1
    \$\begingroup\$ You can save some chars if you replace the if-else with statement?(msg="correct",correct++):(msg="wrong",wrong++); \$\endgroup\$ – izlin Jul 23 '14 at 10:24
2
\$\begingroup\$

C# - 283 Characters

This is my solution in C# in 283 characters:

var r=new Random();int a=0,b=0,x=0,y=0;var w="";Action C=()=>Console.WriteLine(w);for(;;){x=r.Next(11);y=r.Next(11);int[]R={x+y,x-y,x*y};w=""+x+"+-*"[x%3]+y+"=";C();var f=Console.ReadLine()==""+R[x%3];x=f?a++:b++;w=(f?"correct":"wrong")+"!\nScore:"+a+" correct | "+b+" wrong\n";C();}

With more indentation, it looks like:

var r=new Random();
int a=0,b=0,x=0,y=0;
var w="";
Action C=()=>Console.WriteLine(w);
for(;;){
    x=r.Next(11);y=r.Next(11);
    int[] R={x+y,x-y,x*y};
    w=""+x+"+-*"[x%3]+y+"=";C();
    var f=Console.ReadLine()==""+R[x%3];
    x=f?a++:b++;
    w=(f?"correct":"wrong")+"!\nScore:"+a+" correct | "+b+" wrong\n";C();
}
\$\endgroup\$
2
\$\begingroup\$

K, 155

k:l:0;
while[1;
    1@(s:,/(($2?11),(1?"+-*"))0 2 1),"=";
    -1@*$[(.:s)="I"$0:0;("correct!";l+:1);("wrong!";k+:1)];
    -1"Score: ",($l)," correct | ",($k)," wrong\n\n"
    ]
\$\endgroup\$
1
\$\begingroup\$

Haskell 286

import System.Random
main=0?0
s=show
a°b=s a++b
r=randomRIO
d=r(0,10)
p=putStr
c?w=do a<-d;b<-d;i<-r(0,2);let{(#)=[(+),(-),(*)]!!i;o="+-*"!!i};p(s a++o:b°"=");r<-getLine;let{u=fromEnum$read r/=a#b;d=c+1-u;v=w+u};p(["correct!\n","wrong!\n"]!!u);p("Score: "++d°" correct | "++v°" wrong\n\n");d?v
\$\endgroup\$
0
\$\begingroup\$

VBA - 250

Sub t()
a=0
b=0
While 1
x=Int(Rnd()*11)
y=Int(Rnd()*11)
o=Int(Rnd()*3)
If InputBox(x & Array("+","-","*")(o) & y & "=")=Array(x+y,x-y,x*y)(o) Then r="Correct!":a=a+1 Else r="Wrong!":b=b+1
MsgBox r & vbCr & "Score:" & a & " correct|" & b & " wrong"
Wend
End Sub

Runs until the memory limit for the variables is reached, otherwise it runs 'forever'.

\$\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.