Lunar Lander Programming Challenge

To commemorate the 50th anniversary of the Apollo 11 moon mission and as part of our “Universe of Stories” Summer Reading Program, Ilsley Public Library invites you to write a lunar lander computer simulation in the Python programming language and submit your program for a chance to win a gift certificate from the Vermont Book Shop.  Your program will simulate the controlled descent of the lunar lander and model both a successful and a crash landing, keeping track of the lander’s current altitude, speed and fuel.[i]

The challenge has 2 parts. Complete both parts and receive 2 raffle tickets for a chance to win 1 of 2 $25 dollar gift certificates from the Vermont Book Shop. All entries must be received by August 27. Successful submissions will earn the entrants raffle tickets that we will enter in  a drawing on August 30th. Please send your program as email attachments to info@ilsleypubliclibrary.org with your name and contact information as a comment in each script file with the email subject heading “Ilsley Lunar Lander Challenge”. Only one submission per person is permitted.

Getting Started in Python

If you are new to Python, first get a basic installation of Python and a programming IDE. Thonny is one such programming environment and comes with Python as part of the installation.

Tutorials in the Python language can be found at Python.org.

Part (1):

Write a module called LunarLander.py that defines a class LunarLander and includes the methods listed below. To keep things simple, we will use simple ints for all calculations and updates will occur once every second.  In the lunar landing simulation, the user will have the option to request thrust from the lander’s engines.  For each thrust request that is made, a certain amount of fuel will be expended to generate a certain negative acceleration.  If the user makes more than one thrust request in a given second, then you apply the appropriate number of fuel units.  For example, if the user makes four thrust requests in a given second, then you burn four times the normal amount of fuel and give the lander four times the negative acceleration of a single thrust.

Methods Description
getAltitude() returns the current altitude in meters
getVelocity() returns the current velocity in meters/second
getFuel() returns the current number of thrust units remaining
reset() resets the lunar lander to the initial situation
thrust() remember to apply one more unit of fuel on the next update (can be called multiple times between updates)
tick() called once every second, should update the simulation variables appropriately, applying whatever thrust has been requested since the last update
getStatus() Returns the status of the lander—“descending”, “crashed”, “landed”
_init_() Class constructor for LunarLander. It should reset your lander to beginning variables.
printState() if the status is “descending”, print out the altitude, velocity, and fuel remaining. If the status is “landed”, print “landed”. If the status is “crashed”, print “crashed at” along with velocity and units of fuel remaining.

 

Constants:
The following constants should be used in the LunarLander.py module  :

INITIAL_VELOCITY = 40   # meters/second
INITIAL_ALTITUDE = 1000 # meters
INITIAL_FUEL     = 25   # thrusts
SAFE_LANDING = 4  # speed at which lander can
# safely land in meters/second
GRAVITY = 2  # gravitational acceleration
# in meters/second/second
THRUST  = 4  # thrust acceleration in
# meters/second/second

Additional notes on specific methods:

reset()
In resetting the simulation, you will need to know what values to use initially for altitude, velocity and fuel.

thrust()
Keep in mind that the thrust() method should not update anything. It should just keep track of how many thrust units have been requested during the current second.

tick()
All updating should be done when method tick() is called.  The method should first recompute the velocity.  Because we are computing once per second, this calculation is rather simple.  You should use the following constants GRAVITY and THRUST for the calculation:

GRAVITY indicates that the Moon’s gravity will increase velocity by 2 meters/second every second of the simulation.  So to account for gravity, you simply add this number to the velocity once every second.  The second constant, THRUST, indicates that each thrust unit will decrease velocity by 4 meters/second.  For example, with one thrust unit, the overall effect is to decrease velocity by 2 (add 2 for gravity, subtract 4 for one thrust unit).  With two thrust units the velocity is decreased by 6 (add 2 for gravity, subtract 8 for two thrust units).  With three thrust units the velocity is decreased by 10 (add 2, subtract 12).  And so on.

Once you have updated the velocity in the tick() method, you should recompute the altitude.  Because we are storing velocities as meters per second, you can simply subtract the velocity from the current altitude.  For example, if the altitude is 900 and the velocity is 54 meters/second, then you would reset the altitude to be 846 meters (900 minus 54) to account for one second of movement at that velocity.  You do not have to make a special case for negative velocities.  If the user has applied so much thrust that the velocity has gone negative, then the new altitude will be higher than the old one because you are subtracting a negative number.

Once you have updated the velocity and altitude in the tick() method, you should reset the fuel by subtracting the number of thrust units requested from the current available fuel.  This is a simple computation because we are expressing the fuel level in terms of thrust units (i.e., one unit is the amount of fuel necessary to produce one thrust unit). Within your tick() method, you will also need to reset the variable that keeps count of thrust in preparation for the next thrust() call.

You have to handle one minor problem in the tick method.  It is possible that the user will request too many thrust units.  For example, suppose the fuel level is at 3 units and the user requests 5 thrust units. You have to limit the user to the number of fuel units available so that the user will never be allowed to use fuel that doesn’t exist.  You would normally accomplish this in your code by using an if or if/else statement.    Within the tick() method, you will also need to update the status of the lander (“descending”, “landed”, or “crashed”) based on the altitude of the lander.

Your task in challenge part (1) is to complete the lunar lander module by defining methods and variables that implement the behavior described above.

Part 2:

Create a module called LunarTester.py to test your LunarLander class. This script will create two instances of the LunarLander class: one for (1) a crash landing and one (2) for a safe landing. For each scenario (1) and (2), your lunar lander will need to execute a series of calls to the tick(), thrust(), and printState() methods that result (1) in a “crashed” lunar and (2) in a “landed” state.

[i] Thanks to Stuart Reges of the University of Washington for the use of his original CS 227 assignment as the basis of this challenge, and to Peter Johnson of Middlebury College for adapting it to the Python language. All errors omissions are the responsibility of the staff of Ilsley Public Library!