Freeform Strategy
Densest Crossings
Builds a graph of word connections and prioritizes the most interconnected words.
This strategy treats your word list as a graph problem. Each word is a node, and two words are connected by an edge if they share at least one letter, meaning they could potentially cross in the grid.
The placement order is then derived from this graph: start with the most connected word (the one that could cross the most other words), and at each step add the unplaced word that has the most connections to words already on the grid.
By clustering interconnected words together in the placement order, the greedy placer is much more likely to find positions where a new word crosses multiple existing words simultaneously, producing denser layouts than naive ordering.
Strengths
- ✓Tends to produce high intersection counts among user-word-only strategies, particularly on word lists with rich letter overlap
- ✓Connectivity-aware ordering surfaces non-obvious crossings between words that would be difficult to find manually
- ✓Places the most words on average, since highly connected words are tried first and rarely fail to find a valid position
Weaknesses
- !Less effective when words have few shared letters (sparse compatibility graph), falling back to essentially random ordering for disconnected nodes
- !Can produce less compact grids than Longest First, since high-degree seed words may be short and create a small initial grid that subsequent words extend outward
How It Works
- 1
Build the compatibility graph
For every pair of words (A, B), count how many distinct letter positions could line up if they crossed. If they share at least one letter, add an edge in the graph weighted by the number of crossing options. This is a one-time O(W² × L²) preprocessing step.
- 2
Pick the seed word
Find the word with the highest degree (most edges to other words). On the first attempt, ties are broken by word length. On subsequent attempts, the seed is randomized among the top-third highest-degree nodes to produce diverse layouts.
- 3
Iteratively add the most connected unplaced word
At each step, score every unplaced word by how many edges it has to already-placed words. Pick the highest scorer (with shared-letter count and small randomness as tiebreakers). This naturally builds tight clusters of compatible words.
- 4
Hand the ordering to the greedy placer
Once the order is determined, the standard greedy placer takes over: place each word at the position that maximizes intersections with existing words on the grid. The graph-guided ordering ensures these greedy choices produce denser results than longest-first or random ordering.
Pseudocode
function graphGuidedOrder(words, graph):
picked = {}
order = []
// Step 1: pick seed (highest degree)
seed = argmax(words, w => degree(w in graph))
order.append(seed)
picked.add(seed)
// Step 2: greedily add most-connected unplaced word
while picked.size < words.size:
best = null
bestScore = -1
for w in words \ picked:
edgesToPicked = count(edge in graph[w] where edge.other in picked)
score = edgesToPicked × 10000 + sharedLetterTotal(w) × 100
if score > bestScore:
best = w
bestScore = score
order.append(best)
picked.add(best)
return orderComplexity
Graph build: O(W² × L²) where W = word count, L = average word length. Ordering: O(W² × E) where E = average edges per word. For typical lists (10–50 words), this is microseconds.
Benchmark Results
Measured locally on three wordlist scenarios. Each cell is averaged across 3 runs of 16 attempts each. Best= top layout's metric. Compactness = grid area per placed word (lower is denser).
| Scenario | Best × | Avg × | Placed | Compactness | Time |
|---|---|---|---|---|---|
Themed (9 words) Short personal wordlist with low letter overlap, typical of user input. | 9 | 8.25 | 9/9 | 11.56 | 1.3ms |
Vocabulary (40 words) Common 5-letter English words with high letter overlap. | 41 | 40.5 | 40/40 | 19.2 | 17.6ms |
Mixed (156 words) Mixed-length English words (3–8 letters), broad coverage. | 157 | 156.25 | 153/156 | 10 | 317.6ms |
★ Best across all four strategies on this scenario. Reproducible via scripts/benchmark-strategies.ts.
Metric Definitions
Each benchmark run executes 16 randomized attempts of the strategy and returns up to 4 distinct layouts, sorted by quality. This process is repeated 3 times to reduce variance. The metrics below describe how each column is derived from those runs.
- Best ×
- The highest intersection count from the top-ranked layout across 3 independent runs. An intersection is a grid cell shared by two words (one across, one down). Higher is better.
- Avg ×
- The mean intersection count across all returned layouts (up to 4 per run), averaged over 3 runs. This includes second- through fourth-best layouts, so it reflects consistency rather than peak performance.
- Placed
- The most words placed on the grid in any top-ranked layout. For Adjacency-Aware, this includes dictionary fill words from Phase 2, so it can exceed the input word count. Shown as placed/input.
- Compactness
- Grid bounding-box area (rows times columns) divided by the number of placed words. Lower values indicate denser packing. Note that this measures the full bounding box, which includes empty cells between words. Adjacency-Aware's denominator is inflated by fill words.
- 2-Letter Frags
- The number of 2-letter contiguous letter runs in the best grid that are not covered by any placed word in that direction. These are perpendicular fragments left behind by parallel placements that Phase 2 could not extend into complete dictionary words. Only applicable to adjacency strategies; always 0 for other strategies since they never place words in parallel.
- Fill Words
- The number of dictionary words added in Phase 2 to extend 2-letter gaps into complete words. These are not from the user's word list. Capped at max(3, 75% of user word count). Only applicable to adjacency strategies.
- Time
- Wall-clock time for one run (16 randomized attempts), averaged across 3 runs. Measured in single-threaded JavaScript without Web Workers. Includes ordering, candidate enumeration, validation, and (for Adjacency-Aware) Phase 2 gap filling.
Comparative Performance
All four strategies measured side-by-side on the same word lists and hardware. Rows highlighted in blue indicate the strategy being viewed.
Themed (9 words)Short personal wordlist with low letter overlap, typical of user input.
| Strategy | Best × | Avg × | Placed | Compact | Frags | Fill | Time |
|---|---|---|---|---|---|---|---|
| Adjacency-Aware | 16 | 15 | 12/9 | 6 | 0 | 3 | 125.9ms |
| Parallel-Seeded | 20★ | 18.75 | 14/9 | 5★ | 2 | 5 | 128.8ms |
| Densest Crossings | 9 | 8.25 | 9/9 | 11.56 | 0 | 0 | 1.3ms |
| Longest First | 8 | 8 | 9/9 | 8.56 | 0 | 0 | 1.2ms★ |
| Balanced | 9 | 8.25 | 9/9 | 15.89 | 0 | 0 | 1.4ms |
Vocabulary (40 words)Common 5-letter English words with high letter overlap.
| Strategy | Best × | Avg × | Placed | Compact | Frags | Fill | Time |
|---|---|---|---|---|---|---|---|
| Adjacency-Aware | 99★ | 90.25 | 69/40 | 7.71★ | 10 | 29 | 781.9ms |
| Parallel-Seeded | 96 | 93.5 | 68/40 | 11.03 | 11 | 28 | 901.6ms |
| Densest Crossings | 41 | 40.5 | 40/40 | 19.2 | 0 | 0 | 17.6ms |
| Longest First | 42 | 40.25 | 40/40 | 15.95 | 0 | 0 | 14.8ms★ |
| Balanced | 41 | 40.5 | 40/40 | 15.6 | 0 | 0 | 19.6ms |
Mixed (156 words)Mixed-length English words (3–8 letters), broad coverage.
| Strategy | Best × | Avg × | Placed | Compact | Frags | Fill | Time |
|---|---|---|---|---|---|---|---|
| Adjacency-Aware | 312★ | 300.5 | 228/156 | 7.01★ | 35 | 72 | 5129.8ms |
| Parallel-Seeded | 306 | 292.75 | 228/156 | 8.6 | 24 | 72 | 5230.4ms |
| Densest Crossings | 157 | 156.25 | 153/156 | 10 | 0 | 0 | 317.6ms |
| Longest First | 158 | 153.25 | 151/156 | 10.33 | 0 | 0 | 78.6ms★ |
| Balanced | 161 | 157.25 | 156/156 | 12.38 | 0 | 0 | 306.8ms |
Analysis
The four strategies share the same underlying greedy placement algorithm but differ in word ordering and, in the case of Adjacency-Aware, in which placements are considered valid. This means performance differences stem from two factors: the cost of computing the ordering, and the size of the candidate set evaluated per word.
Graph-guided, Balanced, and Longest First operate exclusively on the user's word list. Their placement pass considers only perpendicular intersection candidates (positions where a new word crosses an existing word at a shared letter). Longest First skips the graph-build step entirely, making it the fastest strategy in every scenario. Graph-guided and Balanced are similar in cost because they both compute the compatibility graph; Balanced adds a minor constant factor for its hybrid seed selection.
Adjacency-Aware adds two sources of overhead. First, each word's candidate set is larger because parallel placements (same direction, offset by one row or column) are enumerated alongside perpendicular intersections. For a word of length L placed beside an existing word of length P, this adds up to 2 × (L + P - 1) additional candidates per pair. Second, every candidate undergoes perpendicular-run validation against the dictionary, which requires walking the grid in the perpendicular direction at each cell. Phase 2 (gap filling) adds a third cost: scanning for 2-letter fragments and searching dictionary buckets for valid extensions.
The practical impact scales with word count. On a 9-word themed list, the adjacency strategies run in roughly 126-129ms versus 1.2ms for Longest First (approximately 100x slower). On 156 words, the gap narrows to roughly 65x (5.1-5.2s versus 79ms). The overhead comes from dictionary validation of perpendicular runs, parallel candidate enumeration, and gap filling.
An important caveat applies when comparing intersection counts across strategy types. The adjacency strategies' reported intersections include crossings involving dictionary fill words. For the mixed-large scenario, Adjacency-Aware places 228 total words (156 user + 72 fill) and reports 312 intersections, while Densest Crossings places 153 user words and reports 157 intersections. Some portion of the intersection difference is attributable to the additional fill words, not to more efficient placement of the original word list.
The 2-letter fragment count reveals an inherent tradeoff of parallel placement. Every pair of words placed side-by-side creates perpendicular 2-letter runs that must either be extended into dictionary words or left as fragments. Inline gap filling (used by both adjacency strategies) mitigates this by resolving gaps immediately after each parallel placement, while surrounding constraints are still loose. Parallel-Seeded reduces fragments by roughly 43% compared to deferred filling on large word lists, producing 24 fragments versus 35 for base Adjacency-Aware on the mixed-large scenario. The remaining fragments are structurally unfillable due to constraints accumulated during grid construction.
The compactness metric (grid area divided by placed words) also requires careful interpretation. Adjacency-Aware tends to produce grids with lower compactness values, which suggests denser packing. However, the fill words extend existing perpendicular runs rather than expanding the grid boundary, so they reduce compactness partly by inflating the denominator without proportionally increasing the numerator. Among the user-word-only strategies, Longest First tends to produce the most compact grids, likely because long anchor words create a tighter bounding box relative to the words they accommodate.
Each strategy was run 3 times with 16 randomized attempts per run. Adjacency-aware loads the full crossword dictionary (~42K words, filtered to 3-8 letters with score >= 60) for perpendicular validation and gap filling; other strategies use only the scenario's word list. Note that adjacency-aware's "placed" count includes dictionary fill words from Phase 2, so its intersection counts are not directly comparable to other strategies, which only place words from the input list.
When to Use This
- •Your word list has many shared letters (vowels, common consonants)
- •You want maximum visual density in the resulting crossword
- •You're building a themed puzzle where related words tend to share letters
Try it
Open the creator with this strategy pre-selected.
Try Densest Crossings→Other Strategies
Adjacency-Aware
Two-phase: places your words with parallel adjacencies, then fills perpendicular gaps with real dictionary words.
Parallel-Seeded
Starts with an optimal parallel word pair, then uses inline gap filling to build dense clusters incrementally.
Longest First
Places longer words first as anchors, then fits shorter words around them.
Balanced
Hybrid: starts with the longest word, then prioritizes connected words.