Wave Function Collapse (WFC)
WFC is a constraint-based algorithm that generates output by collapsing possibilities one cell at a time, ensuring local consistency through constraint propagation.
How WFC Works
Inspired by quantum mechanics, WFC treats each output cell as a superposition of all possible tiles. The algorithm repeatedly selects the cell with the fewest remaining possibilities (lowest entropy), collapses it to a single tile, and propagates constraints to neighbors.
Initialize
Every cell starts in superposition — all tile types are possible. The grid begins in maximum entropy.
Observe
Find the cell with the lowest entropy (fewest remaining options). Collapse it by randomly selecting one tile (weighted by frequency).
Propagate
Remove impossible tiles from neighboring cells based on adjacency constraints. This may cascade to their neighbors.
Repeat
Continue observing and propagating until all cells are collapsed or a contradiction is found.
Handle Contradictions
If a cell has zero possibilities, backtrack or restart with a different seed.
import random from collections import defaultdict class WFC: def __init__(self, width, height, tiles, rules): self.w, self.h = width, height self.tiles = tiles self.rules = rules # {tile: {dir: [valid_neighbors]}} # Each cell starts with all tiles possible self.grid = [[set(tiles) for _ in range(width)] for _ in range(height)] def lowest_entropy_cell(self): min_entropy = float('inf') candidates = [] for y in range(self.h): for x in range(self.w): entropy = len(self.grid[y][x]) if 1 < entropy < min_entropy: min_entropy = entropy candidates = [(x, y)] elif entropy == min_entropy: candidates.append((x, y)) return random.choice(candidates) if candidates else None def collapse(self, x, y): tile = random.choice(list(self.grid[y][x])) self.grid[y][x] = {tile} self.propagate(x, y) def propagate(self, x, y): stack = [(x, y)] while stack: cx, cy = stack.pop() for dx, dy, direction in self.neighbors(cx, cy): nx, ny = cx + dx, cy + dy changed = False for tile in list(self.grid[ny][nx]): if not self.is_compatible( tile, self.grid[cy][cx], direction): self.grid[ny][nx].discard(tile) changed = True if changed: stack.append((nx, ny)) def run(self): while (cell := self.lowest_entropy_cell()): self.collapse(*cell) return self.grid
WFC Variants
| Variant | Input | Best For |
|---|---|---|
| Simple Tiled | Tile set + adjacency rules | Level generation, tile maps, building layouts |
| Overlapping | Example image | Texture synthesis, pattern replication from samples |
| 3D WFC | 3D tile set + rules | Voxel worlds, 3D building generation |
Applications in Games
- Tile-based levels: Generate 2D levels that respect tile connectivity rules (roads connect to roads, walls connect to walls).
- City layouts: Generate building blocks, road networks, and neighborhoods that look coherent.
- Texture synthesis: The overlapping model can synthesize large textures from small example images.
- Interior decoration: Place furniture and props in rooms following spatial rules.
- Sudoku-like puzzles: WFC is fundamentally a constraint satisfaction solver, applicable to any problem with local adjacency rules.
Lilly Tech Systems