The rough idea is below.
- Create matrix of Cell objects, which will be used for synchronization
- Assign Actors to the cells
- Whenever Actor moves to another cell it must get a monitor on the cell
Note that the cell, from which Actor starts to move, is not protected in the code below.
Also, what would you expect if every cell is populated has an Actor?
import java.util.ArrayList;
import java.util.List;
public class CellularAutomata {
public static void main(String ... args) throws InterruptedException {
final int rows = 5;
final int cols = 5;
Cell[][] matrix = new Cell[rows][cols];
List<Actor> actors = new ArrayList<>();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = new Cell();
//populate actors
if ((i + j) % 2 == 0) {
Actor actor = new Actor(matrix, i, j);
actor.setName(String.format("Actor %d %d", i, j));
actors.add(actor);
}
}
}
for (Actor actor : actors) {
actor.start();
}
for (Actor actor : actors) {
actor.join();
}
}
public static class Cell {}
public static class Actor extends Thread {
private final static int[][] circleMoves = {
{-1, -1}, {-1, 0}, {-1, 1}
, {0, 1}, {1, 1}, {1, 0}
, {1, -1}, {0, -1}, {0, 0}
};
private final Cell[][] matrix;
private final int row;
private final int col;
public Actor(Cell[][] matrix, int row, int col) {
this.matrix = matrix;
this.row = row;
this.col = col;
}
@Override
public void run() {
for (int i = 0; i < circleMoves.length; i++) {
int nextRow = row + circleMoves[i][0];
int nextCol = col + circleMoves[i][1];
if (nextRow >= 0 && nextRow < matrix.length
&& nextCol >= 0 && nextCol < matrix[nextRow].length) {
Cell targetCell = matrix[nextRow][nextCol];
System.out.println(Thread.currentThread().getName() + " waiting for cell (" + nextRow + ";" + nextCol + ")");
synchronized (targetCell) {
try {
System.out.println(Thread.currentThread().getName() + " moved to cell (" + nextRow + ";" + nextCol + ")");
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
}
}
}
}
}