The last ALIVE post ended on an open question: the defences were built and they fired, and a world still ground a hundred people down to a handful inside a decade. Hard, or broken? It should be decided with numbers rather than a feeling. This is that judgement, plus a second update later the same day.
It was broken. Four separate faults, three of them hard logic errors rather than balance.
The seed never meant anything
This one comes first, because until it was fixed no measurement here could have been trusted, including the ones in the last post.
The game shows a seed on the setup screen and offers to save a run. Both promise that a world is a fixed thing. It was not. The same seed and options, run three times, gave three different worlds.
| same seed, same options, three years | alive at the end |
|---|---|
| run one | 60 |
| run two | 109 |
| run three | 33 |
The wandering of critters was drawn from Math.random() instead of the world's own seeded stream: four calls, in the block that decides how long an animal rests, which way it turns and whether it moves at all. That would be harmless if critters were scenery. Wolves are critters. Where a wolf wanders decides who it notices and who runs from it, so an unseeded number walked into the simulation and came out the other side as a death. It had been there long enough to invalidate every A/B comparison ever run on this game.
The fix was the seeded stream already in scope two lines above. Three runs of one seed are now identical down to the last state of the random number generator. It also means the background sim on the title screen, which runs for as long as you sit on the menu, can no longer change the world you then start.
Being hungry prevented eating
This was killing every world, and it is four lines long.
A task that is not self-care is abandoned the moment the person is hungry. That is right for a woodcutter, who should not keep chopping while starving. But foraging, hunting, fishing and farming were not on the self-care list, because going to get food is not, on its face, looking after yourself.
So a hungry person decided to forage, took one step toward the berries, noticed they were hungry, dropped the task, decided to forage, took one step, and kept doing that until they starved standing in a berry patch. A closed loop: being hungry prevented the only act that ends hunger.
| one year, ~120 people | before | after |
|---|---|---|
| food-gathering tasks started | 326,077 | 24,956 |
| harvests that reached a berry | 254 | 514 |
| units of food gathered | 497 | 1,226 |
| attempts per person per year | ~2,860 | ~200 |
Two thousand eight hundred attempts per person per year, and one in thirteen hundred produced anything. Meanwhile the map held three thousand units of berries and the total was going up, because regrowth was outpacing a harvest that was not happening.
Hunger no longer interrupts the work that answers hunger. Thirst, cold, wounds, terror and the sixteen-hour task limit all still do, so nobody farms their way through a bear attack.
Dying of thirst with water one tile away
Thirty-three of thirty-five deaths by thirst, and thirty-nine of forty by starvation, happened while the person's action read "eating". Not walking to eat, not looking for food. Eating. The nearest open water was on average one tile away.
Three faults in one behaviour:
- A meal is five units and the stores were consulted at half a unit. Ninety people would set off across town for a granary holding twenty-five; four would eat and eighty-six would arrive at nothing.
- Everyone could see the same number and everyone believed it was theirs. In year two, fifty-one of fifty-three survivors were on the eat task and two were foraging. They were never short of food. They were short of anybody going to get it. A person now walks to the stores only if a meal is left once everybody already walking there has taken theirs, and the claim is taken the instant the walk starts, because a town decides all at once and a count that refreshes even slightly late lets the whole crowd through.
- Hunger outscored thirst right up until the moment thirst killed, and self-care was never interrupted by anything, including more urgent self-care. A body about to die of thirst now drops whatever else it is doing.
| year two of one world | before | after |
|---|---|---|
| on the eat task | 51 | 8 |
| foraging | 2 | 39 |
| hunting | 2 | 34 |
| alive | 53 | 77 |
The land could not have fed them anyway
With the labour fixed, the arithmetic still did not close. A year is ninety-six game hours. Berries regrew at 0.090 an hour against a cap of twenty-two, so a stripped patch took nearly three years to fill, and the whole map produced about 1,450 units a year while a hundred and twenty people needed something over three thousand. No arrangement of labour closes a gap like that.
It is the same error found in the trees, which sat at 0.055, about six years to regrow a wood, until they were corrected to 0.190 in an earlier update. The berries and fish were left behind. Berries now sit at 0.230 and fish at 0.190, which puts a patch back to full in roughly a year with the seasons averaged in.
Foragers were also being sent to any tile holding at least one unit, so somebody would cross the valley for a single berry. The measured return was 2.4 units for a trip that could have carried nine. They now look for a patch worth the walk first, and settle for scraps only when nothing better is within reach, which is also the signal that the land around them is finished.
What it adds up to
Before any of this, twenty-four worlds were run for fourteen years each, across four shapes and three map sizes, at high drama and monster settings. All twenty-four ended with between zero and six people alive.
| three worlds, twelve years, 360 souls | before | after |
|---|---|---|
| born | 41 | 97 |
| alive at the end | 0 | 18 |
| deaths by starvation | 127 | 187 |
| deaths by thirst | 50 | 0 |
Starvation goes up in that table and that is not a mistake: more people now live long enough to reach the mid game and starve there instead of dying in year two. The honest measure is the population curve.
| one world, people alive | before | after |
|---|---|---|
| year 1 | 97 | 126 |
| year 2 | 34 | 119 |
| year 3 | 5 | 121 |
| year 4 | extinct | 123 |
| year 5 | extinct | 118 |
| year 6 | extinct | 96 |
| year 8 | extinct | 30 |
A town now holds its full strength through its fourth year instead of collapsing in its second. It still declines after year six, and that is stated plainly rather than dressed up: the job is not finished.
A change that did not ship
Fields are guaranteed only up to three, after which they have to win their turn against housing, walls and libraries, one build in six. A town of a hundred and twenty had fifteen fields in its eighth year. The obvious fix is to let fields keep pace with mouths: a hungry people builds a field before anything else, up to one per three people.
It was written, and it made things worse.
| one world | without | with fields-for-mouths |
|---|---|---|
| alive, year 3 | 121 | 115 |
| alive, year 4 | 123 | 57 |
| hungry (over 76), year 3 | 4 | 55 |
Pushing fields to the front of the queue starves everything else, the granary that stops food spoiling and the huts that let people sleep, and the town falls over two years earlier. It was reverted. A fix that was measured and rejected is worth as much as one that worked, and the next attempt at the mid-game decline should not start by trying it again.
Other things found and fixed
Nothing could sink a ship. The sea serpent and the devourer from the deep looked only for people, so they swam past a fishing fleet to bite somebody on the beach. The sinking code only ever ran when an entire people went extinct, which meant the hulls, armour and guns on all ten ship classes were decoration. A sea beast now hunts hulls as readily as people, anything with guns fires back, and a holed ship runs for port and is repaired there out of the tribe's timber.
A fleet vanished on save and load. Ships were added after the save format was written, so a people with ten hulls in the water loaded back into an empty harbour. The format is now version 4 and carries the fleet; version 3 saves still load, checked against a real one in the browser rather than assumed.
Panels were blank while paused. The Discoveries, Tribes and Soul panels were filled in only from the simulation's own tick, which does not run when the game is paused. Opening Discoveries while paused, exactly when you would read it, showed an empty panel and went on showing one. A panel now paints itself the moment it is opened.
How these were found
Three of the four big faults were invisible from inside the game, because the game is carefully written not to crash. Errors are swallowed in eight places so that a bad frame can never take the page down, which is right, and also means a fault can run every tick for years without a word appearing anywhere. The test runs now rewrite each of those catch blocks so anything swallowed is counted and its stack kept. Twenty-four worlds for fourteen years, and nine hundred rendered frames across four zoom levels with one of every structure and all ten ships on screen, report zero swallowed exceptions.
The starvation spiral was found by counting task starts against harvests. Nothing about 326,077 attempts and 254 results is visible on screen; it looks like people milling about, which is what a simulation of people looks like.
One measurement along the way was wrong. An early death census wrapped the kill function to count causes and dropped its third argument, the killer, while passing the call through. That silently changed the run it was measuring and halved the birth rate. The instrument has to be checked as carefully as the thing it is pointed at.
The second update: people, speed, and the hunt
The people look like peoples
There were eight skin tones, dealt at random one per person with no relation to anybody standing nearby. Random is not the same as varied. A settlement came out as noise, children looked nothing like their parents, and because the palette ran from very light to a mid brown and stopped, a crowd read as one lightly freckled people.
There are now twelve complexions, ordered lightest to deepest. The order is the substance of the change, not the count: a tone is carried as a position on a ladder rather than as a swatch, which is what lets it be inherited, averaged between two parents and drifted a little each generation. An unordered list of colours cannot do any of that.
- Each people has a heritage, and everyone born among them is drawn around it, so two peoples meeting on a shore look like two peoples.
- A child takes after its parents rather than the crowd: the mean of the two, with a rung of drift. Where peoples mix, their descendants mix.
- Hair follows complexion. Fair and red belong at the light end and black hair belongs everywhere. Dealt flat at random, it put pale blonde hair on every complexion in equal measure and the crowd read as costume.
Measured on a four-tribe world of two hundred: ten of the twelve complexions in use across the map, and every tribe internally coherent, one people spanning rungs zero to four and another nine to eleven.
The tribe namer crosses an adjective with a word for a group, and its adjective list held Black, White, Pale and Red while the group list held Sons, Daughters, Kin and Bloods. It produced exactly what that combination produces. Those four are gone, replaced in the same register with words like Quiet, Standing, Riven, Storm and Tide. Nothing left in the list describes a person; ash, iron, salt, stone and frost describe the country they live in. Five hundred generated names were checked and none uses a word for skin.
10x stopped keeping up
Reported from play: at ten times speed the days stopped turning. It was not a bug in the loop. The simulation was too slow to run at 10x, and had been getting slower as worlds got bigger.
| cost of one 0.1s step | before | after |
|---|---|---|
| 122 people | 13.7ms | 9.7ms |
| 300 people | 65.7ms | 11.5ms |
| 600 people | 431ms | 102ms |
At 10x a step has to run every ten milliseconds, and at 122 people one step already cost more than a whole frame. The shape of the first column is the tell: two and a half times the people cost nearly five times the work, and five times the people cost thirty-one times the work. Something was quadratic.
Separation ran off the neighbour grid, which has 64-pixel cells because that is right for "who can I see" queries at ranges of ninety to three hundred and eighty. Personal space is six pixels. A hundred people in a village occupy a handful of those cells, and a hundred people in one cell is five thousand pair checks for the sake of a six-pixel push. Separation now has its own ten-pixel grid, larger than the six it needs so no pair that matters can fall between cells, and the sweep visits occupied ground only. The old one walked every cell of the world whether anyone stood in it or not, over a hundred thousand empty cells a tick on the Vast map.
A latent hole closed during the rewrite: the old neighbour scheme visited right, down and down-left and never down-right, so one diagonal was skipped entirely. Almost unobservable at 64 pixels, a real gap at ten.
The loop is also honest about what it can do now. The simulation budget was a flat 9.5ms whatever speed was asked for, and the renderer got a frame whether or not the clock was keeping up, so at 10x on a crowded world the picture was redrawn sixty times a second while the days barely moved. Asking for 10x is asking for time to pass, not for frames. The budget now scales with speed, and when the backlog is real the frame goes to the world instead of the screen, never twice in a row, because a frozen picture is worse than a slow one.
The hunt was never finished
Hunting had been asked for as a feature, and nearly all of it was already there. Every part except the end.
A person picked the nearest deer, ran it down over as much as thirty seconds, arrived, and fell through to the default branch of the work switch, which ends the task with the word "wandered". The animal was never struck, never killed, and no meat ever came home.
The proof is in a table. CRITTER carries a food value for every animal (a deer is thirty, a boar twenty-six, a hare ten) and nothing in the codebase had ever read it. Hunting is one of the two things a hungry person falls back on when the stores are empty, so a large share of the food labour in every run had gone into chasing deer around a field for nothing.
- The kill is not one roll. A hunter closes and strikes, the animal bleeds and bolts, and it is run down again. A boar and a wolf can turn on the hunter. What comes down is carried home like a harvest.
- A slain beast is butchered, scaled to its size. Killing a bear used to earn prestige, a memory and a party, and no dinner.
- The herds breed back. Wildlife replaced itself at one animal every six game hours, ample while nothing died. With the hunt working, a map was stripped to fifteen animals inside four years. A hunted country now breeds back harder the emptier it gets. It is still nowhere near enough to feed a town on meat alone, which is right: hunting is a supplement and a dangerous one. The fields are the living.
What the numbers say, and what they do not
Three worlds, twelve years each, 360 souls, against the same run from the earlier update.
| cause of death, three worlds | earlier | v1.3 |
|---|---|---|
| starvation | 187 (41%) | 157 (34%) |
| thirst | 0 | 1 |
| old age | 20 | 37 |
| killed by another person | 98 | 97 |
| the light in the sky | 83 | 93 |
| total deaths | 454 | 462 |
Starvation is down about a sixth and deaths from old age have nearly doubled. That second number is the one worth pointing at, because dying old is what happens when the other things stop killing you first. Total deaths are flat, so what has shifted is how people die, not yet whether the world survives.
Two things the table does not say. Births and final population are missing because the capture of that run was truncated before the header and was not re-run. And the run predates the herd-recovery change, so it measures a world where hunting had already stripped the map bare. The effect of the hunt as it now ships is unmeasured.
Three of the four faults in the second update were of the same kind: the hunt that never killed anything, the food value nothing read, the separation grid at ten times its working range. None of them throw, none of them log, and all of them look completely normal on screen. They were found by counting: task starts against harvests, milliseconds against population, food values against the code that reads them.
