I'm doing a change calculator - a function that takes in the cost of an item and the amount of money given to the cashier, before returning the number of each type of coin to optimally return the minimum coins.
I did it the nice simple way using floor division and modulo functions, but was also curious to stretch my understanding of recursion and defining functions within functions by doing it the following method (print statements for debugging):
def change_calc_2(cost, given): # input in full £xx.xx
coin_vals = [200, 100, 50, 20, 10, 5, 2, 1]
coins = [0] * len(coin_vals)
cost = cost * 100 # pence
given = given * 100
left = given - cost
def _calc(left):
for i, c in enumerate(coin_vals):
print("for loop level:", i)
print("Amount left at start of kernel:", left)
print("Coin val in question:", c)
if left == 0:
return coins # early exit routine
elif c > left:
continue
else:
coins[i] += 1
print("coin added:", c)
left -= c
print("Amount left at end of kernel:", left)
_calc(left)
return coins
#_calc(left)
return _calc(left)
#return coins
print(change_calc_2(17, 20))
Running change_calc_2(x, 20) for x = 18 and x = 19, works fine. The outcomes are [1 0 0 0 0 0 0 0] ( a single £2 coin), and [0 1 0 0 0 0 0 0] (a single £1 coin).
However, when I try x = 17, and expect [1 1 0 0 0 0 0 0], I get [1 2 0 0 0 0 0 0].
The print debugging gives the following:
for loop level: 0
Amount left at start of kernel: 300
Coin val in question: 200
coin added: 200
Amount left at end of kernel: 100 ##### Completion of one round of for loop, as expected
for loop level: 0
Amount left at start of kernel: 100
Coin val in question: 200 ##### Rejects the 200p coin as too big for the amount left
for loop level: 1
Amount left at start of kernel: 100
Coin val in question: 100
coin added: 100 #### Adds the last coin expected, so 100p + 200p in total
Amount left at end of kernel: 0
for loop level: 0
Amount left at start of kernel: 0 ############ <----- Running as expected until here
Coin val in question: 200 ************** <--- Should break just after this point?
for loop level: 2
Amount left at start of kernel: 0
Coin val in question: 50
for loop level: 1
Amount left at start of kernel: 100 ########### <--- Wtf? How has it added on money?
Coin val in question: 100
coin added: 100
Amount left at end of kernel: 0
for loop level: 0
Amount left at start of kernel: 0
Coin val in question: 200
for loop level: 2
Amount left at start of kernel: 0
Coin val in question: 50
[1 2 0 0 0 0 0 0]
I expect, at the marked points in the logs above, the program to have left=0 (which it does), and then hit the if left == 0: return coins , then exit the instance of _calc(). My thoughts are as it returns into the parent instance of _calc(), the parent too will hit the left==0, and return to the _calc() above it and so on.
Obviously my thinking is wrong - any help greatly appreciated! I have a feeling that it is due to me misunderstanding of the return function, and/or misunderstanding the "locality" vs "globality" of the variables