patternjavaMinor
Game of Life implementation ran in the terminal
Viewed 0 times
theterminalrangamelifeimplementation
Problem
I have been teaching myself programming, mainly in Java, for about 6 months. I'm looking for some feedback on this implementation of the Game of Life, which runs entirely in the terminal. Specifically, where does it not follow best practices, is it over-engineered, etc?
The entry point:
Seed interface defines specific behavior of concrete seeds:
Here are some concrete seeds:
```
public class OscillatorSeed implements Seed {
public boolean[][] seed = {
{false, false, false, false, false},
{false, false, false, false, false},
{false, true, true, true, false},
{false, false, false, false, false},
{false, false, false, false, false}
};
public int height = 5;
public int width = 5;
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
public boolean[][] getSeed() {
return seed;
}
}
public class GliderSeed implements Seed {
public boolean[][] seed = {
{false, false, false, false, false},
{false, false, false, true, false},
{false, true, false, true, false},
{false, false, true, true, false},
The entry point:
public class GameOfLife {
public static void main(String[] args) {
Seed seed = new OscillatorSeed(); //could be any object implementing seed interface
LifeBoard gameOfLife = new LifeBoard(seed);
}
}Seed interface defines specific behavior of concrete seeds:
public interface Seed {
/*
*pattern for seed files
*must have a "board" made of a 2d boolean array
*board is not required to be rectangular
*/
public int getHeight();
public int getWidth();
public boolean[][] getSeed();
}Here are some concrete seeds:
```
public class OscillatorSeed implements Seed {
public boolean[][] seed = {
{false, false, false, false, false},
{false, false, false, false, false},
{false, true, true, true, false},
{false, false, false, false, false},
{false, false, false, false, false}
};
public int height = 5;
public int width = 5;
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
public boolean[][] getSeed() {
return seed;
}
}
public class GliderSeed implements Seed {
public boolean[][] seed = {
{false, false, false, false, false},
{false, false, false, true, false},
{false, true, false, true, false},
{false, false, true, true, false},
Solution
First of all, I think your code is very nice for 6 months of training. The following tips are mainly regarding style and object orientation.
Fun tip: You can even use the mentioned Strategy pattern to make the set of rules used for the game exchangeable.
Have fun!
- If you want to truly separate the implementation from the user interface, you should not call
BoardPrinter.print()from within yourLifeBoardclass. A good way to achieve separation is, for example, to create an interface (for instanceIBoardOutput), which has a methodprint(boolean[][] state). Then, you can add a method to yourLifeBoardclass, which allows you to set anBoardOutput, soBoardOutput.print(...)can be called. Finally, letBoardPrinterimplement the interfaceIBoardOutput. So, the output method can be changed without touching theLifeBoardclass. This is called strategy pattern or dependency injection, if you want to do further research.
- Be careful with data encapsulation. Your
BoardPrinterclass receivesoldGamefield, which enables theBoardPrinterclass to modify your gamefield! If you implement the approach above, an implementation ofBoardOutputcould modify the gamefield by accident. Passing a copy of the gamefield toBoardOutputis possible solution, passing an instance ofLifeBoardistself and accessing thegetCellmethod is another one (add an overload without the direction parameter for this).
- Do the
evaluateCellandevaluateCellsmethods really have to be public?
- Your implementation of
Directionis nice, if you have to access methods which depend on theDirectionclass from outside. However, I only see this class being used internally. In such a case, two nested for loops from -1 to 1 for searching directions would be fine, too, especially if performance is important. If you need a code sample on how to do this, just leave a comment.
- Instead of
if(state[row][position] == true)useif(state[row][position]).
- If you want a small pause between the steps of the simulation, DON'T pause the thread in the
BoardPrinterclass. Do it in yourLifeBoardclass. Why? Because theBoardPrinteris for printing the board, not for controlling the simulation.
- Implementing a
SeedFactoryis a valid way of doing so, and will probably be a nice exercise.
- Your
OscillatorSeedclass exposes variables as public (public int width;). You have getters for that and should make them private (or even const/final, since these values are not supposed to change any more).
Fun tip: You can even use the mentioned Strategy pattern to make the set of rules used for the game exchangeable.
Have fun!
Context
StackExchange Code Review Q#31245, answer score: 3
Revisions (0)
No revisions yet.