HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Game of Life implementation ran in the terminal

Submitted by: @import:stackexchange-codereview··
0
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:

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.

  • If you want to truly separate the implementation from the user interface, you should not call BoardPrinter.print() from within your LifeBoard class. A good way to achieve separation is, for example, to create an interface (for instance IBoardOutput), which has a method print(boolean[][] state). Then, you can add a method to your LifeBoard class, which allows you to set an BoardOutput, so BoardOutput.print(...) can be called. Finally, let BoardPrinter implement the interface IBoardOutput. So, the output method can be changed without touching the LifeBoard class. This is called strategy pattern or dependency injection, if you want to do further research.



  • Be careful with data encapsulation. Your BoardPrinter class receives oldGamefield, which enables the BoardPrinter class to modify your gamefield! If you implement the approach above, an implementation of BoardOutput could modify the gamefield by accident. Passing a copy of the gamefield to BoardOutput is possible solution, passing an instance of LifeBoard istself and accessing the getCell method is another one (add an overload without the direction parameter for this).



  • Do the evaluateCell and evaluateCells methods really have to be public?



  • Your implementation of Direction is nice, if you have to access methods which depend on the Direction class 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) use if(state[row][position]).



  • If you want a small pause between the steps of the simulation, DON'T pause the thread in the BoardPrinter class. Do it in your LifeBoard class. Why? Because the BoardPrinter is for printing the board, not for controlling the simulation.



  • Implementing a SeedFactory is a valid way of doing so, and will probably be a nice exercise.



  • Your OscillatorSeed class 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.