Object-Oriented Programming with Java, part I + II

cc

This material is licensed under the Creative Commons BY-NC-SA license, which means that you can use it and distribute it freely so long as you do not erase the names of the original authors. If you make changes in the material and want to distribute this altered version of the material, you have to license it with a similar free license. The use of the material for commercial use is prohibited without a separate agreement.

Authors: Arto Hellas, Matti Luukkainen
Translators to English: Emilia Hjelm, Alex H. Virtanen, Matti Luukkainen, Virpi Sumu, Birunthan Mohanathas, Etiënne Goossens
Extra material added by: Etiënne Goossens, Maurice Snoeren, Johan Talboom
Adapted for Informatica by: Ruud Hermans

The course is maintained by Technische Informatica Breda


Randomness

When programming, you may occasionally need to simulate random events. Situations such as the unpredictability of weather, or surprising moves on the AI’s part in a computer game can often be simulated with random number generators, running on a computer. In Java, there is a ready-made class Random, which you can use in the following way:

import java.util.Random;

public class Randomizing {
    public static void main(String[] args) {
        Random randomizer = new Random(); // creates a random number generator
        int i = 0;

        while (i < 10) {
            // Generates and prints out a new random number on each round of the loop
            System.out.println(randomizer.nextInt(10));
            i++;
        }
    }
}

In the code above, you first create an instance of the class Random with the keyword new – exactly as when creating objects implementing other classes. An object of type Random has the method nextInt that can be given an integer value as parameter. The method returns a random integer within the range 0..(the integer given as parameter- 1).

The printout of this program could be as follows:

2
2
4
3
4
5
6
0
7
8

We will need floating point numbers, for example when dealing with probability calculations. In computing, probabilities are usually calculated with numbers within the range [0..1]. An object of the class Random can return random floating point numbers with the method nextDouble. Let us consider the following probabilities of weather conditions:

Using the estimates above, let us create a weather forecaster.

import java.util.ArrayList;
import java.util.Random;

public class WeatherForecaster {
    private Random random;

    public WeatherForecaster() {
        this.random = new Random();
    }

    public String forecastWeather() {
        double probability = this.random.nextDouble();

        if (probability <= 0.1) {
            return "Sleet";
        } else if (probability <= 0.4) { // 0.1 + 0.3
            return "Snow";
        } else { // the rest, 1.0 - 0.4 = 0.6
            return "Sunny";
        }
    }

    public int forecastTemperature() {
        return (int) ( 4 * this.random.nextGaussian() - 3 );
    }
}

The method forecastTemperature is interesting in many ways. Within this method, we are calling the method this.random.nextGaussian(), just like any other time we have called a method in the previous examples. Interestingly, this method of the class Random returns a value from the normal distribution (if you have no interest in the different varieties of random figures, that’s okay!).

public int forecastTemperature() {
    return (int) ( 4 * this.random.nextGaussian() - 3 );
}

In the expression above, interesting is the section (int). This part of the expression changes the bracketed floating point number into an integer value. A corresponding method transforms integer values into floating point numbers: (double) integer. This is called an explicit type conversion.

Let us create a class with a main method that uses the class WeatherForecaster.

public class Program {

    public static void main(String[] args) {
        WeatherForecaster forecaster = new WeatherForecaster();

        // Use a list to help you organise things
        ArrayList<String> days = new ArrayList<String>();
        Collections.addAll(days, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun");

        System.out.println("Weather forecast for the next week:");
        for(String day : days) {
            String weatherForecast = forecaster.forecastWeather();
            int temperatureForecast = forecaster.forecastTemperature();

            System.out.println(day + ": " + weatherForecast + " " + temperatureForecast + " degrees.");
        }
    }
}

The printout from this program could be as follows:

Weather forecast for the next week:
Mon: Snow 1 degrees.
Tue: Snow 1 degrees.
Wed: Sunny -2 degrees.
Thu: Sunny 0 degrees.
Fri: Snow -3 degrees.
Sat: Snow -3 degrees.
Sun: Sunny -5 degrees.

Exercise random-1: Rolling the dice

In the template is class Dice that has the following functionality:

  • The constructor Dice(int numberOfSides) creates a new dice object that has the amount of sides defined by the argument.
  • The method roll tells the result of a roll (which depends on the number of its sides)

The frame of the program is as follows:

import java.util.Random;

public class Dice {
    private Random random;
    private int numberOfSides;

    public Dice(int numberOfSides){
        this.numberOfSides = numberofSides;
        random = new Random();

    }

    public int roll() {
          // we'll get a random number in the range 1-numberOfSides<
    }
}

Expand the class Dice so that with each roll the dice returns a random number between 1...number of sides. Here is a main program that tests the dice:

public class Program {
    public static void main(String[] args) {
        Dice dice = new Dice(6);

        int i = 0;
        while ( i < 10 ) {
            System.out.println( dice.roll() );
            i++;
        }
    }
}

The output could look something like this:

1
6
3
5
3
3
2
2
6
1

Exercise random-2: Password randomizer

Your assignment is to expand the class PasswordRandomizer that has the following functionality:

The constructor PasswordRandomizer creates a new object, which uses the given password length. The method createPassword returns a new password, which consists of symbols a-z and is of the length given as a parameter to the constructor The frame of the class is as follows:

import java.util.Random;

public class PasswordRandomizer {
    // Define the variables here

    public PasswordRandomizer(int length) {
        // Format the variable here
    }

    public String createPassword() {
      // Write the code here which returns the new password
    }
}

In the following is a program that uses a PasswordRandomizer object:

public
class Program {
    public static void main(String[] args) {
        PasswordRandomizer randomizer = new PasswordRandomizer(13);
        System.out.println("Password: " + randomizer.createPassword());
        System.out.println("Password: " + randomizer.createPassword());
        System.out.println("Password: " + randomizer.createPassword());
        System.out.println("Password: " + randomizer.createPassword());
    }
}

The output could look something like this:

Password: mcllsoompezvs
Password: urcxboisknkme
Password: dzaccatonjcqu
Password: bpqmedlbqaopq

Tip 1: this is how you turn the integer number into a character:

int number = 17;
char symbol = "abcdefghijklmnopqrstuvwxyz".charAt(number);

Tip 2: The tip in assignment 58 might be useful in this one too.

Exercise random-3: Lottery

Your assignment is to expand the class LotteryNumbers, which draws the lottery numbers of the week. The numbers of the week consist of 7 different numbers between 1 and 39. The class has the following functionality:

  • the constructor LotteryNumbers creates a new LotteryNumbers object, which contains the new drawn numbers
  • the method numbers returns the drawn numbers of this draw
  • the method drawNumbers draws new numbers
  • the method containsNumber reveals if the number is among the drawn numbers

The frame of the class is as follows:

import java.util.ArrayList;
import java.util.Random;

public class LotteryNumbers {
    private ArrayList<Integert> numbers;

    public LotteryNumbers() {
        // We'll format a list for the numbers
        this.numbers = new ArrayList<Integert>();
        // Draw numbers as LotteryNumbers is created
        this.drawNumbers();
    }

    public ArrayList<Integert> numbers() {
        return this.numbers;
    }

    public void drawNumbers() {
        // Write the number drawing here using the method containsNumber()
    }

    public boolean containsNumber(int number) {
        // Test here if the number is already among the drawn numbers
    }
}

The following main program comes with the template:

import java.util.ArrayList;

public class Program {
    public static void main(String[] args) {
        LotteryNumbers lotteryNumbers = new LotteryNumbers();
        ArrayList<Integert> numbers = lotteryNumbers.numbers();

        System.out.println("Lottery numbers:");
        for (int number : numbers) {
            System.out.print(number + " ");
        }
        System.out.println("");
    }
}

The program can print lines like these:

Lottery numbers:
3 5 10 14 15 27 37
Lottery numbers:
2 9 11 18 23 32 34

Note! a number can be in one set of numbers only once (per draw of course).

Exercise random-4: Game logic for Hangman

Your friend designed a Hangman game that looks like the following:

hangman

Your friend has programmed the user interface and also a skeleton for the game logic. Now, she asks you to finish the remaining pieces of the game logic.

Amongst other stuff, with TMC you get the following skeleton for the class HangmanLogic

public class HangmanLogic {

    private String word;
    private String guessedLetters;
    private int numberOfFaults;

    public HangmanLogic(String word) {
        this.word = word.toUpperCase();
        this.guessedLetters = "";
        this.numberOfFaults = 0;
    }

    public int numberOfFaults() {
        return this.numberOfFaults;
    }

    public String guessedLetters() {
        return this.guessedLetters;
    }

    public int losingFaultAmount() {
        return 12;
    }

    public void guessLetter(String letter) {
        // program here the functionality for making a guess

        // if the letter has already been guessed, nothing happens

        // it the word does not contains the guessed letter, the number of faults increases
        // the letter is added among the already guessed letters
    }

    public String hiddenWord() {
        // program here the functionality for building the hidden word

        // create the hidden word by iterating through this.word letter by letter
        // if the letter in turn is within the guessed words, put it in the hidden word
        // if the letter is not among the guessed ones, replace it with _ in the hidden word

        // return the hidden word at the end

        return "";
    }
}

In this assignment, you should only touch class HangmanLogic and implement the functionality of the methods guessLetter(String letter) and hiddenWord().

Testing the code

The TMC project includes two classes that help you with testing. The class Main starts the graphical version of the game. The class TestProgram can be used to test the class HangmanLogic.

Exercise random-4.1: Guessing a letter

Touch only the method guessLetter(String letter) in this assignment!

When a user guesses a letter, the user interface calls method guessLetter which is supposed to take care of action related to guessing a letter. First, it should check if the letter has already been guessed. In that case, the method does not do anything.

The method increases the number of faults (this.numberOfFaults) if the word (this.word) does not contain the guessed letter. Then the letter is added among the already guessed letters (the object variable this.guessedLetters).

An example of how the method guessLetter should work:

HangmanLogic l = new HangmanLogic("kissa");
System.out.println("guessing: A, D, S, F, D");
l.guessLetter("A");   // correct
l.guessLetter("D");   // wrong
l.guessLetter("S");   // correct
l.guessLetter("F");   // wrong
l.guessLetter("D");   // This should not have any effect on the number of faults since D was already guessed
System.out.println("guessed letters: "+l.guessedLetters());
System.out.println("number of faults: "+l.numberOfFaults());
guessing: A, D, S, F, D
guessed letters: ADSF
number of faults: 2

Exercise random-4.2: Creating the hidden word

The Hangman user interface shows a hidden version of the word to the user. In the above figure, the hidden word is METO_I. All the letters that the user has already guessed are shown in the hidden word but the rest of the letters are replaced with underscores. In this part of the assignment, you should complete the method hiddenWord of Hangman logic that takes care of building the hidden word for the user interface.

Commands while, charAt and contains might be useful here. Note that a single char can be made into a string as follows:

char c = 'a';
String aString = "" + c;

An example of how the method works:

HangmanLogic l = new HangmanLogic("kissa");
System.out.println("word is: "+l.hiddenWord());

System.out.println("guessing: A, D, S, F, D");
l.guessLetter("A");
l.guessLetter("D");
l.guessLetter("S");
l.guessLetter("F");
l.guessLetter("D");
System.out.println("guessed letters: "+l.guessedLetters());
System.out.println("number of faults: "+l.numberOfFaults());
System.out.println("word now: "+l.hiddenWord());
word is: _____
guessing: A, D, S, F, D
guessed letters: ADSF
number of faults: 2
word now: __SSA

Now, you can test the game by using class Main. You can change the guessed word by changing the constructor parameter of the game logic:

HangmanLogic logic = new HangmanLogic("parameter");
HangmanUI game = new HangmanUI(logic);
game.start();

The game is played with the keyboard. You can end the game by pressing x in the upper left corner of the game window.