The Strike
The strike store change
The second row can eat fallen mass, but it cannot put fallen mass under its own feet. An animal on that row can lift grams off a pile and turn them into store energy at exactly the rate a browser turns a leaf; without a strike, it waits for some other body to starve.
A strike spends the striker's store and takes the same number out of the store it lands on. No gram moves at all: the striker's body weighs what it weighed and so does the body it hit. When a struck store closes a tick at nothing, the creature stops the only way anything in The Hollow has ever stopped, and its whole bulk goes onto the cell it was standing over through the burial that was already there.
A browser that starved five cells away is five cells of walking and a hundred ticks of rotting from becoming the second row's meal. A hunter needs a way of putting something on the ground where it is standing, at a moment of its own choosing.
The seventh entry already has the front half of that act. It is priced at the whole body thrown at its top speed. It has a rule of its own and a refusal value nothing else uses. Animals score it, the check allows it when a living body of a lower level is standing inside reach, and the tick it is taken on charges the store in full.
Before this page, the striker paid and the animal it threw itself at carried on eating. The entry cost its row a great deal for no return at all.
A blow reaches across from one creature's books into another creature's books, which nothing in this world has ever done. A plant takes light and water off a cell. A mouth takes grams off a stand or a pile. A body charges its own store for its own upkeep.
Every one of those spends what is in front of it. A blow is one creature writing a number onto a second creature, and everything downstream of that fact on this page is a consequence of it.
By the end of the page the blow is written and charged, the creature phase has one more
step in it than it had, and there is a run of a valley in which one row of animals hunts
another. There is a bench called strike. There is a proof that the new phase
step changes nothing whatever in a valley where no animal hits another, which matters more
than it sounds: three volumes of runs go through that phase, and a step added to it that
quietly moved one of them would be the worst kind of defect this book can produce.
The grams books still close, with the last few bits printed instead of tidied away.
The strike cost
Start with what a blow may not take, because that is the part with an answer already written down. The obvious thing for a predator's strike to remove is meat. Try it and four things in the module break on the same afternoon. The roster counts the grams walking about as the number of creatures times the bulk of the row each one came off. A creature joining the roster charges that same bulk to the valley's opening stock. A burial credits it back to the litter. And the price of a child is that bulk times what a gram of tissue converts to. A body whose mass went down would make all four of those describe an animal that is no longer standing there, and it would do something worse than arithmetic: a wounded creature would be cheaper to keep alive, because upkeep is charged per gram, and cheaper to breed from, because a child is priced off the parent's mass. Hurting an animal would improve it.
Energy has no such problem, and the reason is that nothing anywhere audits it. The grams ledger is closed and checked every time a valley run ends, because grams are conserved by construction: every one of them is standing somewhere, walking somewhere, lying somewhere or has been counted out through one of the roads that burn them. Store energy has never been in any ledger at all. It comes into existence when a mouthful of grams is converted and it leaves when a body spends it, and no line anywhere adds up how much of it there is. A blow can take energy out of a creature for the same reason upkeep can: it is a spend, and a spend needs no counterpart.
Then how much. The entry is already priced, and it was priced as the movement charge run at the whole animal: the mass of the body, times the square of the speed it is thrown at, at the row's price for a unit of work. For the second row that comes to 7.2900 energy units a throw. The blow is that number again. What the striker's muscles spent is what arrives, and the two halves of a strike are one multiplication read twice, charged once to the animal that threw it and once to the animal it landed on.
// internal/beast/act.go — inside apply's switch, where the entry has
// charged its price and done nothing else since it was written
case Strike:
// The price, and then the same number again on somebody
// else's account. A strike is the only thing in this world
// that writes a number onto a creature that is not the one
// taking the tick, and what it writes is what it just spent:
// the work the striker threw is the work the struck body
// takes. Nothing is manufactured and nothing is moved. The
// striker's store goes down by the price because the muscles
// burned it, and the prey's store goes down by the blow
// because the blow landed on it, and no gram anywhere in the
// valley changes hands.
//
// The search runs again here, exactly as a bite's does: the
// check asks Quarry whether there is anybody to hit, and the
// effect asks it who. Both are pure walks over the cells
// inside Reach against a View nothing is writing to.
t.Price = k.Lunge()
if q, _ := b.Quarry(v); q != nil && !b.Feinting {
t.Blow = k.Lunge()
q.Store -= t.Blow
q.Hurt += t.Blow
}
b.aim(0)
// internal/beast/act.go — one more line on the tick's record
type Tally struct {
// ...
Price float64 // energy units the action itself charged
Blow float64 // energy units this tick took out of somebody else's store
// ...
}
// internal/beast/body.go — and one more on the body
Ate float64 // grams it has taken off the valley since it was born
Hurt float64 // energy units blows have taken out of this store
$ go run ./cmd/strike -mode blow
strike: one hunter on 5,4, one browser on 6,4, and nothing else moving
the hunter stands at level 2 and the browser at level 1
Quarry comes back with creature 2, carrying 40.0000 grams
the check says: allowed
the browser asked for one gets: creature 2 at 6,4 cannot strike: no creature of a lower level inside reach
a strike costs the hunter 7.2900 to throw and takes 7.2900 off the
browser's store, and the two are one number: the work the striker
spent is the work the struck body took
blow paid landed hunter browser walking
1 7.2900 7.2900 592.4700 32.7100 100.0000
2 7.2900 7.2900 584.7000 25.4200 100.0000
3 7.2900 7.2900 576.9300 18.1300 100.0000
4 7.2900 7.2900 569.1600 10.8400 100.0000
5 7.2900 7.2900 561.3900 3.5500 100.0000
6 7.2900 7.2900 553.6200 -3.7400 100.0000
the browser is standing at -3.7400 with the tick still open, and it is
still standing: nothing in a strike strikes anybody off
then one phase closes over the pair of them
creature 2, a browser, struck off on tick 901 over cell 6,4
40.0000 grams of body onto the litter of that cell, and the roster is
down to 1
the step found 1 of them and the sweep found 0
the pile on 6,4 is 40.0000 grams and 0.0000 nutrient units
the hunter has taken 0.0000 grams in its life and lost 0.0000 energy to blows
the browser took 0.0000 grams in its life and lost 43.7400 energy to blows
and the hunter's own mouth, standing where it is, now finds 40.0000 grams
lying on 6,4: the body it emptied is the meal it eats
The last column of that table is the one to read first, because it never moves. One hundred grams of animal are walking about on those two cells at the start of the run and one hundred are walking about after six blows have landed. The browser's store has gone from forty energy units to nothing and a bit under, and the browser is exactly as heavy as it was: forty grams of body, which is what the second field of its row says and what the roster has been counting since the day it was stood up.
The hunter's own column falls faster than the blow explains, and the difference is the entry's second tick. A strike occupies the body for the tick after it, the same as a bite does, so every round after the first is 7.2900 for the throw and then two ticks of a sixty-gram body charging itself 0.2400 to stand there: 7.7700, of which the blow is nine tenths. The opening round is 7.5300, because only one tick of it has gone by.
Then the phase closes, and everything after that line is machinery this page did not write. The browser is struck off. Its forty grams land on the cell it was standing over as litter, with a nutrient figure of nothing, because a browser borrowed no minerals out of the ground and repaid what it lifted off a plant on the tick it took the bite. The roster is one shorter. And the hunter, which has not moved, now has forty grams lying inside its reach, which its mouth reads as a meal by the same rule it has read every other pile by. No new road, no new kind of death, no second burial.
The blow and the price are one number, and that makes the cost of a kill something you can work out before you run anything. Every unit that comes out of the target's store came out of the striker's store first. So emptying a store that holds forty units costs the striker forty units, and emptying one that holds four hundred costs four hundred. The store's size is the bill, and nothing about the striker changes it.
The run above is that sentence with the numbers in. The browser opened on 40 energy units. Six blows at 7.29 come to 43.74, and 43.74 is the first multiple of 7.29 that gets past 40. The overshoot is one blow's worth at most, because the last one cannot be thrown in halves.
Now the other side. A browser's body is forty grams, and a gram of tissue is worth four energy units to any mouth in this valley, so a browser carcass is 160 energy units lying on a cell. Set that against the bill and the rule falls out: a strike pays while the store you are emptying is smaller than the body you get for emptying it. Under 160 units of store, the arithmetic is on the striker's side. Over it, the animal is spending more than the meat is worth before it has taken a bite.
The hunter does not get the whole body. The pile starts rotting on the tick it lands, at a hundredth of itself a tick at full warmth, which for forty grams is 0.4 of a gram on the first tick. A mouth takes 0.375 grams and is occupied for two ticks doing it, so it lifts 0.1875 grams a tick. The mouth and the rotting are working on the same pile at the same time and the rotting is going about twice as fast, so an animal that stood on its kill and never left would get a shade under a third of it: 0.1875 divided by the 0.5875 the two of them take between them, which is 0.319.
Three tenths of 160 is about 51 units, against a bill of the store you emptied. So the arithmetic that decides whether hunting pays turns on how empty the animal inside the body was when you started, and hardly at all on how big the body is.
The same four lines in symbols.
blow = price = Work × Bulk × Top × Top
blows to empty a store = Store ÷ blow, rounded up
what a kill costs = blows × blow, which is Store or a little over
what a carcass holds = Bulk × Convert
Two things about the blow are decided by nothing random, and both should be said before any valley is founded. Which body a strike lands on is the search the entry's rule already runs: of every creature inside reach at a strictly lower level, the one carrying the most grams, with a tie going to the lower identity. Whether it kills is a subtraction on two numbers. There is no roll to hit anywhere in this, and adding one would put a draw inside the creature phase whose count depended on how many animals were standing nearby, which is the one thing the generators in this world may not do.
Deaths after the creature phase
The creature phase has had the same order since the roster was written. Build one reading of the world, cast every fan against it, step the whole roster from the first animal to the last, bury whatever stopped standing, and hand the valley to whatever registered itself for the births. Inside the stepping loop, each animal is asked what it wants, does it or is refused, pays its upkeep, and then the loop asks one question: is there anything left in the store. A creature at nothing goes on a list, stays exactly where it is until every other animal has had its tick, and is struck off at the end.
That question is asked once a tick, at the creature's own step, and until this page it could not have been asked anywhere better. There was only one thing in the world that could take energy out of a store, and it was the creature that owned the store. Nobody else could reach it. Asking at the animal's own step meant asking immediately after the only event that could have changed the answer.
A blow arrives from outside that. Two animals stand next to each other; one of them is number nineteen on the roster and the other is number four hundred; the hunter throws and the browser's store goes under. If the hunter is stepped first, the browser's own step comes afterwards and the loop catches it like any starved animal. If the browser is stepped first, its tick has already closed and nothing looks at that store again until the next phase builds a new view. Same two animals, same blow, same tick, and the answer to "is anything alive here" decided by which of them was founded first.
So the phase gains a step. After the roster has been stepped and before anything is buried, walk the list once more and write every creature standing at nothing into the same list the stepping loop writes into. In a valley where no animal strikes another, that walk finds exactly what the step found, with no new death to add.
// internal/beast/roster.go
func (r *Roster) sweep(v *terra.Valley, died []Carcass) []Carcass {
if r.Slack {
return died
}
for _, b := range r.Live {
if b.Dead || b.Store > 0 {
continue
}
b.Dead = true
died = append(died, Carcass{Who: b.ID, Name: b.Name,
At: b.Underfoot(v.Bed), Grams: b.Kind.Bulk, Tick: v.Now})
r.Swept++
}
return died
}
// internal/beast/roster.go — the tail of Phase, where the stepping
// loop has just finished. first is where the sweep's own dead start,
// so the burial that runs as each creature falls can be handed the
// newcomers alone.
first := len(died)
died = r.sweep(v, died)
switch {
case !r.Hasty && len(died) > 0:
r.bury(v, died)
case r.Hasty && len(died) > first:
r.bury(v, died[first:])
}
if r.Born != nil {
r.Born(v)
}
return died, refused
$ go run ./cmd/strike -mode sweep
strike: the hunter is stepped first, then the browser
the browser opens on 8.0000 and eats every tick it can
tick hunter browser on the roster struck off, and by what
901 592.4700 1.4000 2 -
902 592.2300 1.2400 2 -
903 584.7000 -6.2100 1 the browser, by the step
over those ticks the step found 1 and the sweep found 0
strike: the browser is stepped first, then the hunter
the browser opens on 8.0000 and eats every tick it can
tick hunter browser on the roster struck off, and by what
901 592.4700 1.4000 2 -
902 592.2300 1.2400 2 -
903 584.7000 -5.3600 1 the browser, by the sweep
over those ticks the step found 0 and the sweep found 1
Two runs of the same two animals with one difference between them: the order they were put on the roster in. Both browsers eat every tick the table lets them, both hunters throw a blow every tick they are free to, and both browsers are struck off on tick 903. The right-hand column is the only thing that differs, and it says which of the phase's two ways of noticing a dead animal got there first.
The stores those two stopped on differ, and the gap is worth a moment because it is not the blow. In the first run the hunter goes first, so the browser is already under when its own step comes round; the check asks the store before it asks anything else, a bite costs 0.1500 and the store is at nothing, so the animal cannot buy the mouthful and rests instead, paying only its upkeep. In the second run the browser eats first and then gets hit. One mouthful is worth 1.0000 and cost 0.1500 to take, so the two runs part by 0.8500, which is exactly one bite's profit.
$ go test ./internal/beast/ -run 'ABlowSpendsTwoStores|TheSweepFindsWhatTheStepCannot|BothRosterOrdersStopOnTheSameTick|AStrikeFreePhaseSweepsNobody' -v
=== RUN TestABlowSpendsTwoStoresAndMovesNoGrams
--- PASS: TestABlowSpendsTwoStoresAndMovesNoGrams (0.00s)
=== RUN TestTheSweepFindsWhatTheStepCannot
--- PASS: TestTheSweepFindsWhatTheStepCannot (0.00s)
=== RUN TestBothRosterOrdersStopOnTheSameTick
--- PASS: TestBothRosterOrdersStopOnTheSameTick (0.00s)
=== RUN TestAStrikeFreePhaseSweepsNobody
--- PASS: TestAStrikeFreePhaseSweepsNobody (0.00s)
PASS
ok theworld/internal/beast 0.048s
The first of those asserts the whole of what a blow does, one quantity at a time: the striker's store falls by the price beside its own upkeep and travel, the struck store falls by the same number, the roster is walking the same grams afterwards, the litter holds the same grams, and nothing anywhere has eaten anything. The third is the claim the new step exists for. It runs the same pair in both roster orders and requires the two runs to agree on whether anything is alive, while explicitly allowing them to disagree about which half of the phase noticed. The fourth starves a herd of browsers with nothing in the valley that could hit any of them and requires the sweep's own counter to be at nothing when they are all dead.
That last test is a small version of the claim the volumes behind this one depend on, and the claim deserves an argument as well as a run. Work out what the sweep can possibly find that the step did not. A store goes down when its creature pays upkeep, pays for an action, or is hit. It goes up when its creature takes a bite. In a valley where nothing can be hit, every one of those happens inside one creature's own step, and the loop tests the store on the way out of that step. Anything at nothing was at nothing then. The sweep walks a list, compares a number it cannot have changed, and writes nothing down.
An argument is cheap and a tape is not, so here is the tape. Two runs of the same valley, founded the same way, with the same browsers and nothing in it at a level anything else stands above. One of them runs the phase as it now ships. The other runs it with the sweep switched off through the counterfactual flag the roster carries for exactly this purpose. Every tick of both runs, every creature on the roster contributes its identity, the cell it is standing on and its store to a running hash, and the valley's own plant census goes in behind them.
$ go run ./cmd/strike -mode still -years 8
strike: 16x12 valley, 21 browsers off stream 12, 8 years, and
nothing in it standing at a level anything else is above
with the sweep with it left out
creatures still walking 27 27 same
creatures born 267 267 same
creatures struck off 261 261 same
of those, found by the sweep 0 0 same
standing plant mass 7330.333626 7330.333626 same
the world digest b47028475f094fa7 b47028475f094fa7 same
the tick tape 4bcb904669a2cbf6 4bcb904669a2cbf6 same
the tape is folded every tick of the run out of the roster in
order: every identity, the cell it is standing on and its store,
and then the valley's own census. Two runs that agree on it agree
on every creature on every tick and not merely at the end
Two hundred and sixty-one animals starve over those eight years and the sweep finds none of them. The tape is the line that matters: a digest taken at the end would let two runs arrive at the same place by two different roads, and this one is folded twenty-eight thousand eight hundred times a run out of every store on the roster. The two runs are the same run, tick by tick, and a step that was added to the phase in this chapter is therefore not something any earlier figure in this book has to be re-checked against.
The sixteen-year hunter run
Now found a valley and let it go. Sixteen cells by twelve, browsers scattered over the ground off the stream they have come off since the creature chapters, hunters scattered after them off a stream of their own, every animal driven by a wiring that grows its own nodes, and sixteen years of ticks. It is exactly the valley the second row was first turned loose in, founded from the same seed with the same draws in the same order, and the only thing that has changed underneath it is that the seventh entry now does something.
$ go run ./cmd/strike -mode valley | tail -77 | head -17
strike: 16x12 valley, 21 browsers off stream 12 and 8 hunters off stream 22,
every one of them driven by a graph the table's own width, and the
seventh entry landing on whatever the check allows it to land on
year browsers hunters standing lying kills swept
1 21 8 4654.10 0.95 0 0
2 11 0 6668.07 144.04 13 5
3 24 0 6999.00 137.63 13 5
5 19 0 7254.60 513.50 15 5
9 79 0 6464.87 1091.71 15 5
13 223 0 4684.13 643.67 15 5
17 257 0 3673.12 151.79 15 5
29 founded, 1816 born, 1588 struck off, 257 still walking after 57150 ticks
the step found 1583 of the deaths and the sweep found 5
the last hunter was struck off on tick 2826, 1925 ticks after the valley
was founded
Predation happened. Fifteen browsers took a blow in this valley from animals that hunted them down, and all fifteen are dead by the end of it; five of those deaths were found by the sweep and not by the stepping loop. Read the column carefully, because it counts a dead browser that was hit at some point and not a browser a strike killed, and the years say the difference out loud: thirteen of the fifteen are counted by the end of the second year and the last two not until the fifth, three years after the last hunter was struck off. At least two of these animals took a blow, walked away from it, and died later of the one thing everything in this valley dies of. Those five swept deaths are the whole reason the phase has a fourth step. They are the animals that were struck after their own turn had closed, and the roster order that decided it was settled when their identities were handed out.
And the hunters were all dead by the middle of the second year. The last of the sixteen was struck off 1,925 ticks after the valley was founded. A full store on that row covers 2,500 ticks of standing perfectly still, so between them the sixteen of them managed less life than doing nothing whatever would have bought the eight that were founded.
The reason is in the accounts, and the accounts are the point of this run; the population column is not. Rent here means what a standing body charges its own store every tick before a single entry of the table is priced: the animal is asleep, it is not moving, it is not eating, and the bill arrives anyway.
$ go run ./cmd/strike -mode valley | tail -59 | head -28
the two rows' accounts, added up over every animal that ever lived
browsers hunters
animals that ever lived 1829 16
creature-ticks they were stepped 7851768 7179
grams their mouths took 639711.56 139.36
energy that came in 2503436.32 557.43
energy standing still charged 826480.18 1690.94
income as a share of rent 302.90% 32.97%
strikes they threw 0 108
energy those strikes cost 0.00 873.51
energy blows took off them 873.51 0.00
bodies struck off 1572 16
of those, ones that were hit 15 0
the blow's two ends, added up over every strike thrown
strikes thrown 108
energy the strikers paid to throw them 873.51
energy taken off the struck 873.51
the difference between the two 0.00
browsers a blow ever landed on 15
of those, ones that were struck off 15
grams those bodies put on the litter 600.00
grams the hunters lifted off the litter 139.36
energy those grams were worth 557.43
so one body cost, in blows 58.23
and one body brought back 37.16
Read the middle four lines of the second block first, because they are the blow's own books and they close by construction. The hunters paid 873.51 energy units to throw 108 strikes and 873.51 came out of browsers' stores. The difference is nought and it is nought for a reason no run could have discovered: the two numbers are the same multiplication. What the block does not say, and what is true, is that neither half of it went anywhere. The striker burned its half in its muscles and the browser lost its half to a blow, and the world is 1,747 energy units poorer for the exchange. A strike creates nothing. What it leaves behind is a body on the ground, and a body is grams, and grams are audited.
Fifteen browsers were hit and all fifteen are dead by the end of the run, though the year column above says two of them not for years afterwards. A hundred and eight strikes landed on fifteen animals, which is seven apiece, and that says something about how a hunter behaves once it starts: the check hands it the heaviest body inside its reach every tick it asks, so it keeps hitting the same animal until that animal stops standing there.
The last two lines are the finding. Each of those fifteen bodies cost 58.23 energy units in blows and brought back 37.16. The first number is the arithmetic of the interlude arriving in a real valley: a kill costs whatever the animal was carrying, and 58.23 units is about a seventh of a full browser, so these hunters were not pulling down healthy animals. They were finishing ones that were nearly out anyway. The second number is the race with the rotting, measured: 600 grams of carcass went onto the litter and the hunters lifted 139.36 grams back off it, which is a little under a quarter, and some of that was plant litter they walked over rather than anything they killed.
So hunting in this valley runs at a loss of about twenty energy units a body, and the loss is not in the killing. Buying a 160-unit body for 58 units is a good trade. Everything goes wrong afterwards, in the part where an animal has to stand on what it killed and get it inside before the ground takes it.
Now the comparison that matters, which is the same valley with the blow switched off. The module carries a flag for it: the strike stays priced, stays refusable, stays two ticks long, and lands on nothing at all, which is what the entry did before this page.
$ go run ./cmd/strike -mode valley -feint | tail -64 | head -19
29 founded, 1185 born, 881 struck off, 333 still walking after 57150 ticks
the step found 881 of the deaths and the sweep found 0
the last hunter was struck off on tick 2353, 1452 ticks after the valley
was founded
the two rows' accounts, added up over every animal that ever lived
browsers hunters
animals that ever lived 1198 16
creature-ticks they were stepped 11610914 5437
grams their mouths took 772389.10 30.23
energy that came in 2989867.19 120.93
energy standing still charged 836719.75 1272.86
income as a share of rent 357.33% 9.50%
strikes they threw 0 147
energy those strikes cost 0.00 1136.27
energy blows took off them 0.00 0.00
bodies struck off 865 16
of those, ones that were hit 0 0
Same sixteen hunters, same founding, same wirings. Without the blow they lift 30.23 grams off the ground between them and their income covers 9.50 percent of what standing still costs them. With it they lift 139.36 grams and cover 32.97 percent, and the last death on the row moves 473 ticks further out, from 1,452 after the founding to 1,925. So the blow more than quadruples what an animal on the second row manages to find, and it still leaves the row paying two thirds of its rent out of a store nothing is refilling.
The other line in that run says something about how far a comparison like this can be pushed, and it is a warning rather than a result. The two runs have 333 and 257 browsers walking at the end and 1,185 against 1,816 births behind them, and the temptation is to read those as what predation did to a browser population. They are not that. Fifteen deaths in the first two years put the two valleys on different roads, and by the ninth year one of them is carrying 79 browsers and the other 232 with nothing whatever hunting in either. This is one world and then a second world, run from a point where they had already parted. The figures that can honestly be set side by side are the ones inside the window where both runs still had hunters in them, and those are the ones above.
Here is the mistake, and it is the kind that is made by reading the code carefully rather than carelessly. The stepping loop tests every creature's store on the way out of its own step. The sweep tests every creature's store again a moment later. The second test is over the same list, comparing the same field, with nothing in between that touches it except the last few creatures' own steps. So delete it, and let a body that gets hit late be picked up by the loop on the next tick, which it will be.
The flag that runs the phase without its sweep is on the roster beside the other counterfactuals this book keeps, and it is false in everything that ships.
// internal/beast/roster.go
// Slack is the phase without its sweep: deaths noticed only where
// the stepping loop notices them, at the creature's own step, so
// a body struck below nothing after its turn has closed stands
// for a tick it cannot pay for and is struck off at its own next
// step instead, one tick late and over whatever cell it coasted
// to. It is kept behind a flag so what leaving the sweep out
// costs can be run instead of described, and it is false in every
// roster this book ships.
Slack bool
$ go run ./cmd/strike -mode order -slack
strike: one hunter, one browser, one blow a tick, and the two orders
the two of them can be stepped in, with the phase's sweep left out
stepped in this order struck off store then under for found by
hunter first, browser second 903 -6.2100 1 the step
browser first, hunter second 904 -5.3600 2 the step
the second order leaves a creature standing at a store below nothing
for a whole tick, and it cannot buy the mouthful that would have
filled it: a bite costs 0.1500 and the check asks the store first
and the same two rows in a valley, three years of it, run both ways
with the sweep with it left out
creatures still walking 23 23 same
creatures born 151 151 same
creatures struck off 157 157 same
standing plant mass 7588.323047 7588.323047 same
the world digest 980cd83985dba8aa 980cd83985dba8aa same
creature-ticks under nothing 0 5 MOVED
stores that came back above it 0 0 same
the tick tape e33a5bd13e1563ca 65cc66cd32381fa4 MOVED
The top table is the symptom. One animal, one blow, and a date of death that moves by a tick when the two bodies are put on the roster the other way round. The two stores differ as well, by the one mouthful the second order let the browser take first, and they differ by that much with the sweep in place too. What appears only when it is taken out is the number in the second column, and nothing about the valley chose 904 over 903. Two integers handed out at a founding did.
The bottom table is what happens when the mistake is tested the way people usually test this kind of thing, which is by running the thing and comparing the totals. Three years of a valley with both rows in it. Same population, same births, same deaths, same standing plant mass, same digest of the ground. If that were the whole test, the sweep would look like a step that costs a walk over the roster every tick and buys nothing.
Two rows disagree, and they are the two that were folded every tick instead of read at the end. Five creature-ticks were spent by animals standing at a store of nothing, and the two runs wrote two different tapes. That is the whole defect, and it is small, and it is exactly as unacceptable as a large one: a run whose history depends on the order two founders were drawn in is a run that cannot be compared with anything, including itself.
The reasoning from symptom back to cause has one turn in it to take slowly, because it is the turn that tells you how big the damage can get. The extra tick a struck animal gets is a tick it can do nothing with. Every entry of the table except rest has a price above nothing, the check asks the store before it asks anything else, and the only way in this world to put energy into a store is a bite, which costs 0.1500 for a browser and 0.2250 for a hunter. An animal below nothing cannot afford either. So the store can only go further down, the animal dies at its own next step, and the run recovers. The reason the sweep is in the phase is not that it saves an animal from a wrong answer, then: it is that without it the answer to when is a fact about a list, and everything downstream of a death is dated.
Then the books, which have to close over all of this. One row of animals spent sixteen years hitting another row hard enough to empty fifteen of them, and if any of that had moved a gram it would show up here as a number that does not add up.
$ go run ./cmd/strike -mode valley | tail -20 | head -18
the books in grams
the valley opened with 67.000000 plants founded on the first tick
built out of light 1874363.231258 every gram the leaves ever fixed
creatures stood up 55956.045992 bodies the run opened with
in 1930386.277250
standing 3673.124254 living plant tissue
walking 6614.273819 living creature bodies
in the air 0.000000 seeds still flying
in the bank 2224.000000 seeds waiting in the ground
lying dead 151.792164 litter: plants and carcasses together
burned as upkeep 1208493.880006 grams a plant spent on standing there
rotted 69378.295099 grams the litter has burned off
blown away 0.000000 seeds that left over the rim
eaten off a stand 639711.555295 grams a mouth took off living tissue
eaten off the litter 139.356612 grams a mouth took off a pile
out 1930386.277249
difference 0.000001 8.775e-07, which is the last bits of the adding
One million nine hundred and thirty thousand grams in, the same out, and a residue of nine ten-millionths of a gram, printed because it is the last bits of adding a great many numbers in a written-down order and not because anybody is content with it. The ledger has the same lines it had before this page and no others. There is no line for grams a blow moved, because there is no such quantity, and the whole of predation's contribution to this table is the routing of forty grams at a time into lying dead a few hundred ticks earlier than they would otherwise have arrived.
The valley run ends on a line the blocks above leave out: 57,150 ticks in 21.099 seconds, 2,709 ticks a second, measured on an eight-core Ryzen 7 3700X and different on your machine. The tick count is arithmetic and is compared like every other number here. The duration and the rate are this machine talking, and no argument on this page rests on either.
Why one number is charged to two accounts
Strip the animals out and there is a pattern here that turns up in any system where one part is allowed to change another part's state. Three questions have to be answered before the change is written, and getting any of them wrong produces a different kind of mess.
The first is which books the change goes in. This world keeps two: grams, which are conserved and audited to the last bits at the end of every run, and store energy, which is spent and gone and counted by no ledger. Putting a blow in the audited column would have made it a transfer, and a transfer has to have a destination; the grams would have had to arrive somewhere, and the four places that read a body's mass would all have had to learn that mass is now a per-creature number that goes down. Putting it in the unaudited column makes it a spend, and a spend needs no counterpart at all. The lesson generalises past valleys: before writing a cross-object effect, find out which of your quantities are conserved and put the effect in one that is not, or be ready to write the other end of it everywhere.
The second is how big the change is, and the answer here was chosen so that no new number had to be invented. The blow is the price. That is a design decision and not a discovery, and it has one consequence: because the two are equal, the cost of emptying a store is the store, exactly, and no amount of cleverness on the striker's side can move it. A quantity that falls out of an identity like that is a quantity you can reason about before you run anything, and reasoning about it beforehand is how the interlude in the middle of this page predicted what the valley then measured.
The third is when the change is noticed, and it is the one that is easy to miss because the code that needs fixing is code that was correct when it was written. The stepping loop tested a store immediately after the only event that could change it. That was not a shortcut; it was the tightest possible place to test. A blow moved the set of events that can change a store, and the test stayed where it was, and the two of them are now out of step by however much roster order says. The general form is direct: when you add a new writer to a piece of state, go and look at everything that reads it and ask what each reader was assuming about who could have written it. The answers are usually in comments explaining why the read is safe.
And a fourth thing, about proving a negative. The step added to the phase runs on every tick of every valley in this book, including all the ones whose numbers are printed in volumes that were finished before predation existed. Saying that a walk over a list which writes nothing cannot change anything is true and is not evidence. Folding a hash out of every creature's store on every tick of two runs and putting the two sums side by side is evidence, and it costs one command. When something you added is supposed to be invisible, the cheapest way to be believed is to make the invisibility itself a measurement.
- Work out, without running anything, what it costs a hunter to empty a browser carrying 220 energy units, and say why the answer is that number give or take one blow whatever the hunter is built like.
- Name the four places in the module that read a creature's bulk, and say which of them would be wrong first if a blow took grams instead of energy.
- Say why a strike moving 7.2900 energy units out of one store and into nowhere leaves the valley's grams ledger with exactly the lines it had before.
- Given two creatures standing next to each other and the fact that one of them was founded first, say which half of the phase notices if the second one is struck below nothing, and what the other half would have noticed instead.
- Explain what the tick tape shows that the world digest cannot, using the two rows of the worked failure's second table that disagree.
- Given a row whose kills cost less energy than the carcasses are worth and which still starves, say which line of the accounts you would read to find out where the margin went.
Exercise 1 — hit a healthy one. The browser in the small bench opens on forty energy units and takes six blows. Work out how many blows a browser with a full store takes, and what that costs the hunter, before you run it.
Four hundred divided by 7.29 is 54.9, so 55 blows, and 55 times 7.29 is 400.95. The bench takes the store as a flag:
$ go run ./cmd/strike -mode blow -store 400 | tail -7
the step found 1 of them and the sweep found 0
the pile on 6,4 is 40.0000 grams and 0.0000 nutrient units
the hunter has taken 0.0000 grams in its life and lost 0.0000 energy to blows
the browser took 0.0000 grams in its life and lost 400.9500 energy to blows
and the hunter's own mouth, standing where it is, now finds 40.0000 grams
lying on 6,4: the body it emptied is the meal it eats
Four hundred point nine five energy units, to obtain a body holding 160. And that is only the blows. Fifty-five strikes with a held tick after all but the last of them is 109 ticks, at 0.24 of upkeep for a sixty-gram body, so another 26.16 goes on standing there while the work is done: 427.11 out of the 600 the hunter started with, for one carcass it will get about a third of. An animal that did this twice would be dead, and the check would have let it do it both times, because the rule on the seventh entry asks whether there is a body of a lower level inside reach and asks nothing about whether the animal can afford to finish.
Exercise 2 — try to bring one back. Without the sweep, a struck animal stands for a tick at a store below nothing. Find an opening store for which that animal eats its way back above nothing and survives, or show that there isn't one.
There isn't one, and the argument is three lines. A store below nothing can only be refilled by a bite. A bite has a price, 0.1500 for a browser and 0.2250 for a hunter. The check compares the price with the store before it looks at the world at all, so an animal at a negative store is refused it, along with every other entry on the table except rest, which is free and does nothing. Resting still pays upkeep. So the store falls, and the animal is struck off at its own next step.
The store that comes closest is the one that leaves the browser a tenth of a unit under, with a plant it cannot buy standing right beside it:
$ go run ./cmd/strike -mode order -slack -store 13.26 | tail -19 | head -3
stepped in this order struck off store then under for found by
hunter first, browser second 903 -0.9500 1 the step
browser first, hunter second 904 -0.1000 2 the step
That is the closest the arithmetic gets: a browser stopped ten hundredths of a unit below nothing, with a mouthful worth a full unit standing next to it, and 0.1500 it cannot pay to reach it. The valley table in the same run has a row for this, and it reads nought on both sides.
Exercise 3 — send more hunters. One hunter loses most of a kill to the rotting. Predict what a valley founded with three times as many of them does to that, and whether it saves the row.
The kill turns a profit and the row still cannot live. Three times the hunters, over four years:
$ go run ./cmd/strike -mode valley -hunters 24 -years 4 -every 2 | tail -51 | head -20
income as a share of rent 265.64% 50.42%
strikes they threw 0 201
energy those strikes cost 0.00 1464.56
energy blows took off them 1464.56 0.00
bodies struck off 245 44
of those, ones that were hit 28 0
the blow's two ends, added up over every strike thrown
strikes thrown 201
energy the strikers paid to throw them 1464.56
energy taken off the struck 1464.56
the difference between the two 0.00
browsers a blow ever landed on 28
of those, ones that were struck off 28
grams those bodies put on the litter 1120.00
grams the hunters lifted off the litter 566.92
energy those grams were worth 2288.33
so one body cost, in blows 52.31
and one body brought back 81.73
The two lines at the foot read 52.31 spent a body and 81.73 brought back. Hunting has gone from a loss to a profit of about thirty units a kill, and the reason is that a crowd of hunters puts more mouths near a fresh carcass, so more of it is inside somebody before the ground gets it. Income against rent goes from a third to a half.
And the row still dies out, which is the part to sit with. The bill that kills these animals is charged on every tick they exist, and a kill happens on a handful of them. Making the kill more profitable raises a number that is multiplied by something very small. Watch income as a share of rent rather than the population line: it is the number that says whether a row can pay for itself, and it is under one hundred percent in both runs.
The valley now has a level above the browsers that can do something about being hungry, and the run says it is not enough. What the run also says, in the two lines about what a body costs and what it brings back, is that the killing is the cheap part. And nothing about how any of those animals behaved changed how hard it hit: the blow is a multiplication over three numbers off the row an animal was stamped from, so the only thing that separates one striker from another is the body it inherited, and no gene describing temper alters it by a thousandth. There are three numbers in a genome here describing how an animal behaves, inherited and crossed and archived since the volume that installed them, and not one line of code in this world reads any of the three.