Now Reading
Lemonade Stand | Presumably Incorrect

Lemonade Stand | Presumably Incorrect

2024-03-13 12:17:36

Introduction

This was a enjoyable nostalgia journey. However it ended up being an try to gather and protect some retro computing historical past as properly… and I additionally realized– or forgot and remembered?– one other fascinating quirk of that programming setting from almost 45 years in the past.

In 1981, I had a good friend down the road who had an Apple II+. Later that yr, my dad and mom employed a tutor for programming classes. I really feel like I owe a lot of the following course of my life to that point with “Mrs. Cathy,” who had a number of computer systems in her dwelling: I keep in mind an Apple II+, a VIC-20, and an IBM PC.

However it wasn’t till 1983 that we bought our own residence pc, an Apple //e. One of many packages that got here with the pc, Lemonade Stand, is proven within the screenshot under.

The sport is fairly easy: every morning, based mostly on the climate forecast for the day, you determine what number of glasses of lemonade and what number of promoting indicators to make, and the way a lot to cost for every glass. These choices and the day’s climate have an effect on demand, you promote some variety of glasses, rinse and repeat.

It’s about as enjoyable because it sounds… however I keep in mind being intrigued by the prospect of “reverse engineering” the sport. The Applesoft BASIC supply code accommodates the system for computing the demand and the ensuing revenue as a perform of the participant’s inputs and the climate. We will, in precept, “resolve” for the inputs that might maximize the anticipated revenue. This submit is motivated by my failed try to do that.

Historical past

All the code mentioned right here, each previous and new, is obtainable on GitHub. Let’s begin with the previous code: lemonade.bas is the Applesoft BASIC supply by Charlie Kellner, from the .dsk picture of my unique 5.25″ diskette. I consider that is the earliest Apple model of the sport– for completeness I’ve additionally included supply extracts of two subsequent launched variations (lemonade_v4.bas and lemonade_v5.bas), however for our objective right here their conduct is similar, with beauty updates to the graphics and sound by Drew Lynch, Bruce Tognazzini, and Jim Gerber.

For comparability, I’ve additionally extracted the supply for selll.bas (as in “promote lemonade”), from the Minnesota Instructional Computing Consortium (MECC, of Oregon Path fame) Elementary Quantity 3 disk A704. Though showing later in 1980, I feel this model is considerably nearer to the precise unique model of the sport written by Bob Jamison in 1973 for the UNIVAC mainframe. That unique 1973 supply appears to be misplaced to the mists of antiquity… however I feel selll.bas retains extra of its parentage than the Kellner model, which eliminated some useful feedback explaining the phrases within the demand perform, mistranslated some variable names and GOTO line numbering leading to unreachable code, and so on.

Maximizing revenue

Now for the brand new code: lemonade_strategy.py implements the profit-maximization described above. It’s pure brute pressure: given the target perform under,

def expected_profit(glasses, indicators, value, value, r1=1, p_storm=0):
    n1 = 54 - 2.4 * value if value < 10 else 3000 / (value * value)
    demand = min(int(r1 * n1 * (2 - math.exp(-0.5 * indicators))), glasses)
    income = demand * value
    expense = glasses * value + indicators * 15
    return ((1 - p_storm) * income - expense, income - expense,
            glasses, indicators, value)

the place r1 and p_storm are capabilities of the climate forecast, we merely consider the anticipated revenue for all possible inputs and discover the utmost, with the wrinkle that the possible area– what number of glasses and indicators we are able to presumably make– additionally relies on our present property:

max(expected_profit(glasses, indicators, value, value, r1, p_storm)
    for glasses in vary(min(1000, property // value) + 1)
    for indicators in vary(min(50, (property - value * glasses) // 15) + 1)
    for value in vary(101))

I ended up on this rabbit gap within the standard approach, after dialogue with a scholar. My goal wasn’t actually to “resolve” this decades-old sport, however simply to provide an express instance of how a lot slower computer systems had been then: this similar brute-force method in Applesoft BASIC, with the Apple //e’s 1 MHz processor, took almost 4 hours to compute optimum technique only for the primary sunny day in Lemonsville. That’s over 200,000 instances slower than the above Python code, which runs in a fraction of a second on my decade-old 2.6 GHz laptop computer– that’s, with a clock pace “solely” 2,600 instances quicker.

Altering the climate

You’ll be able to play an Apple model of the sport in a browser on the Internet Archive, linked from the sport’s Wikipedia web page. I did simply that, with my Python script working alongside to compute optimum technique… and it didn’t work.

The primary day’s climate was “scorching and dry.” With $2.00 and every glass of lemonade costing 2 cents, the optimum technique ought to have been to make 74 glasses, 3 promoting indicators, and cost 12 cents per glass, for an anticipated revenue of $6.95. However after I entered these values within the sport, I solely bought 37 glasses, for a awful $2.51 revenue.

What was happening? It seems that there are various completely different copies of Lemonade Stand on the market, each on the Web Archive in addition to in varied Apple II disk image archives… however the explicit one linked from Wikipedia is exclusive amongst all of those in that it accommodates an necessary modification to the supply code showing in not one of the different copies, highlighted under:

400  REM   WEATHER REPORT
410 SC = RND (1)
420 IF SC < .4 THEN SC = 2: GOTO 460
430 IF SC < .7 THEN SC = 10: GOTO 460
440 SC = 7
460 REM IF D<3 THEN SC=2

(You’ll be able to play the unique unmodified model on the Web Archive here.)

I don’t know the place these modifications got here from. And I consider these are certainly modifications from the unique launch (i.e., not the opposite approach round). However simply these three edits had been sufficient to maintain my optimum technique calculation from producing the right outcome. This was unusual at first look, for the reason that above part of code merely computes the randomly generated climate forecast for the day, which is an enter to the following revenue calculation. Within the above modified model, the climate forecast is sunny (SC=2) 40% of the time, cloudy (SC=10) 30% of the time, and scorching and dry (SC=7) 30% of the time. The unique threshold values are 0.6 and 0.8, similar to possibilities (0.6, 0.2, 0.2) of (sunny, cloudy, scorching and dry).

The REM in line 460 is a “comment” remark, successfully disabling the unique conduct of forcing sunny forecasts for the primary two days (when D=1 and D=2) of the sport. However once more, why ought to this matter? That is all enter to the revenue calculation, which stays similar to the unique, so what’s inflicting the distinction in conduct?

Undeclared variables

See Also

To make it simpler to poke (!) round this downside, I wrote lemonade.py, which is my try at a shot-for-shot remake of the unique lemonade.bas in Python, minus the graphics and sound– that’s, only a canonical mode textual content interface, however an in any other case line-for-line direct translation with similar conduct.

That translation course of was an fascinating train, nearly a logic puzzle, changing the unstructured GOTO-based move management of Applesoft BASIC into structured Python– I used to be stunned on the finish of all of it to seek out that solely a single defined perform and additional momentary Boolean variable had been wanted, regardless of all the GOSUBs.

That translation helped me to know the reason for the completely different conduct I used to be seeing within the unique. The issue is within the following part of code, with the offending traces highlighted:

700  REM   AFTER 2 DAYS THINGS CAN HAPPEN
710 IF D > 2 THEN 2000
...
2000 REM RANDOM EVENTS
2010 IF SC = 10 THEN 2110
2030 IF SC = 7 THEN 2410
...
2410 X4 = 1
2430 PRINT "A HEAT WAVE IS PREDICTED FOR TODAY!"
2440 R1 = 2
2450 GOTO 805

The variable R1 is an enter to the revenue perform. However though the code change in line 460 above permits the primary day’s displayed forecast to be scorching and dry– or anything aside from sunny– line 710 nonetheless prevents really setting R1 to replicate that non-sunny forecast when computing revenue.

The impact is that, for the primary two days, the climate forecast may point out “scorching and dry,” or “cloudy,” and so on., however it’s actually nonetheless sunny for these first two days, similar to the unique model.

All of which ends up in the precise motivation for this submit: after I initially tried to breed the impact of the three modified traces within the Python model, I bought a “NameError: identify 'D' isn't outlined“, as a consequence of commenting out line 460 within the BASIC model above: the variable D isn’t declared or assigned a worth prior to line 460.

Python can’t deal with this… however apparently Applesoft BASIC can. Variables don’t must be declared earlier than use: when evaluating an expression containing a variable not beforehand assigned, the worth of that variable defaults to zero (or the empty string for string variables).

This conduct is definitely relied on in a number of different locations within the sport as properly. I admit that I assume that is new to me– in all of these early days of studying programming, I don’t keep in mind ever being conscious of nor profiting from this “characteristic.” And it’s not a characteristic of the unique Dartmouth BASIC. And I couldn’t discover documentation of it anyplace within the books, manuals, and magazines that I’ve… however I did discover it written down within the unique “Blue Book” Applesoft Reference Guide. From web page 9: “One other necessary reality is that if a variable is encountered in a system earlier than it’s assigned a worth, it’s robotically assigned the worth zero. Zero is then substituted as the worth of the variable within the explicit system.

Source Link

What's Your Reaction?
Excited
0
Happy
0
In Love
0
Not Sure
0
Silly
0
View Comments (0)

Leave a Reply

Your email address will not be published.

2022 Blinking Robots.
WordPress by Doejo

Scroll To Top