Row

Now, we have Colors and even instances if we need having a ColorManager. This is the time to store Colors in Rows. The Row class is a bit longer, but not too complex.

package packt.java9.by.example.mastermind; 

import java.util.Arrays;

public class Row {
final Color[] positions;
private int matchedPositions;
private int matchedColors;

A Row contains three fields. One is the positions array. Each element of the array is a Color. The matchedPositions is the number of positions that are matched and matchedColors is the number of colors that match a color in the hidden row but is not on the position as in the hidden row.

    public static final Row none = new Row(Guesser.none);

The none is a constant that contains a special Row instance that we will use wherever we would use null. The constructor gets the colors in an array that should be in the row.

  public Row(Color[] positions) { 
this.positions = Arrays.copyOf(positions, positions.length);
}

The constructor makes a copy of the original array. This is an important code that we will examine a bit. Let's reiterate that Java passes arguments by value. It means that when you pass an array to a method, you will pass the value of the variable that holds the array. However, an array in Java is an Object just as well as anything else (except primitives like int). Therefore, what the variable contains is a reference to an object that happens to be an array. If you change the elements of the array, you actually change the elements of the original array. The array reference is copied when the argument passes, but the array itself, and the elements, are not.

The java.util.Arrays utility class provides a lot of useful tools. We can easily code the array copying in Java but why to reinvent the wheel? In addition to that, arrays are continuous area of memory that can very effectively be copied from one place to another using low-level machine code. The copyOf method that we invoke calls the method System.arraycopy which is a native method and as such executes native code.

Note that there is no guarantee that Arrays.copyOf invokes the native implementations and that this will be extremely fast in case of large arrays. The very version I was testing and debugging was doing it that way, and we can assume that a good JDK does something similar, effective and fast.

After we copied the array, it is not a problem if the caller modifies the array that was passed to the constructor. The class will have a reference to a copy that will contain the same elements. However, note that if the caller changes any of the objects that are stored in the array (not the reference in the array, but the object itself that is referenced by an array element), then the same object is modified. Arrays.copyOf does not copy the objects that are referenced by the array, only the array elements.

The row is created along with the colors and thus, we used a final field for the Color array. The matches, however, cannot be known when a Row is created. One of the players creates the Row and after that, the other player will tell the two int values. We do not create two setters for the two values, however, because they are always defined at the same time in the game together.

  public void setMatch(int matchedPositions, int matchedColors) { 
if (matchedColors + matchedPositions > positions.length) {
throw new IllegalArgumentException(
"Number of matches can not be more that the position.");
}
this.matchedColors = matchedColors;
this.matchedPositions = matchedPositions;
}

The setMatch method does not only set the values, but also checks that the values are consistent. The sum of the two values cannot be more than the number of the columns. This check ensures that the caller, who uses the API of the Row class, does not use it inconsistently. If this API is used only from inside our code, this assertion should not be part of the code. A good coding style, in that case, will ensure that the method is never invoked inconsistently using unit tests. When we create API to use out of our control, we should check that the use is consistent. Failing to do so, our code may behave just weird when used inconsistently. When the caller sets matches to values that do not match any possible guess, the game may never finish and the caller may have a hard time figuring out what is going on. This figuring out probably will need the debug execution of our code.

If we throw an exception in this case, the program stops where the bug is. There is no need to debug the library.

public boolean guessMatches(Color[] guess) { 
return nrMatchingColors(guess) == matchedColors &&
nrMatchingPositions(guess) == matchedPositions;
}

The next method decides if a guess, given as an argument, matches the actual row. This method checks that the answers to the guess in the row can be valid if the current guess was in the hidden row. The implementation is fairly short and simple. A guess matches a row if the number of the colors matching and the number of positions matching are the same as the number given in the row. Do not be shy to write short methods. Do not think that a one-line method that essentially contains one statement is useless. Wherever we use this method, we could also write the expression, which is right after the return statement, but we do not for two reasons. The first and most important reason is that the algorithm, which decides that a row matches a guess belongs to the implementation of the class Row. If ever the implementation changes, the only location where the code is to be changed is here. The other reason is also important, and that is readability. In our codebase, we call this method from abstract class Guesser. It contains an if statement with the following expression:

if (!row.guessMatches(guess)) {

Would it be more readable in the following way:

if( !(nrMatchingColors(guess) == matchedColors && nrMatchingPositions(guess) == matchedPositions)) {

I am certain that the majority of the programmers understand the intention of the first version easier. I would even recommend implementing the doesNotMatchGuess method to improve the readability of the code even more.

  public int nrMatchingColors(Color[] guess) { 
int count = 0;
for (int i = 0; i < guess.length; i++) {
for (int j = 0; j < positions.length; j++) {
if (i != j && guess[i] == positions[j]) {
count++;
}
}
}
return count;
}

The number of matching colors is that which appears both in the row and the guess, but not in the same position. The definition, and how we calculate it, is fairly simple and unambiguous in case no color can appear twice in the hidden row. In case a color may appear multiple times in the hidden row, this implementation will count all occurrences of that color in the guess as many times as it appears in the hidden row. If we, for example, have a hidden RRGB row and the guess is bYRR, the calculation will say 4. It is a matter of agreement between the players how they count in this case. The important aspect is that they use the same algorithm, which should be true in our case, because we will ask the program to play both players. As we will program the code ourselves, we can trust that it will not cheat.

public int nrMatchingPositions(Color[] guess) { 
int count = 0;
for (int i = 0; i < guess.length; i++) {
if (guess[i] == positions[i]) {
count++;
}
}
return count;
}

Counting the colors that are OK, and also on the position where they are supposed to be, is even simpler.

public int nrOfColumns() { 
return positions.length;
}

This method tells the number of columns in the Row. This method is needed in the Game class that controls the flow of a whole game. As this class is in the same package as Row, it can access the field positions. I created the code to get the number of columns as row.positions.length. But then, I was reading the code next day and told myself: This is ugly and unreadable! What I am interested in here is not some mysterious positions' length; it is the number of columns. And the number of columns is the responsibility of the Row class and not the business of any other class. If I start to store the positions in a List, which does not have length (it has method size), it is the sole responsibility of Row and should not affect any other code. So, I created the nrOfColumns method to improve the code.

The rest of the class contains some more very simple methods that are needed only to display the game and not for the algorithm to play:

  public int nrColumns() { 
return positions.length;
}

public Color position(int i) {
return positions[i];
}

public int matchedPositions() {
return matchedPositions;
}

public int matchedColors() {
return matchedColors;
}
}

If you are a purist, you can encapsulate these methods into an inner class named Output or Print and call them through a final instance of it created as a field in the Row class. It is also possible to change the visibility of these fields from private to protected and implement these methods in a PrintableRow that can be instantiated from an already existing Row and implement these methods.

The first version of PrintableRow will look like this:

public class PrintableRow extends Row { 
public PrintableRow(Row row) {
super(row.positions);
super.setMatch(row.matchedPositions,row.matchedColors);
}
// the methods are deleted from the print ...
}

The methods are exactly the same as in the preceding print; they are cut and pasted, or rather moved, using the IDE refactoring support from one class to the other.

When you write a code, please never use copy and paste. However you can use cut and paste to move code fragments around. The danger is in the copy paste use. Many developers claim that their use of actual copy and paste is not copy paste programming. Their reasoning is that they change the pasted code so much that it has practically nothing to do with the original code.
Really? In that case why did you need the copied code when you started the modification of it? Why not start from scratch? That is because if you use the IDE's copy and paste functionality then, no matter what, you do copy paste programming.

Class PrintableRow is pretty neat and separates the output concern from the core functionality. When you need an instance, it is not a problem that you have a Row instance already in hand. The constructor will essentially clone the original class and return a printable version. What bothers me is the implementation of the cloning. The code in the constructor calls the super constructor and then a method and all these work with the original functionality of the Row class. They have nothing to do with the printability that PrintableRow implements. This functionality actually belongs to the Row class. We should create a protected constructor that does the cloning:

protected Row(Row cloneFrom) { 
this(cloneFrom.positions);
setMatch(cloneFrom.matchedPositions, cloneFrom.matchedColors);
}

The constructor of PrintableRow should simply call super(row) and that is it.

Code is never finished and never perfect. In a professional environment, programmers many times tend to finish polishing the code when it is good enough. There is no code that cannot be made better, but there is a deadline. The software has to be passed on to the testers and users and has to be used to help economy. After all, that is the final goal of a professional developer: have a code that supports the business. A code that never runs is worth nothing.
I do not want you to think that the examples that I provided here were created perfect upfront. The reason for that is (did you read carefully?) because they are not perfect. As I said, code is never perfect.
When I first created Row, it contained the printing methods in an inner class. I did not like it. The code was smelly. So, I decided to move the functionality to the Row class. However, I still did not like the solution. Then, I went to bed, slept, worked, and returned to it a few days later. What I could not create the day before now seemed obvious—these methods have to be moved to a subclass.
Now comes another dilemma. Should I present this final solution or should I have here the different versions? In some cases, I will just present the final version. In other cases, like this, there are things to learn from the development step. In these cases, I present not only the code, but part of its evolution on how it was created. If you want to see those that I did not dare publishing, look at the Git history. I admit, sometimes, I create code that even makes me facepalm a day later.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.205.235