T: cycle the tileset: CIRCUIT, COAST, KNOTS 1 2 3: speed — 1, 3 or 10 collapses per frame R: restart with a fresh seed The readout shows the tileset, how many of the 384 cells are placed, how many cells the last wave touched — that is the reach of the last propagation, and it is the number worth watching — and how many times a contradiction has forced a restart. That last one stays at zero with the three tilesets shipped here, and the reason turned out to be more interesting than the counter; see below. Run it on 1 at least once. A single collapse in a tight tileset can visibly ripple forty cells away, and the dots shrinking and dimming ahead of it are the constraint propagation.
Wave Function Collapse, solved in front of you. Every cell starts holding all tiles at once; watch certainty spread outward from each collapse across the entropy field until the whole 24 x 16 grid has resolved into one consistent pattern. THE ALGORITHM One step is: find the cell with the fewest tiles left, collapse it to one tile chosen by weight, then propagate — remove from its neighbours every tile that no longer has a compatible partner, and keep going outward until nothing changes. Propagation uses support counts, not re-derivation. The naive version asks, for every tile still possible in a neighbour, whether any tile still possible in this cell is compatible with it. That is O(T²) per edge, recomputed from scratch every time. Instead sup[cell][tile][dir] holds how many tiles in that neighbour currently support that tile here. Banning one tile decrements a fixed, pre-baked list of counters, and a counter reaching zero is exactly the condition for banning another. The whole propagation becomes O(number of removals), which is optimal, and it is how Gumin's original implementation works. The price is a 24,576-entry counter table that has to be rebuilt from nothing on every restart — that is the one visible pause in the project, and it is why the "SEEDING" message exists at all. It has to be shown from a nowarp proc with a wait in it, because everything inside a goboscript func is atomic and can never paint a progress message. The three tilesets define adjacency three different ways, which is the point of having three: | set | tiles | sockets | adjacency density | | --- | --- | --- | --- | | CIRCUIT | 16 | one bit per edge — every subset of the four edges | 0.50 | | COAST | 16 | per corner; two tiles fit if the corners they share agree | 0.25 | | KNOTS | 7 | edges again, but only pass-through and turn tiles | 0.51 | A corner scheme forces diagonal consistency that an edge scheme cannot express, and it is half as permissive. KNOTS drops the dead ends and junctions, and that single omission is what makes its arcs close into loops instead of terminating. Tile weights matter more than they look. CIRCUIT gives the blank board tile a weight of 26 against 2 for the four-way cross; without that the result is wall-to-wall spaghetti with no board left showing. CONTRADICTION — AND THE THING I WAS WRONG ABOUT On a contradiction the run restarts rather than backtracking. Backtracking needs a snapshot of the entire wave at every decision — 6,144 booleans a step for this grid, which is 2.4 million list writes over a full solve. The original algorithm restarts too. I wrote that path expecting it to fire regularly, and set out to quote the rate. It never fires. **Sixty full solves across the three tilesets produced zero contradictions**, twenty per set. That is not luck, and finding out why was the most interesting thing in the project: CIRCUIT is all sixteen subsets of the four edges, so a tiling is nothing more than a free 0/1 labelling of every interior grid edge — whatever the neighbours have already committed to, some tile fits. COAST is all sixteen land/water assignments of the four corners, so a tiling is a free labelling of the corner lattice, by the same argument. Both sets are **contradiction-proof by construction**, and no amount of seeding will ever show otherwise. All original - code, art and sound. See Inside is open.