Run It Until It Dies
The 200-year run
Six years leaves the terrarium looking alive and proves almost nothing. Trees have barely spent their ground, scrub has not fed a second generation on top of the first, and no lineage has grown old. Take the stop out, run 200 years unpaced, print one census per midsummer, and do not tune the model when the census collapses; the collapse is the measurement.
The run needs two more pieces before it can stand on its own. Founding plants must come from a seeded stream instead of a hand-picked list, and old plants must be able to die even when they do not starve in the current tick.
Those two pieces claim streams 10 and 11. Stream 10 governs plant mortality. Stream 11 places the founding generation. The row order fixes which plant spends which draw.
The census tape
A census is three numbers per row per year: how many of that kind are standing, the grams they hold between them, and the grams the average one is holding. The third is the first two divided, and it earns its column. A count and a total can both sit still while the valley moves underneath them; thirty plants at forty grams and thirty plants at four hundred are the same two numbers and two completely different valleys. Every table below prints all three, and by the middle of the run the mean is the only one of them still saying anything.
// internal/terra/valley.go
// Roll is one row's line in a census: how many of that kind are
// standing, the grams they hold between them, and the grams the
// average one is holding. The third number is the first two divided,
// and it is in here rather than left to the caller because a count on
// its own and a mass on its own can both hold still while the valley
// changes underneath them.
type Roll struct {
N int
Mass float64
}
// Mean is the grams one plant of this row is holding, or nothing at all
// when none of them are standing.
func (r Roll) Mean() float64 {
if r.N == 0 {
return 0
}
return r.Mass / float64(r.N)
}
// Take is the census: one Roll per row of the species table, counted in
// the order the stands are held so two runs of one seed add the same
// numbers in the same sequence.
func (v *Valley) Take() []Roll {
out := make([]Roll, len(Flora))
for _, st := range v.Stands {
k := v.rowOf(st)
out[k].N++
out[k].Mass += st.Plant.Mass
}
return out
}
The death sweep at the end of a tick already knew two ways to finish a plant. It now knows three, and it writes down which one it used, because a valley where everything starves and a valley where everything grows old are two different accounts of the same falling count.
live := v.Stands[:0]
for _, st := range v.Stands {
up, _ := st.Kind.Awake(v.Climate, theta)
how := -1
switch {
case st.Plant.Mass < st.Kind.Least:
how = Starved
case st.Kind.Annual && !up:
how = Ended
case v.Wear > 0 && st.Kind.Span > 0 &&
v.luck.Float64() < v.Wear*st.Kind.Hazard():
how = Unlucky
}
if how < 0 {
live = append(live, st)
continue
}
v.Gone[v.rowOf(st)][how]++
v.Bed.Fall(st.At, Pile{Mass: st.Plant.Mass, Nutrient: st.Holds()})
v.Fell += st.Holds()
}
v.Stands = live
Span is a new field on the species row, in years: twelve for the moss,
sixty for the scrub, three hundred for the tree, and nothing at all for the annual,
which has a shorter way of dying already. Hazard turns it into a chance per
tick, one over the ticks in the span, and Wear on the valley multiplies it.
The six-year bench left Wear at zero and drew no numbers at all off stream
10, which is why its output has not moved a bit; a run this long cannot leave it there.
// Found scatters a founding generation over the valley: n seedlings of
// every row, on soil cells drawn from stream 11, refusing a cell that
// already has something on it and refusing to plant anything on rock or
// in the pond. It is the one place in this world where a plant appears
// somewhere nothing put it, and a run founded this way does not depend
// on which handful of cells somebody liked the look of. The rows are
// walked in table order, so who gets first pick of the ground is fixed
// and every seed of the draw is spent even when a cell says no.
func (v *Valley) Found(n int) int {
var soil []sim.Coord
for y := 0; y < v.Grid.H; y++ {
for x := 0; x < v.Grid.W; x++ {
c := sim.Coord{X: x, Y: y}
if v.Bed.Rootable(c) {
soil = append(soil, c)
}
}
}
if len(soil) == 0 {
return 0
}
made := 0
for k := range Flora {
for i := 0; i < n; i++ {
c := soil[v.where.IntN(len(soil))]
if v.Taken(c) {
continue
}
v.Plant(k, c)
made++
}
}
return made
}
Three of every row is twelve draws, and a draw that lands on a taken cell is spent without planting anything, so the founding is twelve plants at most and often fewer. Saying so out of the return value costs one integer and buys a line in the header that no reader has to take on trust.
The loop itself has nothing new in it whatsoever. That is the point of the chapter.
// cmd/ages/main.go
wall := time.Now()
log := make([]year, 0, years)
for y := 1; y <= years; y++ {
for {
v.Tick()
if v.Now%terra.Year == terra.Quarter+1 {
break
}
}
log = append(log, snap(v, y))
}
spent := time.Since(wall)
$ go run ./cmd/ages -mode pace
ages: what two hundred years costs, at the rate volume 1 fixed
ticks in a year 3600
years 200
ticks in the run 720000
ticks a second, paced 10
paced, that is 20h0m0s
a census at every midsummer is 200 lines; every tick is 720000
Volume 1's runner takes a Paced flag and, when it is set, waits on a ticker
before every step so that ten ticks of the world cost one second of yours. That is the
right rate for a world somebody is looking at. Here it would cost twenty hours to find
out one thing, and the census would print one line every six minutes for all of them.
Nothing in the simulation cares. A tick is a function call; the ticker is a thing bolted on outside
it, and taking it off is a change to the caller and not to the world.
Numbers first. A year in this valley is 3,600 ticks, so two hundred years is 200 × 3,600 = 720,000 ticks. At volume 1's ten ticks a second that is 720,000 ÷ 10 = 72,000 seconds, and 72,000 seconds is twenty hours. The same 720,000 ticks with the ticker taken out came back in 8.296 seconds on the machine this was written on, which is 86,792 ticks a second: 8,679 times faster than the clock would have permitted.
Write the ticks in a year Y, the years y, the ticks in the run T, the rate in ticks a second r, and the wall-clock cost W in seconds. Two multiplications and a division:
T = y · Y and W = T ÷ r
Both rates go in the same slot. Paced, r is a number you chose and W is what it costs you; unpaced, r is a number the machine hands back and W is what it managed. The second r moves with the hardware, so it carries the same warning every measured figure in this book carries: yours will differ, and the arithmetic around it will not.
The last number is what the method costs. Two hundred censuses out of 720,000 ticks is one reading every 3,600, which is 0.028 per cent of the run. Everything that happens between two midsummers happens where nobody is looking, and the run below is going to make you pay for exactly one of those blind spots.
Years 1 to 12
Start short, because the first dozen years hold everything the next hundred and eighty-eight only finish. Twelve years is 43,200 ticks, and about a second and a half on the machine this was written on.
$ go run ./cmd/ages -mode run -years 12 -every 1
ages: 12x8 valley from seed 5, 44 soil cells, 12.00 light on an average day
founded in mid spring with 3 of every row on stream 11, 12 took a cell
12 years, 43200 ticks, no pacing, one census at every midsummer
the air holds 3960 seeds: 44 soil cells times the 90 of the biggest clutch
year moss herb scrub tree standing
n mass mean n mass mean n mass mean n mass mean grams
1 3 93.9 31.3 3 63.1 21.0 3 493.1 164.4 3 867.4 289.1 1517.5
2 0 0.0 0.0 0 0.0 0.0 18 1263.6 70.2 4 1144.8 286.2 2408.4
3 0 0.0 0.0 0 0.0 0.0 29 1412.2 48.7 6 1291.2 215.2 2703.3
4 0 0.0 0.0 0 0.0 0.0 32 1399.2 43.7 6 1164.8 194.1 2563.9
5 0 0.0 0.0 0 0.0 0.0 32 1352.2 42.3 6 1086.2 181.0 2438.3
6 0 0.0 0.0 0 0.0 0.0 34 1321.8 38.9 6 1030.6 171.8 2352.5
7 0 0.0 0.0 0 0.0 0.0 36 1289.5 35.8 4 965.3 241.3 2254.9
8 0 0.0 0.0 0 0.0 0.0 41 1787.4 43.6 3 623.7 207.9 2411.1
9 0 0.0 0.0 0 0.0 0.0 39 1700.8 43.6 3 559.5 186.5 2260.3
10 0 0.0 0.0 0 0.0 0.0 39 1622.6 41.6 3 503.5 167.8 2126.1
11 0 0.0 0.0 0 0.0 0.0 37 1528.1 41.3 3 483.4 161.1 2011.5
12 0 0.0 0.0 0 0.0 0.0 39 1457.9 37.4 3 462.2 154.1 1920.0
The moss and the herb are gone by the second census and never come back. Between them they released 41 seeds in the whole two centuries, against the scrub's 29,528, and the two of them lost the valley in the first twelve months of it. Both reasons were already on the table: the herb wants nearly fourteen per cent of an average day's light before it will start at all, and the moss stands seven hundredths of a cell tall and drops most of its clutch on the cell it grew on. What the census adds is that the argument was settled inside one year.
Now read the scrub's three columns across, and read them in the right order. The count climbs the whole way: 3, 18, 29, 32, 32, 34, 36, 41. The total climbs to 1412.2 by year 3 and then goes flat, wandering between 1289 and 1787 for the next nine years. The mean does neither. It falls off a cliff: 164.4, then 70.2, then 48.7, and it is under forty by year twelve. The valley is filling up with scrubs and each new one is smaller than the last, and only one of the three columns is saying so.
The tree column is the same argument run slowly. Three trees at the founding, four by year 2, six from year 3 to year 6, and for a while their mean holds up better than the scrub's: 289.1 grams each, then 286.2, then 215.2. Then the count starts falling and the mean never recovers. By year 20 there are three trees left carrying 48.5 grams apiece, a twelfth of what one tree reaches standing alone on open ground, and the same weight as the scrubs underneath them. The tallest row in the table, the one that takes the light before anything else gets a look at it, has been brought down to the size of its own understorey.
$ go run ./cmd/ages -mode run -years 12 -every 1 (second table of the same run) what the valley is holding, and what has stopped standing since it opened year in soil in litter in tissue in bank starved year ended unlucky 1 137.400 214.533 176.067 0.000 0 0 0 2 89.079 181.558 247.533 7.730 3 3 0 3 14.267 205.470 278.404 23.320 6 3 0 4 26.489 193.106 258.665 39.420 18 3 0 5 37.714 183.182 244.055 48.800 31 3 0 6 50.524 176.280 233.906 48.900 45 3 1 7 64.974 168.263 222.173 49.820 61 3 2 8 80.151 164.495 200.804 54.260 76 3 3 9 95.924 153.254 185.972 57.600 99 3 4 10 111.679 143.301 172.880 59.430 120 3 4 11 126.645 135.851 164.194 55.560 144 3 6 12 140.092 129.621 156.797 50.850 165 3 7
This valley opened holding 528 nutrient units, twelve in each of its 44 cells of soil, and nothing puts any more in: the seeding chapter closed with the observation that seeds are the first thing in this world able to carry matter over the rim, and nothing at all carries any back. By the first midsummer 137.4 of those units are still in the ground. By the third there are 14.267, which is under three per cent of the stock. The rest is standing up as tissue or lying on the cells as litter.
Then the soil column turns round and climbs, every year, for the rest of the run. That is the part to hold on to. The starved column climbs with it, from 6 to 165 in nine years, and by the twelfth year the ground has 140 units back and 165 plants have died of not being able to pay their bills.
2703.3 grams down to 1.8
Eight and a bit seconds for the whole two centuries, so run it and read the census as it comes.
$ go run ./cmd/ages -mode run -years 200
year moss herb scrub tree standing
n mass mean n mass mean n mass mean n mass mean grams
1 3 93.9 31.3 3 63.1 21.0 3 493.1 164.4 3 867.4 289.1 1517.5
2 0 0.0 0.0 0 0.0 0.0 18 1263.6 70.2 4 1144.8 286.2 2408.4
3 0 0.0 0.0 0 0.0 0.0 29 1412.2 48.7 6 1291.2 215.2 2703.3
10 0 0.0 0.0 0 0.0 0.0 39 1622.6 41.6 3 503.5 167.8 2126.1
20 0 0.0 0.0 0 0.0 0.0 31 1305.4 42.1 3 145.4 48.5 1450.8
30 0 0.0 0.0 0 0.0 0.0 21 704.4 33.5 2 138.4 69.2 842.8
40 0 0.0 0.0 0 0.0 0.0 17 508.8 29.9 2 47.1 23.5 555.9
50 0 0.0 0.0 0 0.0 0.0 14 312.1 22.3 1 27.7 27.7 339.8
60 0 0.0 0.0 0 0.0 0.0 9 201.5 22.4 1 12.3 12.3 213.7
70 0 0.0 0.0 0 0.0 0.0 7 126.4 18.1 1 6.5 6.5 132.9
80 0 0.0 0.0 0 0.0 0.0 8 84.2 10.5 1 1.0 1.0 85.2
90 0 0.0 0.0 0 0.0 0.0 6 50.0 8.3 0 0.0 0.0 50.0
100 0 0.0 0.0 0 0.0 0.0 2 29.3 14.6 0 0.0 0.0 29.3
110 0 0.0 0.0 0 0.0 0.0 2 17.4 8.7 0 0.0 0.0 17.4
120 0 0.0 0.0 0 0.0 0.0 1 11.4 11.4 0 0.0 0.0 11.4
130 0 0.0 0.0 0 0.0 0.0 1 7.9 7.9 0 0.0 0.0 7.9
140 0 0.0 0.0 0 0.0 0.0 1 4.6 4.6 0 0.0 0.0 4.6
150 0 0.0 0.0 0 0.0 0.0 1 3.1 3.1 0 0.0 0.0 3.1
160 0 0.0 0.0 0 0.0 0.0 1 1.8 1.8 0 0.0 0.0 1.8
170 0 0.0 0.0 0 0.0 0.0 1 1.8 1.8 0 0.0 0.0 1.8
180 0 0.0 0.0 0 0.0 0.0 1 1.8 1.8 0 0.0 0.0 1.8
190 0 0.0 0.0 0 0.0 0.0 1 1.8 1.8 0 0.0 0.0 1.8
200 0 0.0 0.0 0 0.0 0.0 1 1.8 1.8 0 0.0 0.0 1.8
Read the last column down and there is no argument left to have. The valley carries 2703.3 grams of living tissue at its best, in year 3. A hundred and eighty-eight years later it carries 1.8. That is one plant, a scrub, weighing less than four seeds. Nothing else is standing anywhere on the map. The tree column runs out at year 90; the last tree in this world was alive in year 86.
There is no rally in it. From year 3 the standing column falls in every single one of the printed rows, and it falls smoothly: roughly halving every fifteen years for the first century, then more slowly, and then arriving somewhere it cannot leave. The last five printed rows all read 1.8. A run that swung up and then down would be telling you about a control problem; this one is not swinging.
Two named patterns are in that column and they should be kept apart, because they have different causes and only one of them is about crowding.
The first is competitive exclusion, and it happens twice here at two speeds. Four rows started. Inside one year two of them were gone, and neither was eaten or pushed off a cell by force: they were out-earned on the same ground by rows that could hold the same light for a smaller bill. The slow version took the tree, over eighty-six years. That is what a limiting resource does when more than one kind is spending it, and no line of code anywhere implements it.
The second is boom and bust. The scrub went from 3 plants to 41 in eight years and from 41 back to 1 in the hundred and ninety-two after that, and the valley's standing mass went 1517.5, then 2703.3, then 1.8. A population that overshoots its ground and settles back below the peak is an ordinary thing. This one does not settle anywhere: the ending is roughly a fifteen-hundredth of the peak, and about a hundredth of what one scrub weighs standing alone on open ground.
The two together produce an ending no one would have designed. The scrub won every argument it had, and what it won was a valley it cannot live in.
$ go run ./cmd/ages -mode run -years 200 -every 50 (the tables after the census) what the valley is holding, and what has stopped standing since it opened year in soil in litter in tissue in bank starved year ended unlucky 1 137.400 214.533 176.067 0.000 0 0 0 2 89.079 181.558 247.533 7.730 3 3 0 3 14.267 205.470 278.404 23.320 6 3 0 50 342.920 20.987 22.883 6.990 989 3 24 100 373.715 1.719 1.756 0.570 1458 3 24 150 376.192 0.182 0.186 0.000 1470 3 26 200 376.281 0.108 0.111 0.000 1470 3 26 every row, over the whole run peak n in year peak mass in year last seen released grew moss 3 1 93.9 1 1 18 7 herb 3 1 63.1 1 1 23 0 scrub 41 8 1787.4 8 standing 29528 1461 tree 6 3 1291.2 3 86 578 20 starved year ended unlucky all moss 10 0 0 10 herb 0 3 0 3 scrub 1440 0 23 1463 tree 20 0 3 23 no slot in the air: 0, and the fullest the air ever got was 1256 of 3960 the books in grams the books in nutrient units standing 1.8439 in living tissue 0.110634 in the air 0.0000 in the air 0.000000 in the bank 0.0000 in the bank 0.000000 lying dead 0.0000 lying dead 0.108274 burned 842106.0410 in the soil 376.281092 rotted 14283.2020 blown away 151.500000 blown away 2231.0000 the valley opened 528.000000 ever built 858622.0869 difference 0.000000 difference 0.0000 world 493261435901c120 after 720000 ticks 720000 ticks in 8.476s, 84943 ticks a second (measured here; yours will differ) the same run paced at 10 ticks a second would take 20h0m0s
Fourteen hundred and ninety-nine plants have died in this valley and 1,470 of them starved. Twenty-six ran out of luck, three were annuals reaching the end of their year, and that is the entire register. Nothing was eaten, nothing burned, and nothing was pushed off a cell by force. Every plant that fell in two hundred years fell because it could not cover its own upkeep.
And the ground they starved on is holding 376.281 of the 528 units the valley opened with. Not fourteen, the way it stood in year 3. Three hundred and seventy-six, more than two thirds of everything there ever was, sitting in the soil at the end of a run whose entire death register reads starved. Both differences at the bottom are zero to every digit printed, so this is not an accounting leak: the grams add up, the nutrient units add up, and the valley really is that full and that empty at the same time.
One more figure before the diagnosis is handed over. The stock does not come back to 528, and the missing 151.5 units are in the column marked blown away. Over two centuries this valley put 2,231 grams of seed over its own rim, and every gram of that took its nutrient with it. Nearly twenty-nine per cent of everything the world opened with left on the wind, and it is not coming back, because there is no mechanism in this world that brings any.
One number from the row table explains why the run has no ending except this one. The scrub released 29,528 seeds over two centuries and 1,461 of them ever stood up, which is one in twenty. That rate was survivable while the plants making the seeds were large, and it stopped being survivable when they were not. The last plant on the map settles the question for good: a scrub has to be standing at two grams before a quarter of itself pays for one whole seed, and the one alive in year 200 weighs 1.8439. This valley now holds no seed in the air, none in the ground, and one plant that will never make another.
Four seed histories
One run is one run. The terrain, the wind field, the founding draw and every dispersal in two hundred years all come off a single number, so change that number and everything changes with it. If the collapse is a property of the model it will survive that; if it is a property of seed 5 it will not.
$ go run ./cmd/ages -mode seeds
ages: the same 200 years under several world seeds, 3 of every row founded
seed cells peak grams in year most scrub in year at the end grams in soil blown out
3 42 2419.1 3 39 7 scrub tree 3.7 360.7 142.7
5 44 2703.3 3 41 8 scrub 1.8 376.3 151.5
7 54 3150.8 3 44 6 tree 55.9 463.9 169.3
11 51 3328.0 2 37 6 scrub 13.9 441.4 168.7
Four terrains between 42 and 54 cells of soil, four peaks between 2419 and 3328 grams, and every one of those peaks in year 2 or year 3. Every valley then spends the rest of its two centuries coming down, and every one of them ends under 56 grams with between 360 and 464 nutrient units still lying in the ground. The moss and the herb are extinct in all four. The winner is not always the same: seed 7 finishes with five trees and no scrub at all. Which row survives is a detail of the draw. That one does, and that it survives on crumbs, is not.
Numbers are the argument and the client is the reason to believe it. The painter that drew seeds falling in the last chapter moved into a package of its own the moment a second bench wanted it, and it draws this valley the same way it drew that one.
$ go run ./cmd/ages -mode frame -at 1,8,200 -strip assets/frames/valley-two-centuries.png
year 1, tick 901, summer, daylight 1.6000, 12 standing at 1517.5 grams
moss 3 herb 3 scrub 3 tree 3, 0 waiting in the ground, soil nutrient 137.400
############
#.t..ms.h.s#
#.....t..m.#
#.~~~~~....#
#.~~~~~~h..#
#...~~~~...#
#...~m..sht#
############
frame 68333ff00c5710feb22269d1db2c47c98f1e5c3001e927566d1fae7b81bcdbc1
year 8, tick 26101, summer, daylight 1.6000, 44 standing at 2411.1 grams
moss 0 herb 0 scrub 41 tree 3, 1513 waiting in the ground, soil nutrient 80.151
############
#stssssssss#
#ssssssssss#
#t~~~~~ssss#
#s~~~~~~sss#
#sss~~~~sss#
#sss~ssssst#
############
frame 278f2f763f5882e8d2e9a184a4faa4d35b1ad43b09ba446e1de0c825657de4b0
year 200, tick 717301, summer, daylight 1.6000, 1 standing at 1.8 grams
moss 0 herb 0 scrub 1 tree 0, 0 waiting in the ground, soil nutrient 376.281
############
#......s...#
#..........#
#.~~~~~....#
#.~~~~~~...#
#...~~~~...#
#...~......#
############
frame 297926c080668e242aee8b7fc1960767a2755afe3d04768484c3155a9760ae04
the 3 frames side by side, 1184 by 256: 17c4d59dd0588f0f49ec969204cc4f33b1cc7118d9d9b54216a03e3d64727ac8
wrote assets/frames/valley-two-centuries.png
Count the letters in the year 8 map. There are 44 of them and this valley has 44 cells of soil, so every cell of ground a root can live in has a plant standing on it, and 1,513 more seeds are lying in the ground waiting for one of them to move. That is the fullest this world will ever be, and it happens in the eighth year of a two-hundred year run. The year 200 map has one letter on it.
assets/frames/valley-two-centuries.png: the valley in year 1, year 8 and
year 200, drawn by the same painter at the same scale. The middle one is 44 plants on
44 cells of soil. The right-hand one is 1.8 grams.
The air needs a pool, and the pool needs a size. Chapter 41's valley bench printed a
flying column in its census, and here is every value that column took in
six years: 0, 0, 0, 0, 0, 0. Not one seed was ever in the air when the census was taken.
So a few hundred slots would obviously do, and the run below asks for 400.
$ go run ./cmd/ages -mode run -years 200 -air 400 -every 200
the air holds 400 seeds, set on the command line
year moss herb scrub tree standing
n mass mean n mass mean n mass mean n mass mean grams
200 0 0.0 0.0 0 0.0 0.0 1 2.0 2.0 0 0.0 0.0 2.0
no slot in the air: 13767, and the fullest the air ever got was 400 of 400
world dca4c16062c015ff after 720000 ticks
The census is entirely plausible. One scrub, two grams, everything else gone, the same
ending as the honest run to within a fifth of a gram. Nothing in it looks wrong, no
error is printed, and both ledgers still close at zero, because a seed that never got
into the air was counted where it fell instead. If the seed ledger had not carried a
no slot column, this run would have been publishable and false.
13,767 seeds never left their parent. The high-water mark of the honest run says the air held 1,256 at its fullest, so 400 was short by a factor of three, and the world digest says the two runs are not the same world after tick one of the first crowded autumn.
Trace the mistake back and it is not about pools at all. Every row in this table seeds
on the tick its own window shuts, which falls in autumn for all four of them, and a seed
is in the air for anything from one tick to a few dozen. The census is taken at
midsummer. The flying column was therefore structurally zero: not a
measurement of a quantity that happened to be small, but a reading taken at the one time
of year when it is guaranteed to be nothing. A number sampled once a period tells you
nothing about a quantity whose whole life is shorter than the period. The right size
came from arithmetic instead: 44 cells, the largest clutch any row in the table can pay
for is 90 seeds, so 3,960 is the worst the air can ever be asked to hold, and the
program prints that sum in its own header.
The negative result
The method under this page is older than simulation and it has three moves. Build the instrument before the run, so what gets recorded is not chosen by what you hoped to see. Record every period and pick the interesting ones out afterwards: the peak year in the run above was found by scanning a column for its largest number, and if the peak had fallen in year 90 the same three lines of code would have printed year 90. Then keep a ledger that has to close, so that a collapse can be told apart from a leak in your own bookkeeping.
That third one is what makes this a finding rather than a bug report. A world losing plants could be a world with a subtraction in the wrong place. Here the grams balance to four decimals and the nutrient units balance to six, across 720,000 ticks, 858,622 grams ever manufactured and 30,000-odd seeds. Every gram is standing, lying dead, burned as upkeep, rotted, or gone over the rim, and the same is true of every nutrient unit. Nothing here went missing. It was all spent, and the books say on what.
The census earns its third column here too. If it printed only counts, the run from year 3 to year 12 reads as a healthy population climbing from 29 to 39. If it printed only totals, the same years read as a plateau. The mean is the column that says the newcomers are arriving smaller and smaller, and it starts saying so in the second year of the run, six years before the count peaks and turns. Choosing what to record is most of the skill in this kind of work, and the cost of one extra division per row per year was nothing at all.
Accelerated time bought the finding and it charged for it. Twenty hours of paced world became eight seconds, and in exchange nobody watched a single tick of it. Everything in the run above was learned from 200 readings out of 720,000 ticks, and the one thing that was hidden by that sampling rate cost a worked failure to find. Both halves of that trade are permanent: any run fast enough to answer a question about centuries is too fast to watch, and every quantity in it that lives and dies between two readings is invisible by construction.
It is Be careful about how far four seeds reach. The runs above say that this valley, at this calibration, on these four terrains, collapses. They do not say that unmanaged ecologies must collapse, and they do not say that any particular number in the species table is wrong. A different soil stock, a different rain, a bigger map or a fifth row could all move the ending, and none of that has been tested here.
What has been established is narrower and enough to work with: the collapse is not one unlucky draw, it is not an accounting error, and it is not caused by anything the simulation does randomly. That is the ground the next two chapters stand on, and it took a run long enough to be embarrassing to get it.
- Given a tick count and a tick rate, you can work out what a run costs paced and what it cost unpaced, and say which of the two figures moves when the hardware changes.
- Reading a census, you can say what the count, the total and the mean each know that the other two do not, and point at the year in the run above where they first disagree.
- state the three ways a plant stops standing in this world, read the register at the end of the run, and say which of them accounted for 1,470 of 1,499 deaths.
- name the two places two hundred years of this valley's nutrient ended up, give the figure for each, and say which of the two can never come back.
- Shown a long run whose ledgers close and whose population is gone, you can argue that the collapse is in the model rather than in the bookkeeping, and say what you checked.
- Handed a quantity that is sampled once a year, you can work out whether its lifetime is shorter than the sampling period before you trust a single reading of it.
Exercise 1 — accuse the wrong suspect. Twenty-six plants ran
out of luck in that run, and mortality was the mechanism this page added. Predict
what happens with it switched off, then run
go run ./cmd/ages -mode run -years 200 -wear 0.
The peak comes out identical to the digit: 29 scrubs and 6 trees in year 3, 2703.3 grams, because no plant in the first three years was old enough for the hazard to have caught it. The ending moves from one scrub at 1.8 grams to three scrubs at 5.8, which is 5.8 grams against 2703.3 instead of 1.8 against 2703.3. And 1,256 plants still starve.
So the answer is that the mechanism this page added is not the one doing the killing. It moved the ending from 1.8 grams to 5.8 and left the whole first act alone, and a run with no luck in it anywhere still empties out. When something collapses shortly after you add a feature, turning the feature off is the cheapest experiment available, and it is do it before any theory gets written down.
Exercise 2 — start with more. Predict what founding the
valley with ten of every row instead of three does to the peak and to the ending, then
check with go run ./cmd/ages -mode run -years 200 -found 10.
The peak arrives a year earlier and is bigger: 2952.2 grams in year 2 against 2703.3 in year 3. The ending is one scrub at 9.4 grams. More founders means the ground is stripped sooner, which is the same run with the first act played faster, and 1,742 plants starve instead of 1,470.
The useful thing here is what does not change. If the ending depended on the founding population, more founders would buy something real; what they buy is a peak one year sooner, 249 more grams at the top of it, and 9.4 grams standing at the end instead of 1.8. Whatever is driving this is not the number of plants you begin with.
Exercise 3 — take away half the sky. The species chapter
worked out what halving the daylight does to every row's ceiling. Predict what it does
to two hundred years, then run
go run ./cmd/ages -mode run -years 200 -light 6.
The peak drops to 2274.2 grams and moves out to year 5: less light means slower growth, so the ground takes longer to empty and the top of the curve is lower and later. Two hundred years in, the valley holds one scrub and one tree between them weighing 10.4 grams, and that tree is the one genuine surprise on offer: it is still standing in the dim run, where in the bright one the last tree had been gone for over a century. It cost more trees to get there, 91 dead against 23.
One column changes character. In the bright run, not one seed in two centuries was ever refused a cell for want of light; in this one, 423 were. Halving the sky finally made light a binding constraint on germination, and it still did not change the ending.
So: 1,470 plants starved to death on ground holding two thirds of the nutrient the world was founded with, and the valley reached the fullest it would ever be in its eighth year of two hundred. Nothing in that is random, nothing in it is an accounting error, and nothing in it depends on the seed. It is arithmetic, and arithmetic can be drawn: every quantity in this valley feeds something that feeds it back, and the next thing to do is put those loops on paper and find the one with nothing at all pushing the other way.