Wave Function Collapse
Wave Function Collapse: Shannon Entropy Selection: Wave Function Collapse (WFC) synthesizes seamless procedural tile assemblies from small exemplar rules. Every cell begins in quantum-like superposition of all possible states. At each iteration, the algorithm finds the uncollapsed cell with minimum Shannon entropy and collapses it to a single state according to relative pattern frequencies.
Entropy Minimization Principle:
1import math23def calculate_shannon_entropy(cell_possibilities, tile_weights):4 """5 Computes Shannon entropy for an uncollapsed cell in Wave Function Collapse.6 H = log(sum_w) - (sum(w * log(w)) / sum_w)7 Lowest entropy cells are prioritized for collapse to minimize backtracking.8 """9 total_w = sum(tile_weights[t] for t in cell_possibilities)10 if total_w == 0 or len(cell_possibilities) <= 1:11 return 0.0 # Already collapsed or contradictory1213 sum_w_log_w = sum(tile_weights[t] * math.log(tile_weights[t]) for t in cell_possibilities)14 return math.log(total_w) - (sum_w_log_w / total_w)
Wave Function Collapse: Constraint Propagation (AC-3): Once a cell collapses, its decision cascades outwards. Using socket-matching adjacency rules, any option in an adjacent cell that cannot legally connect is pruned. If that cell's options shrink, the pruning continues recursively, propagating the wave until all remaining superpositions satisfy local consistency.
Arc-Consistency Propagation:
1def propagate_wfc_constraints(stack, wave, adjacency_rules):2 """3 Constraint propagation loop (AC-3 style arc consistency).4 When tile possibilities are removed from cell (x, y), check all 4 neighbors.5 Prune any neighbor tile that has zero valid connectors to the current cell.6 """7 directions = [(0, 1), (0, -1), (1, 0), (-1, 0)] # N, S, E, W89 while stack:10 cx, cy = stack.pop()11 current_options = wave[cy][cx]1213 for dx, dy in directions:14 nx, ny = cx + dx, cy + dy15 if not in_bounds(nx, ny):16 continue1718 neighbor_options = wave[ny][nx]19 legal_tiles = set()20 for t in current_options:21 legal_tiles.update(adjacency_rules[t][(dx, dy)])2223 # Intersect possibilities24 pruned = neighbor_options - legal_tiles25 if pruned:26 wave[ny][nx] -= pruned27 stack.append((nx, ny)) # Propagate ripple outwards