This is some code to show you how you might write a simple mars lander simulation in Java. It’s taken from history, way back in the 1970’s - this idea was passed around as some of the very first open source programs.
Meant as an example of a longer program to get you thinking, it’s really not very complicated. The general idea is you have a series of "burns" in a list, and the game (or simulator, if you will) steps through the list applying each burn. If you run out of altitude (or height) while you’re going too fast, you will crash.
The tricky bit would be for you to figure out what burnArray would be used to safely land at a vehicle speed 1 or 2. That could be hard.
import java.util.Random;
import java.util.Scanner;
public class MarsLander {
// Constants
private static final int GRAVITY = 100;
// The rate in which the spaceship descends in free fall (in ten seconds)
private static final String VERSION = "1.2"; // The Version of the program
// Various end-of-game messages
private static final String DEAD = "\nThere were no survivors.\n\n";
private static final String CRASHED = "\nThe Spaceship crashed. Good luck getting back home.\n\n";
private static final String SUCCESS = "\nYou made it! Good job!\n\n";
private static final String EMPTY_FUEL = "\nThere is no fuel left. You're floating around like Wheatley.\n\n";
private static Random random = new Random();
public static int randomHeight() {
int max = 20000;
int min = 10000;
int r = random.nextInt(max - min) + min;
return (r % 15000 + 4000);
}
public static String gameHeader() {
StringBuilder s = new StringBuilder();
s.append("\nMars Lander - Version ").append(VERSION).append("\n");
s.append("This is a computer simulation of an Apollo mars landing capsule.\n");
s.append("The on-board computer has failed so you have to land the capsule manually.\n");
s.append("Set burn rate of retro rockets to any value between 0 (free fall) and 200\n");
s.append("(maximum burn) kilo per second. Set burn rate every 10 seconds.\n");
s.append("You must land at a speed of 2 or 1. Good Luck!\n\n");
return s.toString();
}
public static String getHeader() {
StringBuilder s = new StringBuilder();
s.append("\nTime\t");
s.append("Speed\t\t");
s.append("Fuel\t\t");
s.append("Height\t\t");
s.append("Burn\n");
return s.toString();
}
public static String displayStatus(int time, int speed, int fuel, int height, int burn) {
StringBuilder s = new StringBuilder();
s.append(time).append("\t");
s.append(speed).append(" mps\t\t");
s.append(fuel).append(" kilos\t\t");
s.append(height).append(" meters\t\t");
s.append(burn).append("\n");
return s.toString();
}
public static class LanderStatus {
public int time;
public int speed;
public int fuel;
public int height;
public boolean isAlive;
public boolean hasLanded;
public String message;
public LanderStatus(int time, int speed, int fuel, int height) {
this.time = time;
this.speed = speed;
this.fuel = fuel;
this.height = height;
this.isAlive = true;
this.hasLanded = false;
this.message = "";
}
}
public static LanderStatus updateLander(LanderStatus status, int burn) {
// Update time
status.time += 10;
// Check if we have enough fuel for this burn
if (burn > status.fuel) {
burn = status.fuel; // Use all remaining fuel
}
// Update fuel
status.fuel -= burn;
// Calculate new speed (burn reduces speed, gravity increases it)
status.speed = status.speed + GRAVITY - burn;
// Calculate new height
status.height = status.height - status.speed;
// Check landing conditions
if (status.height <= 0) {
status.hasLanded = true;
if (status.speed <= 2) {
status.message = SUCCESS;
status.isAlive = true;
} else if (status.speed <= 10) {
status.message = CRASHED;
status.isAlive = true;
} else {
status.message = DEAD;
status.isAlive = false;
}
}
return status;
}
public static void playGame() {
Scanner scanner = new Scanner(System.in);
// Initialize game state
LanderStatus lander = new LanderStatus(0, 1000, 8000, randomHeight());
System.out.println(gameHeader());
System.out.println(getHeader());
// Game loop
while (!lander.hasLanded && lander.height > 0) {
System.out.print(displayStatus(lander.time, lander.speed, lander.fuel, lander.height, 0));
// Get burn rate from user
System.out.print("Burn rate (0-200): ");
int burn = 0;
try {
burn = Integer.parseInt(scanner.nextLine());
if (burn < 0) burn = 0;
if (burn > 200) burn = 200;
} catch (NumberFormatException e) {
System.out.println("Invalid input, using 0");
burn = 0;
}
// Update lander
lander = updateLander(lander, burn);
// Check for out of fuel
if (lander.fuel <= 0 && !lander.hasLanded) {
System.out.println(EMPTY_FUEL);
break;
}
}
// Display final status
if (lander.hasLanded) {
System.out.print(displayStatus(lander.time, lander.speed, lander.fuel, 0, 0));
System.out.println(lander.message);
}
scanner.close();
}
// Example of automated landing with predefined burns
public static void automatedLanding() {
// Example burn sequence - you'll need to experiment to find good values!
// Each number represents fuel burn rate for 10 seconds
// 0 = free fall, 200 = maximum burn
int[] burnArray = {0, 0, 0, 50, 50, 50, 100, 100, 150, 150, 200, 200};
LanderStatus lander = new LanderStatus(0, 1000, 8000, 15000);
System.out.println("=== Automated Landing Simulation ===");
System.out.println(getHeader());
int burnIndex = 0;
while (!lander.hasLanded && lander.height > 0 && burnIndex < burnArray.length) {
int burn = burnArray[burnIndex];
System.out.print(displayStatus(lander.time, lander.speed, lander.fuel, lander.height, burn));
lander = updateLander(lander, burn);
burnIndex++;
if (lander.fuel <= 0 && !lander.hasLanded) {
System.out.println(EMPTY_FUEL);
break;
}
}
if (lander.hasLanded) {
System.out.print(displayStatus(lander.time, lander.speed, lander.fuel, 0, 0));
System.out.println(lander.message);
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Choose mode:");
System.out.println("1. Interactive game");
System.out.println("2. Automated landing demo");
System.out.print("Enter choice (1 or 2): ");
try {
int choice = Integer.parseInt(scanner.nextLine());
if (choice == 1) {
playGame();
} else if (choice == 2) {
automatedLanding();
} else {
System.out.println("Invalid choice, running interactive game");
playGame();
}
} catch (NumberFormatException e) {
System.out.println("Invalid input, running interactive game");
playGame();
}
}
}To run this Mars Lander simulation:
-
Copy the code into a file called
MarsLander.java -
Compile it with:
javac MarsLander.java -
Run it with:
java MarsLander
Or, you can experiment with individual methods in jshell:
jshell> // Copy the static methods into jshell and try them out
jshell> int height = randomHeight();
jshell> System.out.println("Random starting height: " + height);
jshell> System.out.println(gameHeader());This program demonstrates several important Java concepts:
-
Classes and Objects: The
LanderStatusclass encapsulates the lander’s state -
Static Methods: Game logic is organized into reusable static methods
-
Constants: Using
final staticfor values that don’t change -
StringBuilder: Efficient string building for output formatting
-
Scanner: Reading user input from the console
-
Arrays: Storing predefined burn sequences
-
Control Flow: Loops and conditional statements for game logic
-
Exception Handling: Try-catch blocks for robust input handling
The challenge is to find the right sequence of burns to land safely. A speed of 1-2 meters per second is a safe landing, while anything over 10 will likely be fatal!
Try creating your own burn sequences and see if you can perfect the landing.