Christopher Dicely
3/11/2009 2:39:00 PM
On Wed, Mar 11, 2009 at 6:18 AM, Benjamin Thomas
<benjamin.thomas81@free.fr> wrote:
> Hi, I'm new to Ruby and programming in general.
> I'm coding a little script to train on multiplication tables but
> something's wrong:
>
> If I type 'exit', the function should normally exit, via a return
> statement. But this does not always happen and I really can't understand
> why. I've been scratching my head for a few hours on that so I'm posting
> here hoping somebody will be able to spot my obvious mistake!
>
> I'm trying to apply here the concept of recursion so maybe this is where
> I'm messing up.
>
> Thanks for your input,
> Ben
Your intuition on where the problem is is correct. Note that when
using recursion, each call to the function is a separate "layer", and
calling return only jumps you out of the current layer. So if you are
in the invocation of rand_multi() that you called from the top level,
return will exit rand_multi() back to the top level, but if you are in
an invocation of rand_multi() called from another invocation of
rand_multi, return will return you from the current invocation of
rand_multi() back to the calling invocation.
I hope that's clear enough. If not, you can get an illustration by
changing your rand_multi() method as follows:
def rand_multi(call_depth=0) # <-- changed
puts "entering rand_multi(#{call_depth})" # <-- added
num1 = rand(10)
num2 = rand(10)
got_wrong = false
operation = "#{num1}*#{num2}"
if $tested[operation].nil?
puts "creation!"
$tested[operation] = 0
elsif $tested[operation] > 1
puts "need restart"
rand_multi(call_depth+1) # <-- changed: forces function call again
puts "returning to rand_multi(#{call_depth}" # <-- added
end
puts "iteration #{$tested[operation]}"
print operation, " = "
before = Time.now
time_before = (before.min * 60) + before.sec # in case I go for a
coffee :)
answer = gets.chomp
if answer =~ /exit/
puts "will exit now"
return ##### <-- return statement does not always exit method; why??
######
# exit
elsif answer =~ /[0-9]+/
answer = answer.to_i
else
puts "Please enter numbers only!"
rand_multi()
end
if answer != num1 * num2
print " [0;31m" # terminal colors
puts "inside not equal"
puts "No! Answer was '#{num1*num2}'"
print " [0;m"
sleep(1)
# system "clear"
got_wrong = true
$tested[operation] -= 5 # give negative value
rand_multi(call_depth+1) # <-- changed
puts "returning to rand_multi(#{call_depth}" # <-- added
elsif answer == num1 * num2
after = Time.now
time_after = (after.min * 60) + after.sec
answer_time = time_after - time_before
print " [1;34m"
puts "inside equal"
puts "Yes!, you answered in #{answer_time} seconds"
print " [0;m"
sleep(0.3)
# system "clear"
if got_wrong == false
if answer_time < 3
$tested[operation] += 1 # give positive value
else
$tested[operation] -= 1 # small penalty if answer too
slow
end
end
rand_multi(call_depth+1) # <-- changed
puts "returning to rand_multi(#{call_depth}" # <-- added
end
end