In Arrow Sweep the par is a number an exact solver has proven, not a guess. A dev note on how the solver finds the fewest taps, how it filters boards, and where hints and stars come from.
At the top of every Arrow Sweep board there are two numbers: Taps and Par. Clear the board in par taps or fewer and you get three stars. But if par were an estimate, three stars would be a shaky reward. A shorter route might be hiding somewhere, and the player who finds it would be right to feel cheated.
So the JWorld team computes the par of every board with an exact solver. This note explains how that solver works, where it is used when boards are made, and why we threw out a rule it could not handle. All numbers come from the game's source and design notes.

The problem the solver has to solve
Quick reminder of the rules. Tap an arrow and it slides in the direction it points. Every arrow in front of it is shoved along and leaves the board too. One tap removes the arrow you tapped plus everything it sweeps. Arrows that stay never move, so the state of a board is just which arrows remain.
That one property makes the solver practical. A board has at most 30 arrows, so the set of remaining arrows fits in a bitmask: one 32-bit integer with a bit per arrow. The problem becomes:
- Start: every bit on.
- One tap: switch off the bits of the tapped arrow's sweep set.
- Goal: switch everything off in the fewest taps.
Tapping every arrow once always clears a board, so par is never more than the number of arrows, n. The solver's job is to find out whether anything shorter exists.
Three tools inside the solver
The solver is an iterative-deepening search. It first asks "can this board be cleared in 6 taps?". If not, it asks about 7, then 8, and so on. The first budget that works is the par. Three tools keep it fast:
| Tool | What it does |
|---|---|
| Lower bound | Estimates the fewest taps still needed, so hopeless branches are dropped at once |
| Memory table | Each set of remaining arrows is judged once; earlier rounds store "this position needs at least k more taps" |
| Biggest sweep first | Tries the taps that clear the most arrows first, and skips taps that lead to the same position |
The lower bound uses two arguments:
- Must-tap arrows. An arrow that lies in nobody else's sweep can only leave by being tapped itself. Each of those costs at least one tap.
- Sum of the biggest sweeps. k taps press k different arrows, so they can remove at most the k largest sweep sizes added together. Add sizes from the biggest down until the total reaches the number of arrows left; that count of taps is the bound.
There is one subtle point. As arrows leave, the sweeps of the arrows that remain can only shrink. So a sweep measured on today's board is an upper limit for every board that follows, and reusing the parent board's measurements for its children is safe. Frozen arrows are the catch: they thaw later and may then sweep a lot. The first prototype counted only tappable arrows in the bound, and on 3 of 400 random frost boards it reported a par higher than the true one. The shipped solver counts frozen arrows too.
How do we know it is exact?
"Exact" means nothing without checks. These are the ones recorded in our design notes:
- The fast engine was compared with a slow step-by-step simulator on 2,262 random taps, with 0 mismatches.
- Two different solvers (the iterative-deepening one and a plain breadth-first search) gave the same par on 40 small boards.
- Replaying the solver's tap list from the start clears the board in exactly par taps, which earns three stars. This test covers every stored board.
- One command,
npm run check-levels, re-solves all stored boards and checks par and hint again: 146 campaign boards, 4 tutorial boards and 730 Daily boards, which makes 880 boards in total. It takes about 3 seconds.
If a single board disagrees, the check fails. When we add boards or touch the rules, a par cannot drift quietly.
Using the solver as a filter
The solver does more than print a number. It is also a sieve for new boards. Every randomly generated candidate has to pass a 12-step filter chain, cheap checks first and the exact solve near the end:
| Step | Check | Why |
|---|---|---|
| 1–2 | Arrows do not overlap; tethered pairs cannot collide | A valid board |
| 3 | Lower bound inside the world's par band | Cut candidates before solving |
| 4 | Taps of the greedy bot (always taps the biggest sweep) | An upper bound for par |
| 5 | Exact par from the solver | The three-star target |
| 6 | Par band and par-to-arrows ratio per world | Difficulty curve |
| 7 | Trap rule: greedy taps > par | A reason to think |
| 8 | A naive bot (taps arrows in reading order) must miss two stars | Two stars should mean something |
In the design experiments, the cheap checks removed 71–80% of candidates in worlds 4 and 5 before any exact solve, so an accepted board needed at most 4.8 exact solves. Even for the biggest boards (world 5) the exact solve had a median of 5.4 ms, a 95th percentile of about 65 ms and a slowest case of about 1.2 seconds in the same experiment.
The trap rule matters most. On random world-5 boards the greedy bot hit par only about half the time. Because the solver knows the true par, we can deliberately keep boards where "always tap the biggest sweep" costs an extra tap, so planning ahead beats reflex.

Rules the solver could not handle were dropped
We tested candidate rules with the solver before building the game. Three were compared:
| Candidate rule | Solver result | Decision |
|---|---|---|
| Tapped arrow slides to the first blocker, shoves it one cell and stops | On all 40 test boards par was at least n. Shoving never saved a tap, so the rule was decoration | Dropped |
| The sweep rule we ship | Par below n on 93% of tiny 5×5 boards; on real world boards par is roughly 0.35–0.75 of n | Adopted |
| Sweep plus pits that swallow arrows | Surviving arrows move, so the state becomes positions; 8 of 12 world-5 boards hit the 400,000-node limit | Dropped |
With pits the median solve time jumped from 0.5 ms to 303 ms. Speed was not the real reason. The rule we kept had to let us prove the par. Frost and tether survived because surviving arrows still never move.
What the solver does inside the game
The solver is not only on the builder's side. The in-game Hint is the same solver, run again from the current position, and it lights up the next best tap. Whatever state you are in, following hints ends at "taps so far plus the fewest still needed".
Stars come from par too:
| Stars | Condition |
|---|---|
| 1 | Clear the board |
| 2 | Taps ≤ par + max(2, par ÷ 4 rounded up) |
| 3 | Taps ≤ par |
Net taps subtract the ones you undid. Undo and Restart are free, so trying a move and taking it back costs nothing. The first hint keeps your stars, but as the result screen says, from 2 hints it is 2 stars max, so an ad cannot buy a third star. Show the 3-star way on the result screen replays the same optimal solution.
Summary
- Par is not an estimate. It is the fewest taps proven by an exact solver.
- With at most 30 arrows and arrows that never move once they stay, a board's state is one bitmask.
- The solver combines iterative deepening, a lower bound, a memory table and biggest-sweep-first ordering.
- All 880 stored boards (146 campaign, 4 tutorial, 730 Daily) are re-solved by
check-levelsto verify them. - The solver also acts as a sieve: it keeps "trap" boards where the greedy bot loses a tap.
- A rule the solver could not handle (pits) was dropped for correctness before fun.
- Hints and star limits come from the same solver, so matching par means you really found the shortest way.
Want to test it yourself? Play on the web. If you cleared a board in par taps, no shorter route exists. The game's page is /en/apps/hwasal/.
Written by the JWorld team from our game design documents and measured play data, with AI tools helping with the writing.