Lab 6 in Object Oriented Programming

Mastermind

1. Introduction

In this final lab, you should complement and enhance a Java program that can play Mastermind.

Mastermind is a game between two players: one of them chooses a secret code and the other one has to guess. In our version of the game the user selects a code and the program is guessing. A code consists of four colors, chosen from the six colors black, white, blue, red, green and yellow. A possible code is "blue, blue, yellow, yellow". One can therefore choose the same color more than once. The order is important, i.e the code "blue, yellow, blue, yellow" is not the same as "blue, blue, yellow, yellow".

The game begins with the user selecting its code. Then, the program tries repeatedly to guess the code. For each guess the user must say how good the guess is by saying how many bulls and cows the guess contains. A bull is a color choice in which the guess appears in exactly the same place in the secret code. A cow is a color that is in the secret, but is in another place. A color in the secret can only be counted as a bull or a cow once. The following table gives some examples of guesses and the user's answers about the secret "blue, blue , yellow, yellow":               
GuessBulls Cows
blue, yellow, white, red 1 1
blue, blue, blue, blue 20
yellow, yellow, blue, blue 0 4
yellow, blue , yellow, blue22

You should now download the file lab6.zip and compile and run the program. First, a dialog box opens where you are prompted to select a code, after that starts the main interface where the program will present its guesses. The picture below gives an example, where the secret is "blue, blue, yellow, yellow" and where the program just unveiled its sixth guess. The user should choose the right number of bulls and cows using the soft keys at the bottom-right and then he/she should press Reply OK:
.

Unfortunately, the program is not very smart. Each time it chooses a completely random guess, with the only restriction that the same guess is not made again. The program thus does not take into account the user's answers to the previous guesses. The result is of course that the program almost never successfully guesses the secret before the play field is filled in.

Your task is to improve the program's ability for guessing.

2. The interface GuessEngine.

Your task is more specifically to replace the class NaiveEngine with a more sophisticated class. A look at the class NaiveEngine indicates that it implements the interface GuessEngine: you must thus, understand this interface. To do this we must first understand classes Color, Code and Reply.

Using these types, we can now go through the methods in the interface GuessEngine:

3. The class NaiveEngine

We can now see how the class NaiveEngine is implemented. Its instance variables are:

    private List<Code> codes;
    private Code newGuess;
    private Code[] oldGuesses;
    private Reply[] oldReplies;
    int guessCount;

The last three of these variables keep track of the old guesses and the user's response to them. The constructor of the class sets both fields to be arrays with 10 elements each. newGuess remembers the last guess that has not yet received a response. The list codes contains all yet to be made ​​guesses. This list is initialized in init to contain all the 64 = 1296 possible codes. A new guess is chosen as a random element from this list. It is simultaneously removed from the list.

NaiveEngine has no ability to detect if the user gives conflicting responses. The exception ContradictionException is thrown only when the list of not yet made ​​guesses is empty. Similarly this class can not give any reasonable explanation as to how the user answered incorrectly.

4. Your task

You are to implement another class that can replace NaiveEngine. Your class must implement GuessEngine, but it must do much better guesses. every guess the program does should have the property that it can not be ruled out because of the user's existing responses. In principle it is easy to describe how to do this: the list codes should contain only codes that can be the secret, given the answers already received by the user.

You should start by carefully reading through NaiveEngine and determining which parts you can keep unchanged and what you need to improve. A lot can be reused! Note also that none of the other classes from the zip file needs to be changed.

The main improvement is thus to reduce codes so that it only contains possible secrets. Prior to the first guess, codes consists of all possible codes: you have not yet received any response. Each call of answerNewGuess to the model knows how right/wrong the latest guess was. One can then go through the list of codes and remove any element which does not give exactly the same response to the last guess.

For each possible secret from the list of codes you should determine whether it leads to the answer reply for the guess newGuess. This in turn requires that the program can figure out what the reply should be for the guess newGuess given a specific secret. If we do this then it is enough to compare the reply given from the user with the reply computed for a potential secret from the list codes. If they do not match then the corresponding code is removed.

to calculate the answer for given secret and guess

We recommend you to define a method that takes two codes secret and guess as parameters and returns a Reply. The result of the method is the response that the user is supposed to give, if the secret is secret and the guess is guess. It may seem strange that one could make use of this feature: When can you use it in the program? You do not know what the secret is!

We repeat the above idea: you have to take the time necessary to understand how it is supposed to work. After each guess codes will only contain the secrets that have not yet been ruled out. We choose one of these randomly as the next guess and we get the user's response. If this answer is not four bulls (in which case we guessed the secret) then we do the following. We consider in a sequence each remaining element in codes as a possible secret and we use our function to calculate the response that the user should give in this case. We compare with the response that we got. If these are not the same then our assumption is wrong, and the corresponding code is removed from the list of possible secrets, i.e. from the list codes.

One way to define this function is the following:

We also strongly recommend you to write a small test program so that you are sure that the function is working properly. Then you use it in the filtration of codes in answerNewGuess.

When you have come so far, you can replace NaiveEngine with your model class and test the program. If the user provides correct answers the program will normally find the secret within six guesses. If the user gives the wrong answer for some guess you will eventually be in a situation where codes is empty, i.e. there are no new guesses to do. Then you cannot do anything but throw an exception. To pass the lab you do not need to improve explainContradiction from NaiveEngine, i.e. you don't need to identify the user's mistake.

5. Optional

We will take a note if you do the optional task and this will be taken into account in borderline cases to decide grades on the exam. The suggestion is to implement an improved explainContradiction. In this method you know the secret and you know all your past guesses and what answers the user gave. Using this, one can identify the wrong answer. Go through the past guesses and for each compute the right response. If it differs from the users response, generate a string which shows the right response and the given response. For example:

When I guessed RED WHITE BLUE RED, you answered 1 0,
the correct answer should have been 0 1.

It is of course possible that the user has given several incorrect answers. It is sufficient in this case to identify and explain one of them.

6. Submission

You should upload your model class and the corrections in Fire. If you have chosen to define a helper class it must of course also be uploaded so that we can run your program.