python-3.xprogram-flow

The concise 'how many beers' issue?


Where I'm at

I'm trying to figure out how many beers I can buy with 10 RMB after recycling every bottle I get. It's obvious to me that I'm doing something wrong, procedurally, but it's not occurring to me what that is. I'm currently reading "How To Think Like a Computer Scientist: Think Python" on chapter 9. I feel like this should be an easy program for me, but I'm not sure how to loop in the recycling portion of the app. What would be the most concise way to rinse and repeat beer purchases?

The question

Basically, one beer costs 2 RMB. 2 bins gets 1 RMB. 4 caps gets 1 RMB. I'm starting out with 10 RMB. How many beers can I buy (recycling all the bins and caps)?

#5 bottles 5 caps 
#= 3 rmb + 1 caps 1 bottles
#6th bottle bought 
#= 2rmb + 2 caps
#7th bottle bought 
#= 0rmb + 3 caps 1 bottles.

import math

def countbeers(rmb):
    beers = 0;
    caps = 0;
    bins = 0;
    bcost = 2;

    for i in range (0,rmb):
        beers += 1/2

    for i in range (0,math.floor(beers)):
        caps += 1
        bins += 1
        rmb = rmb - bcost

    for i in range (0,caps):
        rmb += 1/4

    for i in range (0,bins):
        rmb += 1/2

    #  if rmb > 2  what goes here, trying to loop back through

    return beers

print(countbeers(10))

Second attempt

#5 bottles 5 caps 
#= 3 wallet + 1 caps 1 bottles
#6th bottle bought 
#= 2wallet + 2 caps
#7th bottle bought 
#= 0wallet + 3 caps 1 bottles.

import math

global beers
global caps
global bins
global bcost

beers = 0
caps = 0
bins = 0
bcost = 2

def buybeers(wallet):
    beers = 0
    for i in range (0,wallet):
        beers += 1/2
        wallet -= 2
    return beers

def drinkbeers(beers):
    for i in range (0,math.floor(beers)):
        caps += 1
        bins += 1
        wallet = wallet - bcost
    return wallet, caps, bins

def recycle(caps, bins):
    for i in range (0,caps):
        wallet += 1/4

    for i in range (0,bins):
        wallet += 1/2

    return wallet

def maxbeers(wallet):
    if wallet > 2:
        buybeers(wallet)

    if math.floor(beers) > 1:
        drinkbeers(beers)

    if caps > 4 | bins > 2:
        recycle(caps, bins)
        return wallet

wallet = int(input("How many wallet do you have?"))

maxbeers(wallet)
if wallet >= 2:
    maxbeers(wallet)
elif wallet < 2: 
    print(beers)

Solution

  • Your main problem is that you are not looping. Every beer you bought from rmb gives you one more bottle, and one more cap. This new bottle and cap might be enough to earn you another rmb, which might be enough for another beer. Your implementation handles this to a limited extent, since you call maxbeers multiple times, but it will not give the correct answer if you give it a truckload of beers, i.e. 25656 bottles.

    If you know the number of rmb you have, you can do the calculation by hand on paper and write this:

    def maxbeers(rmb):
        return 7  # totally correct, I promise. Checked this by hand.
    

    but that's no fun. What if rmb is 25656?

    Assuming we can exchange:

    2 bottles -> 1 rmb
    4 caps -> 1 rmb
    2 rmb -> 1 beer + 1 cap + 1 bottle
    

    we calculate it like this, through simulation:

    def q(rmb):
        beers = 0
        caps = 0
        bottles = 0
        while rmb > 0:
            # buy a beer with rmb
            rmb -= 2
            beers += 1
            caps += 1
            bottles += 1
    
            # exchange all caps for rmb
            while caps >= 4:
                rmb += 1
                caps -= 4
    
            # exchange all bottles for rmb
            while bottles >= 2:
                rmb += 1
                bottles -= 2
    
        return beers
    
    for a in range(20):
        print("rmb:", a, "beers:", q(a))
    

    Then we can buy 20525 beers.