So I'm making a program that simulates Life-like cellular automata, but I'm having some trouble with the method used to count a cell's live neighbors. The problem is that I want to be able to change how the grid wraps around -- that is, whether it wraps around from left to right (i.e., cylindrical), from top to bottom and left to right (i.e., toroidal), or not at all (i.e., flat) -- and I can't figure out how to make my method account for that. Here's what I have so far:
public int getLiveNeighbors(int row, int col)
{
int count = 0;
// "topology" is an int that represents wraparound:
// 0 = flat; 1 = cylindrical; 2 = toroidal
int top = topology != 2 ? row - 1 : (row + ROWS - 1) % ROWS;
int bottom = topology != 2 ? row + 1 : (row + 1) % ROWS;
int left = topology != 0 ? (col + COLS - 1) % COLS : col - 1;
int right = topology != 0 ? (col + 1) % COLS : col + 1;
for (int r = top; r < bottom + 1; r++)
for (int c = left; c < right + 1; c++)
if (!(r == row && c == col) && getCell(r, c).equals(LIVE))
count++;
}
The key, I think, is the if-statement in the for-loop -- there has to be some way to check whether r and c are within the bounds of the grid, while keeping in mind that the definition of "bounds" will vary depending on whether/how the grid wraps around. In the past I've gotten around this by having three different sets (one for each wraparound setting) of eight different if-statements to individually check each of the eight cells comprising the original cell's neighborhood; as you can imagine, it was not very pretty, but at least it worked.
I'm not so great at explaining my own code, so I hope that wasn't too confusing -- I'm feeling a little loopy myself (ha). If anyone has any questions, feel free to ask!
You probably already have a class like
Boardwith a method likegetCell(x, y)(at least a method of this kind is present in your code).I'd just make this method lenient in a sense that it would accept negative
xandyorxandygreater or equal toCOLSandROWS. Thus you could just iterate overcol - 1tocol + 1androw - 1torow + 1(minuscolandrow) and not care that these coordinates go "over the board". It's the task of theBoardto do coordinate lookups correctly.What makes your code harder is also that you handle different topologies in one place. It's quite hard to follow.
You could make it simpler by implementing different subclasses of
BoardlikeCylindricalBoard,ToroidalBoardandFlatBoard. Each of the subclasses would implementgetCelldifferently, but in the context of the subclass it will be clearly understandable.