Architecture

Package structure, component roles, data flow, and extension points.

What JCAL Is

JCAL (Java Cellular Automata Library) is a lightweight Java library for building and simulating Cellular Automata with minimal boilerplate.

A Cellular Automaton is formally described as the quadruple <Z^d, S, X, σ>:

Symbol Meaning JCAL type
Z^d d-dimensional grid of cells CellGrid (CellGrid for 2D, CellGrid for 3D/4D)
S Set of possible cell states CellState
X Neighborhood strategy Neighborhood subclass
σ Transition function CellularAutomataRule subclass

Package Structure

io.github.carmelolg.jcal
├── core/
   ├── CellularAutomata                    the grid (CellGrid); holds neighbourhood + config
   ├── CellularAutomataConfiguration       immutable config; use inner Builder
      └── CellularAutomataConfigurationBuilder
   ├── CellularAutomataRule            abstract; extend to define the transition rule
   └── parallel/
       ├── CellularAutomataParallelRule    parallel variant of the executor
       ├── Runner                              internal  Callable for parallel transition
       └── RefinementRunner                    internal  Callable for parallel refinement

├── grid/
   ├── Cell                                one cell; has a CellState + int[] coordinates
   ├── CellState                           a cell's state; key + arbitrary value Object
   ├── CellGrid                            unified n-dimensional grid (2D4D, flat array)
   └── GridDimensions                      immutable nD descriptor (sizes, strides, total)

├── neighborhood/
   ├── Neighborhood                        abstract base; extend for custom neighbourhoods
   ├── NDCapable                           marker interface; implement for 3D/4D custom neighbourhoods
   ├── NeighborhoodType                    enum: MOORE | VON_NEUMANN
   ├── MooreNeighborhood                   built-in 2D: 8 surrounding cells
   ├── VonNeumannNeighborhood              built-in 2D: 4 orthogonal cells
   ├── Moore3DNeighborhood                 built-in 3D: 26 surrounding cells
   ├── VonNeumann3DNeighborhood            built-in 3D: 6 orthogonal cells
   ├── Moore4DNeighborhood                 built-in 4D: 80 surrounding cells
   └── VonNeumann4DNeighborhood            built-in 4D: 8 orthogonal cells

├── utils/
   └── Utils                               internal helpers (isInside, cloneGrid)

└── examples/
    ├── GameOfLifeExample                   2D minimal runnable example
    ├── GameOfLife3DExample                 3D example: Carter Bays' 3D Life
    └── CustomStateExample                  advanced example with multi-value state

Public API vs. Internal

Class Status Notes
CellularAutomata Public API Core grid object
CellularAutomataConfiguration Public API Always build via inner Builder
CellularAutomataRule Extension point Subclass to define your rule
Neighborhood Extension point Subclass for any custom neighbourhood (2D or nD)
NDCapable Marker interface Implement alongside Neighborhood for 3D/4D custom neighbourhoods
CellGrid Public API Unified n-dimensional grid class (2D–4D)
GridDimensions Public API Immutable nD grid descriptor
Cell Public API Returned by the grid; construct for initial state
CellState Public API Create instances for each state your CA needs
NeighborhoodType Public API Pass to builder for built-in neighbourhoods
MooreNeighborhood Public (via NeighborhoodType.MOORE) 2D, rarely instantiated directly
VonNeumannNeighborhood Public (via NeighborhoodType.VON_NEUMANN) 2D, rarely instantiated directly
Moore3DNeighborhood Public (auto-resolved for 3D) Use NeighborhoodType.MOORE
VonNeumann3DNeighborhood Public (auto-resolved for 3D) Use NeighborhoodType.VON_NEUMANN
Moore4DNeighborhood Public (auto-resolved for 4D) Use NeighborhoodType.MOORE
VonNeumann4DNeighborhood Public (auto-resolved for 4D) Use NeighborhoodType.VON_NEUMANN
CellularAutomataParallelRule Extension point Parallel variant of executor
Runner Internal Do not use directly
RefinementRunner Internal Do not use directly
Utils Internal helper May be used by custom neighbourhoods

Data Flow per Generation

for each generation:
  1. refinements(cell)           — applied to every cell  [optional CCA hook]
  2. snapshot the grid           — clone the grid before any mutation
  3. transition(cell, neighbors)  — per cell, reads snapshot, writes result
  4. copy result back            — update the main grid with all new states

The snapshot in step 2 ensures full isolation: all cells in transition see the pre-transition state of their neighbors, regardless of the order in which cells are processed.


Grid Abstraction

CellGrid

CellGrid is the unified n-dimensional grid class (2D–4D) backed by a flat array with stride-based indexing. All executors and neighbourhoods operate on CellGrid.

Cell   get(int[] coords)
void   set(int[] coords, Cell cell)
List<int[]> allCoordinates()
GridDimensions getDimensions()
boolean is2D()

CellGrid is always created by CellularAutomata — you never instantiate it directly.

GridDimensions

A Java 16 record that stores the size of each axis and precomputes strides for O(1) flat-array indexing:

flat index = coords[0] * stride[0] + coords[1] * stride[1] + … + coords[n-1] * stride[n-1]

Extension Points

1. Custom Transition Rule

Subclass CellularAutomataRule (sequential) or CellularAutomataParallelRule (parallel):

public class MyRule extends CellularAutomataRule {
    @Override
    public Cell transition(Cell cell, List<Cell> neighbors) {
        // inspect cell.getCurrentStatus() and neighbors
        // return a new Cell with the next state
    }
}

2. Custom State

CellState accepts any Object as its value:

CellState complex = new CellState("state", Map.of("temp", 100, "pressure", 3));

Two CellState values are equal when both key and value are equal.

3. Custom 2D Neighborhood

Subclass Neighborhood:

public class DiagonalNeighborhood extends Neighborhood {
    @Override
    public List<Cell> getNeighbors(Cell[][] matrix, int i, int j) {
        // return a list of neighbor cells
    }
}

4. Custom nD Neighborhood

Subclass Neighborhood:

public class Custom3DNeighborhood extends Neighborhood {
    @Override
    public List<Cell> getNeighbors(CellGrid grid, int[] coords) {
        // return a list of neighbor cells
    }
}

5. CCA Pre-Processing

Override refinements(Cell cell) in your executor:

@Override
public Cell refinements(Cell cell) {
    // update internal state before neighbors are read
    return cell;
}

Configuration Flow

CellularAutomataConfigurationBuilder
    → CellularAutomataConfiguration (immutable)
    → CellularAutomata(config)       ← builds CellGrid + resolves neighborhood
    → executor.run(ca)               ← applies transition for N generations
    → updated CellularAutomata

Constraints

Constraint Detail
Java 16 Compile target --release 16
No breaking changes Public API signatures must not change without explicit approval
setInitalState Keep the intentional spelling — it is part of the public API
Javadoc required Every new public class and method must have Javadoc
License CC BY-NC-SA 4.0