The score ladder was a triangle

We picked a point value for every merge by hand, one tier at a time, and nobody ever looked at the eleven numbers as a single list. Last week I finally did. The whole thing is a shape from first-year algebra. I did not choose it on purpose. Or maybe I did. I cannot say for sure, and that has been sitting with me all week.

The eleven numbers

A merge is when two pebbles of the same tier touch and become one tier up. Each merge pays a fixed amount of points, stored in a plain array in core.js. Eleven values, one per tier: 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66. Two sand pebbles make a clay pebble and earn 3. The last merge, two garnets into a sunstone, earns 66. That is the entire economy of the game. It fits on a single line of code, and I am still not used to the idea that a whole game can be that small.

I typed these by feel. I wanted a top stone that felt earned and a bottom stone that never felt trivial, and I wanted a slope in between that I could not quite name out loud, something that grew but did not shout, and I wrote the numbers in a note, nudged a couple of them, and pasted the list straight into the source file. No spreadsheet. No plot. No graph. I have no record of what I was thinking, and I am not sure that makes me careless or just the kind of person who trusts a feeling more than a table.

Then I subtracted

What made me finally look was a player question. Someone asked why a big merge does not feel as big as it looks, and I did not have a good answer, so I went to check. I dropped the array into a script and printed the gap between each neighbour. The gaps came out as 2, 3, 4, 5, 6, 7, 8, 9, 10, 11. Each one bigger than the last by exactly one. That is a pattern, and it was not one I remembered making.

That is the signature of the triangular numbers. A triangular number is a pile of dots you can arrange in a perfect triangle: 3 forms a corner, 6 forms three rows, 10 forms four rows, and the rule is n times n-plus-one, all over two. Every number in our array lands on it. Tier 0 pays 1, which is T1. Tier 10 pays 66, which is T11. All eleven fit the rule with nothing left over. The odds of that happening by hand-typing are low, and the longer I stared at it the less comfortable I felt.

What I honestly do not remember

I will not pretend I designed it. I genuinely do not remember the moment I wrote the 6 or the 66. The truth is probably boring: I had the pattern somewhere in my head, maybe from a puzzle I saw years ago, and I kept it because the runs felt right. That is the kind of decision you make with your hands instead of your notes, and the notes never recorded it. So now I am measuring a choice I cannot fully explain. It is either a nice accident or a quiet failure to write down our own rules, and I could be wrong about which one it is.

There is no way to find out. The note where I typed it is gone, and the commit that added the array carries a one-line message that says nothing about intent. I have run out of evidence and I have only my own half-remembered afternoon left.

What the shape does to a run

The part I can measure cleanly is the gap between reward and effort. The points climb linearly, each tier paying a little more than the last in a steady slope, while building a tier is not linear at all, because to make one tier-1 pebble you need two sand pebbles, to make a tier-2 you need four, and every tier up doubles the sand sitting underneath it. By tier 10 you need 1,024 sand pebbles, and you perform 1,023 merges along the way before the crown ever touches the board. Effort doubles. Reward only grows by one more point than the previous tier. That mismatch is the whole feeling of the game.

It keeps the early game moving, because the steps between 1 and 3 and 6 are small and quick and satisfying in a way I could not have engineered by aiming at it directly, and I am quietly proud of that, because it means the shape is doing something real for the player even though I never sat down and designed it to do so. It also keeps the end of a long run from feeling like the entire game happened in one lucky merge, which is the failure mode I was most afraid of when I first picked the numbers. The final merge is worth 66 points. Real points. It is also only about a fifth of the 7,076 points you have already banked by the time you build a clean sunstone from pure sand. The finish is a celebration, not a payout, and I think that is the right balance for a game about patience.

I keep coming back to that 7,076. If you assemble exactly one sunstone, bottom up, wasting nothing, the game hands you 7,076 points across those 1,023 merges, and the last stone is the smallest part of the total by a very wide margin. That felt right when I first ran the script. A great run is long and earned, not one big lucky chain. It also means the top tier is genuinely rare. Most sessions never see a sunstone. I think that is fine.

The number I would change

One place the triangle bothers me. The spawnable band is tiers 0 through 4, and those five stones are deliberately close in size, so a player reads them by colour, not by mass. In that crowded band the points move 1, 3, 6, 10, 15, and the jump from 6 to 10 feels bigger than the jump from 3 to 6 even though both are single steps on the same straight slope. I have considered nudging the low tiers down so the early merges feel smaller and the climb starts slower. I have not done it.

The current numbers are shipped, and a test pins them by checking the fingerprint of a fixed merge log, so changing them would re-value every stored run for a feel difference I have only spotted once. Maybe that is the right call. Maybe it is just that I am lazy. I am not sure which, and the two are harder to tell apart than I would like to admit.

The takeaway is small. Look at your hand-tuned constants as a set, not as a column. Subtract the neighbours. If a shape is hiding in there, it is probably shaping every run you ship, whether or not you chose it. Mine was a triangle. I did not know. Now I do. I am not fully certain that knowing has helped.

← Back to the blog