Arithmetic Drill
December 31, 2010
Children just learning the basic facts of arithmetic need repetitious drill to certify their knowledge, something that a computer does well. Toy stores purvey many brightly-colored plastic boxes that do the job, at a price. Today’s exercise asks you to do the same, minus the plastic box. Consider the following dialog, where the computer’s output is in roman
and the child’s response is in italic
:
4 + 4 = 8
Right!
8 + 3 = 12
Wrong, try again!
8 + 3 = 11
Right!
9 + 4 = 13
Right!
7 + 8 = ?
15
9 + 5 = 14
Right!
8 + 0 = ^Z
Goodbye!
After the drill program presents a problem, the child either enters his answer, asks for help by entering a question mark, or quits by entering an end-of-file. Correct answers are rewarded, incorrect answers cause the problem to be asked again.
Your task is to write a program that drills children on their addition facts. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.
[…] Praxis – Arithmetic Drill By Remco Niemeijer In today’s Programming Praxis exercise, our goal is to write a program that allows children to test their […]
My Haskell solution (see http://bonsaicode.wordpress.com/2010/12/31/programming-praxis-arithmetic-drill/ for a version with comments):
My Python 3 solution:
Here’s a simple ruby version:
My Python solution:
Sorry, only handles keyboard interrupts. This one also handles EOF:
In C:
;; Hum, my comment does not show up (even with refreshes), but the system says I already posted it!
(define (drill)
(call/cc
(lambda(exit)
(let loop ()
(and (call/cc
(lambda (break)
(let ((a (random-integer 10))
(b (random-integer 10)))
(if (or (zero? a) (zero? b))
(break #f))
(map display `(,a ” + ” ,b ” = “))
(let ((v (read)))
(cond
((eof-object? v) (exit ‘bye))
((not (number? v)) (break #f))
((= v (+ a b)) (display ‘yeah!))
(else (display ‘booh)))))))
(newline))
(loop)))))
My ruby version:
Not sure what is meant by handling an end-of-file in the terminal. Just learning Ruby, so probably not the best style.
def quiz (num1=rand(10), num2=rand(10))
while true
print “#{ num1 } + #{ num2 } = ”
answer = STDIN.gets.strip
if answer == “?”
puts “#{ num1 + num2 }”
quiz
elsif answer.to_i == num1 + num2
puts “Right!”
quiz
else
puts “Wrong, try again”
end
end
end
quiz
@Axio: does all that call/cc really bring some benefits or is it just to show some different way it could be done?
Roti: it’s just the way to code it that seemed clear and natural to me. One might argue that call/cc is quite overkill here, as I just use it instead of exceptions to simulate “break” (as in a “while loop”). But it’s just an exit continuation, so this is a quite common pattern that keeps code understandable.
So, whether it is a benefit or not will probably be subjective here.
PHP version
golf score: 305
(require(lib “1.ss” “srfi”))(let p()(let l((n(random 10))(m(random 10)))(printf “~a + ~a = ” n m)(flush-output)(let*((s(read))(z(reduce(lambda(x a)(if(eq?(car x)s)x a))0`((0 “Wrong, try again!”,l,n,m)(,(+ n m) “Right!”,p)(?,(+ n m),p)(^Z “Goodbye!”,void)))))(displayln(cadr z))(apply(caddr z)(cdddr z)))))
C Version:
#include
#include
#include
int createQuestion(int questionType); /*question type decides if the question will be + or -. It returns 0 if answered correct or 1 if wrong.*/
main()
{
int a = 0;
int result = 0;
printf(“\nAnswer the questions. If you get 5 questions wrong the game ends. Try to answer as many as possible.\n”);
printf(“Press 1 for addition problems or 2 for subtraction problems, or 3 for both: “);
scanf(“%d”,&a);
while(result<5){
switch (a)
{
case 1:
result = result +createQuestion(1);
printf("\nresult:%d\n",result);
break;
case 2:
result = result +createQuestion(2);
break;
case 3:
result = result +createQuestion(3);
break;
}//switch
}//while
}//main
int createQuestion(int questionType) {
int int1, int2,input, answer;
srand ( time(NULL) );
int1 = rand() % 256 + 1;
int2 = rand() %256+1;
switch (questionType)
{
case 1:
printf("\n%d+%d= ",int1,int2);
answer = int1+int2;
break;
case 2:
printf("\n%d-%d= ",int1,int2);
answer = int1-int2;
break;
case 3:
if(int1<int2){
printf("\n%d+%d= ",int1,int2);
answer = int1+int2;
}
else{
printf("\n%d-%d= ",int1,int2);
answer = int1 – int2;
}
break;
}
scanf("%d",&input);
printf("\n%d\n",answer);
if(input==answer)
return 0;
else
return 1;
}
I got rid the reduce by using racket’s built in assq function, eliminating the need for srfi/1.
New golf score for my racket scheme version: 238
(let p()(let l((n(random 10))(m(random 10)))(printf”~a + ~a = “n m)(flush-output)(let*((s(read))(z(assq s `((,(+ n m)”Right!”,p)(?,(+ n m),p)(^Z”Goodbye!”,void)(,s”Wrong, try again!”,(lambda()(l n m)))))))(displayln(cadr z))((caddr z)))))
Possible solution REXX