$30
Computer Science CS134
Laboratory 2
Computing the Age of the Moon
Objective. To develop a non-trivial script.
This week we'd like you to implement an algorithm to compute the phase of the moon as a Python
script. Like our day-of-the-week algorithm, this algorithm is simple enough so you could compute the age
in your head, but complex enough so that you'd be motivated to have it available as a Python function.
Method. We'll be implementing a method for determining the moon's age suitable for mental calculation.
This method is due to the late Princeton mathematician, John Conway.
Let's assume that you have a date, speci ed as a valid year, month, and day. For purposes of practicality,
we'll limit the year to those in the range 1900 to 2099. Let's further assume the month is speci ed as a
value between 1 and 12 and the day is a value between 1 and 31. This algorithm computes the moon's
age as days since last new moon, a value between 0 and 29. When the age is zero, the moon is new, when
the age is 15, it's full.
Let's see how Conway's algorithm works. The algorithm involves keeping a running sum, rsum.
(We'll consider the date of the Apollo 11 moon landing, July 20, 1969, as a running parenthetical example.)
1. Initialize the sum, rsum, to the sum of the day, the month, and 30. The nal 30 is helpful to avoid
negative modular arithmetic, later. (For the moon landing, rsum = 7+20+30, or 57.)
2. If the two leading digits of the year, the \century digits," are 20, subtract 8 from rsum, otherwise
subtract 4 from rsum. (The example's year is 1969, so rsum becomes 57-4, or 53.)
3. Compute the value of the year within the century, yy, which would be a value between 0 and
99. Then, compute the distance of yy to the closest multiple of 19|lets call this value dist. For
example, 2018 yields -1, but 1999 gives +4. Notice that 2000 gives 0, but the century correction
avoids a discontinuity here. This calculation is challenging to think about. Take your time, and
carefully check your work! (For our example, yy is 69. 69 is more than 57 by 12, so 69 must be 7
below the next multiple. Since -7 has a smaller magnitude than 12, dist is -7.)
4. Notice that the magnitude of dist, |dist| is always one digit 1
. Next we insert a ten's digit to
dist that is the value of |dist| mod 3. Thus 2014, whose distance is -5, will have a nal dist of
-25, 1999 generates 14, and 2000 gives 0. Notice that this part of the computation never changes
during the year: the nal value of dist for 2020 will always be 11. (For the 1969 moon landing, dist
becomes -17 because 7 has a remainder of 1 when divided by 3.)
5. Add dist to rsum and compute the remainder, when divided by 30. (The moon landing has an rsum
remainder of 6, because 53+(-17) is 36.) That's the \age" of the moon!
1
|x| stands for the absolute value of x, which is de ned as x if x ≥ 0 and −x if x < 0. It is handy that Python has an
in-built abs(i) function that computes the absolute value of an int, i.
Here are some examples you might use to verify your calculations:
The Apollo 11 Moon Landing occurred on July 20, 1969. Thus: (7 + 20 + 30 − 4 − 17)mod 30 ≡ 6
Moon Unit Zappa was born September 28, 1967. Think: (9 + 28 + 30 − 4 − 9)mod 30 ≡ 24
Big Bang physicist, Sheldon \Moon Pie" Cooper, turned 21 on February 26, 2001.
He observes: (2 + 26 + 30 − 8 + 11)mod 30 ≡ 1
Tally, Duane's moon-colored dog, was born on August 28, 2017.
She calculates: (8 + 28 + 30 − 8 − 22)mod 30 ≡ 6
This week’s tasks. Clone the starter repository for this week's lab into your cs134 directory as you did
last week. Open your terminal application and navigate to your cs134 directory with:
cd ~/cs134
git clone https://evolene.cs.williams.edu/cs134-labs/22xyz3/lab02.git lab02
Your CS username replaces 22xyz3. The clone command will follow this pattern each week.
1. Write, in a le called phase.py, a function, moonAge(month,day,year), that computes the age of
the moon associated with the date speci ed by month, day, and year.
2. Use this function, main, to prompt for a date and report the result of the moonAge function:
def main():
"""A method that prompts for a date and prints the moon's age."""
month = int(input("Month? "))
day = int(input("Day? "))
year = int(input("Year (yyyy)? "))
age = moonAge(month,day,year)
print("On {}/{}/{}, the moon's age is {}.".format(month, day, year, age))
When your script is complete, you should be able to type:2
$ python3 phase.py
Month? 9
Day? 18
Year (yyyy)? 2020
On 9/18/2020 the moon's age is 0.
You should also be able to test your code interactively with:
$ python3
>>> from phase import moonAge
>>> moonAge(9,18,2020)
0
Be sure to understand the di erence between exercising code in a script and testing functions interactively.
2The symbols like $ and >>> are prompts. Do not type the prompts when using our examples on your machine.
Submitting your work. When you're nished with phase.py, add, commit, and push your les to the
server as you did in Lab 1. Remember that you must certify that your work is your own, by adding your
name to the honorcode.txt le, submitting it along with your work.
You can verify you've committed all the important les with
git status
which should report
nothing to commit, working tree clean
You can verify you've pushed all your work by going to evolene in a browser, logging in, and checking on
the les associated with your lab02 repository.
Comments on Grading. Both functionality and programming style are important when writing code,
just as both the content and the writing style are important when writing an essay. In this lab we will
focus on the correct functionality of moonAge. Stylistically, we expect to see code that uses meaningful
names, has informative comments, formatted nicely, using appropriate Python commands. There is some
subjectivity to what makes good style, but the overarching goal is to make your logic-as-code as easy to
follow as possible. The copy of GradeSheet.txt (in the repository) shows you more precisely what we're
looking for.
Extra credit—One way to dig deeper. Report a textual description of the moon's age:
moon age description
0,1,29 new
2,3,4,5,6 waxing crescent
7,8 rst quarter
9,10,11,12,13 waxing gibbous
14,15,16 full
17,18,19,20,21 waning gibbous
22,23, third quarter
24,25,26,27,28 waning crescent
For example:
$ python3 phase.py
Month? 9
Day? 18
Year (yyyy)? 2020
On 9/18/2020 the moon's age is 0, a new moon.
This can be accomplished with a new function, age2Str, that converts an integer to a string. This function
would be called from main. We expect that it would make use of several if statements. We will give the
most credit for demonstrating an approach that reduces the average number of if conditions age2Str
would execute for any particular moon age.
?