The history

In the 1980s I started to learn to program on my friends zx81 and then on the Commodore VIC20 that I got for my twelfth birthday. It had a 1.02Mhz MOS 6502A processor, 16 colours and a stonking great 3.5K of 5K RAM available! I learnt to program using some of the Usbourne books (scroll down) and one particular game from them has always stuck with me. You may be able to guess that it was called Space Mines. The Head First books are kind of like these but with clip art rather than drawings.

Designed to run on the ZX81 and written in BASIC rather than machine code, Space Mines isn’t particularly complex or sophisticated but I always thought that it had the potential to be turned into something rather good. I’ve just never got around to it before.

This first version sticks fairly closely to the original but I’ve renamed the variables for my sanity and modified the logic due to some minor differences between Java and BASIC from the 1980s.

The initial code

package com.thefifthcontinent.spacemines;

import java.util.InputMismatchException;
import java.util.Random;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {

        Random rand = new Random();
        Scanner input = new Scanner(System.in);

        int year = 2375;
        int turn = 1;

        int mines = rand.nextInt(3) + 5;
        int population = rand.nextInt(60) + 40;
        int money = rand.nextInt(50) + 10;
        money *= population;
        int foodPrice = rand.nextInt(40) + 80;
        int oreProduced = rand.nextInt(40) + 80;
        int oreStored = 0;
        double satisfactionFactor = 1;
        int minePrice = rand.nextInt(2000) + 2000;
        int orePrice = rand.nextInt(12) + 7;

        boolean victory = true;

        do {

            if (satisfactionFactor < 0.5) {
                System.out.println("The people revolt and chuck you out of the airlock");
                victory = false;
                break;
            }

            if ((population / mines) < 10) {
                System.out.println("You've overworked everybody");
                victory = false;
                break;
            }

            if (population < 30) {
                System.out.println("There are not enough people left to run the mines");
                victory = false;
                break;
            }

            System.out.println("Year: " + (year + turn));
            System.out.println("\nPeople: " + population);
            System.out.println("Mines: " + mines);
            System.out.println("Money: " + money + " Quatloos");
            System.out.println("Production: " + oreProduced + "per mine");
            System.out.println("\nSatisfaction factor: " + satisfactionFactor);

            oreStored += oreProduced * mines;

            System.out.println("\nSelling Ore");
            System.out.println("Ore in stock: " + oreStored + " tonnes");
            System.out.println("Ore selling price: " + orePrice + " Quatloos");
            int oreToSell = -1;

            do {
                System.out.print("How much ore to sell: ");
                try {
                    oreToSell = input.nextInt();
                } catch (InputMismatchException ex) {
                    input.nextLine();
                }
            } while(oreToSell < 0 || oreToSell > oreStored);

            oreStored -= oreToSell;
            money += oreToSell * orePrice;

            System.out.println("\nSelling Mines");
            System.out.println("Mines available: " + mines);
            System.out.println("Mine selling price: " + minePrice + " Quatloos");
            int minesToSell = -1;

            do {
                System.out.print("How many mines to sell: ");
                try {
                    minesToSell = input.nextInt();
                } catch (InputMismatchException ex) {
                    input.nextLine();
                }
            } while(minesToSell < 0 || minesToSell > mines);

            mines -= minesToSell;
            money += minesToSell * minePrice;

            System.out.println("\nBuying food");
            System.out.println("\nMoney available: " + money + " Quatloos");
            System.out.println("Food price: " + foodPrice + " Quatloos");
            int foodToBuy = -1;
            int total = 0;

            do {
                System.out.print("How much food to buy: ");
                try {
                    foodToBuy = input.nextInt();
                    total = foodToBuy * foodPrice;
                } catch (InputMismatchException ex) {
                    input.nextLine();
                }
            } while(foodToBuy < 0 || total > money);

            if (foodToBuy / population > 120) {
                satisfactionFactor += 0.1;
            }

            if (foodToBuy / population < 80) {
                satisfactionFactor -= 0.2;
            }

            money -= foodToBuy * foodPrice;

            System.out.println("\nBuying mines");
            System.out.println("\nMoney available: " + money + " Quatloos");
            System.out.println("Mine price: " + minePrice + " Quatloos");
            int minesToBuy = -1;

            do {
                System.out.print("How many mines to buy: ");
                try {
                    minesToBuy = input.nextInt();
                    total = minesToBuy * minePrice;
                } catch (InputMismatchException ex) {
                    input.nextLine();
                }
            } while(minesToBuy < 0 || total > money);

            mines += minesToBuy;
            money -= total;

            if (satisfactionFactor > 1.1) {
                oreProduced += rand.nextInt(20) + 1;
                population += rand.nextInt(10) + 1;
            }

            if (satisfactionFactor < 0.8) {
                oreProduced -= rand.nextInt(20) + 1;
                population -= rand.nextInt(10) + 1;
            }

            if (rand.nextInt(100) <= 1) {
                System.out.println("Radiation leak! Many are killed");
                population /= 2;
            }

            if (oreProduced > 150) {
                System.out.println("Market glut. Price falls");
                orePrice /= 2;
            }

            System.out.println("\n\n");


            turn ++;

        } while(turn <= 10);

        if (victory) {
            System.out.println("Well done, you survived your term in office");
        }
    }

}

The problems with the initial code

This code meets the first requirement of good software, it compiles, runs and every time I’ve run it it does the right thing. So what’s wrong with it?

  • It’s all in one big method.
  • It’s all in the main method.
  • Code is repeated.
  • It’s not easy to modify.
  • It’s not properly testable.
  • Immutability? What’s Immutability?
  • And many more!

Links

IntelliJ IDEA
Apache Maven
JUnit
Git
Github
Project Repository