TL;DR
- The Book Problem: An ant sits on an infinite grid of white cells. At each step:
- On a white square: flip color to black, turn $90^\circ$ right (clockwise), and move forward one unit.
- On a black square: flip color to white, turn $90^\circ$ left (counter-clockwise), and move forward one unit.
- Simulate the first $K$ moves and print the resulting bounded grid.
- The Optimal Solution: Sparse Coordinate HashSet & Dynamic Bounding Box:
- Infinite Grid Representation: A fixed 2D array cannot represent an unbounded plane. Store only the active black cell coordinates in a
HashSet<Position>.- Dynamic Bounding Box: Track
minRow,maxRow,minCol, andmaxColas the ant moves to render the minimal enclosing rectangle.- State Transitions:
- If
blackCells.contains(pos): removepos, turn counter-clockwise, step forward.- Else: add
pos, turn clockwise, step forward.- Runs in $O(K)$ time and $O(K)$ auxiliary space for $K$ moves.
- Production Reality: Turing completeness in cellular automata, emergent highway chaos theory, and dynamic spatial hashing in game physics engines.
1. The Book Problem Formulation
In Cracking the Coding Interview (Problem 16.22), we are asked:
"Simulate the movement of Langton's Ant across an infinite 2D coordinate grid for K steps and render the resulting board."
2. Cellular Automaton Mechanics & Bounding Box
State Rules:
White Cell (Empty) ──> Turn RIGHT (+90°), Invert to BLACK (Add to Set), Advance
Black Cell (In Set) ──> Turn LEFT (-90°), Invert to WHITE (Remove Set), Advance
Emergent Behavior:
Moves 0 .. 500: Symmetrical patterns
Moves 500 .. 10,000: Chaotic pseudo-random diffusion
Moves > 10,000: Builds an emergent 104-step repeating "Highway" corridor
Production Java Implementation
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
public class LangtonsAnt {
public enum Orientation {
RIGHT(0, 1),
DOWN(1, 0),
LEFT(0, -1),
UP(-1, 0);
public final int dRow;
public final int dCol;
Orientation(int dRow, int dCol) {
this.dRow = dRow;
this.dCol = dCol;
}
public Orientation turnRight() {
return values()[(ordinal() + 1) % 4];
}
public Orientation turnLeft() {
return values()[(ordinal() + 3) % 4];
}
}
public static class Position {
public final int row, col;
public Position(int row, int col) {
this.row = row;
this.col = col;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Position)) return false;
Position pos = (Position) o;
return row == pos.row && col == pos.col;
}
@Override
public int hashCode() {
return Objects.hash(row, col);
}
}
public static class AntSimulation {
private int row = 0;
private int col = 0;
private Orientation orientation = Orientation.RIGHT;
private final Set<Position> blackCells = new HashSet<>();
private int minRow = 0, maxRow = 0;
private int minCol = 0, maxCol = 0;
public void step() {
Position currentPos = new Position(row, col);
if (blackCells.contains(currentPos)) {
blackCells.remove(currentPos);
orientation = orientation.turnLeft();
} else {
blackCells.add(currentPos);
orientation = orientation.turnRight();
}
row += orientation.dRow;
col += orientation.dCol;
// Expand dynamic bounding box
minRow = Math.min(minRow, row);
maxRow = Math.max(maxRow, row);
minCol = Math.min(minCol, col);
maxCol = Math.max(maxCol, col);
}
public void simulate(int k) {
for (int i = 0; i < k; i++) {
step();
}
}
public String printBoard() {
StringBuilder sb = new StringBuilder();
for (int r = minRow; r <= maxRow; r++) {
for (int c = minCol; c <= maxCol; c++) {
if (r == row && c == col) {
sb.append(orientation.name().charAt(0)); // Ant location
} else if (blackCells.contains(new Position(r, c))) {
sb.append('X'); // Black square
} else {
sb.append('_'); // White square
}
}
sb.append('\n');
}
return sb.toString();
}
}
}
Complexity Analysis
| Metric | Complexity | Technical Detail |
|---|---|---|
| Time Complexity | O(K) |
$K$ steps each performing $O(1)$ amortized hash set operations. |
| Auxiliary Space | O(K) |
Stores at most $K$ active black cell coordinates. |
| Memory Overhead | Sparse |
Eliminates wasted matrix allocation for unvisited infinity. |
Real-World Systems Engineering Discussion
Production Systems Architecture: Cellular Automata & Spatial Hashing
- Turing Completeness: Langton's Ant is a proven Universal Turing Machine capable of simulating arbitrary computation via carefully placed initial obstacle configurations.
- Sparse Spatial Hashing in Game Physics: Physics engines (Havok / Box2D) manage collision boundaries in open-world terrains using sparse coordinate hash maps rather than dense 2D arrays.
Edge Cases & Production Hardening
- $K = 0$: Prints initial board containing single ant position
R. - Negative Coordinates: Handled transparently by
Position(row, col)hash hashing and dynamic bounding box tracking.
