1 / 21

Lunar Lander

Lunar Lander. An Example of Interacting Classes. 12-Mar-14. LunarLanderGame.

garren
Download Presentation

Lunar Lander

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Lunar Lander An Example of Interacting Classes 12-Mar-14

  2. LunarLanderGame • This class contains the public static void main(String[] args) method. In this method, you should (1) create a LunarLander object, (2) create an IOFrame object, and (3) send messages to these two objects in order to get the burn rate from the user, tell the lander what to do, find out the lander status, and report the status back to the user. When the lander's altitude is less than or equal to zero, the game ends (one way or the other). • When the game finishes, you should ask the user whether he/she would like to play again. Allow as many games as the user wants before quitting the program.

  3. Additional constraints • At the time this program was assigned, we had: • Classes and methods • Declarations, with and without initialization • Assignment statements • while loops • if and if-else statements • System.out.print and System.out.println • The first version of this program reflects these constraints

  4. public static void main(String[] args) • Here’s the outline of the main method: • public static void main(String[] args) { IOFrame frame = new IOFrame("Lunar Lander"); LunarLander lander; double safeLandingSpeed = 10.0; String again = "yes"; • // Main loop—One game is once through the loop • // Inner loop: Play until the Lander crashes or lands • frame.exit();}

  5. Main loop • Recall that we had a String again = "yes"; declaration • Here’s the main loop: • while ("yes".equals(again)) {// setup lander = new LunarLander(100, 0, 15); frame.clear(); frame.displayLine("Altitude: " + lander.getAltitude()); frame.displayLine("Velocity: " + lander.getVelocity()); frame.displayLine("Fuel left: " + lander.getFuelRemaining()); • // inner loop to play the game • // tell user how game ended • again = frame.getString("Would you like to play again?");}

  6. Inner loop to play game • // inner loop to play one game • while (lander.getAltitude() > 0) { double amount = frame.getDouble("How much fuel should I burn?"); lander.burn(amount); frame.displayLine(""); frame.displayLine("Altitude: " + lander.getAltitude()); frame.displayLine("Velocity: " + lander.getVelocity()); frame.displayLine("Fuel left: " + lander.getFuelRemaining());} • // tell user how game ended • double finalVelocity = lander.getVelocity();if (finalVelocity > safeLandingSpeed) { frame.display("CRASH!");}else { frame.display("Congratulations! A safe landing!");}

  7. LunarLander instance variables • public class LunarLander { double altitude; double velocity; double fuel; final double acceleration = 1.64; final double fuelFactor = 1.0; final double fuelLimit = 2.0; • Where: • acceleration is the Moon’s gravity (meters/second/second) • fuelFactor is how much to reduce the velocity per unit of fuel burned • fuelLimit is the maximum amount of fuel that can be burned at once

  8. The LunarLander constructor • LunarLander(double altitude, double velocity, double fuel) { this.altitude = altitude; this.velocity = velocity; this.fuel = fuel;}

  9. The burn(double) method • This is the method that does all the work of the LunarLander—it recomputes velocity, altitude, and fuel remaining • void burn(double amount) { if (amount > fuel) amount = fuel; if (amount > fuelLimit) amount = fuelLimit; velocity = velocity + acceleration - amount * fuelFactor; fuel = fuel - amount; altitude = altitude - velocity;}

  10. The “getter” methods • double getFuelRemaining() { return fuel;} • double getAltitude() { return altitude;} • double getVelocity() { return velocity;} • That’s all... • ...but the program could be improved

  11. Part II Improving the Lunar Lander program

  12. Refactoring • Refactoring is the process of rearranging and modifying code to improve it (without changing what it does) • The following lines occur twice in the code: • frame.displayLine("Altitude: " + lander.getAltitude());frame.displayLine("Velocity: " + lander.getVelocity());frame.displayLine("Fuel left: " + lander.getFuelRemaining()) • Duplicated code is bad because, if you have to change it, you have to change it everyplace it is used • One way to avoid code repetition is to put the offending code into a method • This particular refactoring is called “Extract Method” • It isn’t necessarily a single-step method • I’ll do it informally

  13. Extract Method I—displayStatus() • I create the following method: • void displayStatus() { frame.displayLine("Altitude: " + lander.getAltitude()); frame.displayLine("Velocity: " + lander.getVelocity()); frame.displayLine("Fuel left: " + lander.getFuelRemaining());} • I call our new method this way (in two places): • displayStatus(); • This gives me syntax errors, because both frame and lander are local variables in main • I have three choices: • Pass in frame and lander as parameters • Make frame and lander instance variables of LunarLanderGame • Make frame and lander class variables of LunarLanderGame

  14. Extract Method II—frame • I only ever want oneIOFrame, so it makes sense to make frame a static variable • I move this lineIOFrame frame = new IOFrame("Lunar Lander");out of the main method, put the word static in front of it, and make it a field of the LunarLanderGame class • public class LunarLanderGame { static IOFrame frame = new IOFrame("Lunar Lander"); • This solves the syntax error for frame

  15. Extract Method III--lander • It seemed to me that each LunarLanderGame should have its own LunarLander • Besides, I have no easy way to “reset” LunarLander for a new game • I therefore decided to make LunarLander an instance variable • Hence, this code: • public class LunarLanderGame { public static void main(String[] args) { LunarLander lander; ... • Becomes this code: • public class LunarLanderGame { LunarLander lander; public static void main(String[] args) { ... • This does not fix the syntax error—I can’t access LunarLander (an instance variable) from within main (a static method)

  16. Extract Method III--run • We have a syntax error because: • Every LunarLanderGame has its own LunarLander • We have noLunarLanderGame objects • Solution: Make a LunarLanderGame object in the main method, and let it do the work • public static void main(String[] args) { LunarLanderGame game = new LunarLanderGame(); game.run();} • void run() { ...use lander here... }

  17. Minor improvements I • It seems unnatural to set the variable again just so we can go through the loop the first time: • String again = "yes";while ("yes".equalsIgnoreCase(again)) { .... again = frame.getString("Would you like to play again?");} • With the do...while loop, we can revise this to: • String again;do { ... again = frame.getString("Would you like to play again?");} while ("yes".equals(again)); • Note: It doesn’t work to define againwithin the loop

  18. Minor improvements II • As written, any response other than “yes” will be taken to mean “no” • This is a real nuisance, especially if you make a typing error • do {...main body of loop... do { again = frame.getString("Would you like to play again?"); } while (!"yes".equals(again) && !"no".equals(again));} while ("yes".equals(again)); • Instead of equals, we can use equalsIgnoreCase • This allows responses such as YES as well as yes

  19. How is this improved? • We’ve moved our status display code into a method, so any corrections or improvements in it need only be done in one place • This also made the main loop smaller, so it’s easier to read and understand • We’ve used the “right” kind of loop to avoid a rather silly-looking initialization • We’ve made the yes/no question much more robust • Come to think of it, this would be a good candidate for a method—getYesOrNo("Would you like to play again?") • The code ends up being eight lines longer (you can’t win them all!)

  20. Summary: Refactoring • Refactoring is the process of rearranging and modifying code to improve it (without changing what it does) • You improve code by making it: • Easier to read and understand • Easier to debug • Easier to modify • “Real” programs are constantly being read and modified • Hence, refactoring is important and useful • Conventional wisdom says: “If it ain’t broke, don’t fix it!” • This is because it’s easy to introduce errors • Refactoring is best done if you have a suite of tests you can run to make sure you didn’t break anything • JUnit is one of the best ways to develop a suite of tests

  21. The End

More Related