The World Vol 9 · The Village
ch 99 / 105
Chapter 99

Drawing the Neighbours

Three people with seven fields each and no face among them

Halla is a name, a body number, two sentences of persona, a law profile, a home on cell 8,5, two hundred grams and a founding tick, and nothing on that row is a thing a renderer can draw. Ander is the same seven fields with other values in them. So is Mose. The last chapter ended with a line the hero model wrote for Ander kept in a field nothing reads, because a line that reaches a reader has to be said from a face and said in a box, and the village has neither. The face comes first, and it comes with a rule it has to obey before a pixel of it is placed.

The obvious way to give three people faces is to open an editor, draw three portraits, save them as three files, and load each one by the villager's name. That works for three. It puts a filename on the row, which is a field a line of simulation code could assign to; it makes the fourth villager an afternoon's work and the twentieth a week's; and it leaves three pictures in assets/ that no program can rebuild, which volume 6 named as the thing a contract cannot check. Nothing about a hand-saved portrait says it is the portrait of the row it is named after, and nothing can, because the row had no part in making it. A villager's face is arithmetic over its row. The parts are drawn once, on one sheet; which parts, and in which colours, is chosen off the record by a fold in a fixed order; the same row always makes the same face; and nothing about the face is stored anywhere.

Chapter 68 met this problem for animals and answered it with a genome: a creature's coat, markings, part and size are worked out from four numbers it was born with, every time it is drawn, and stored nowhere. A villager has no genome. What it has is the roll, and the roll is a record somebody wrote down on purpose, which is a better thing to draw a face from than four mutated floats. That is chapter 68's rule with the genome taken out and the roll put in its place, and this page says so once. No model is asked what Halla looks like, exactly as no model was asked what a genome looks like: a face is arithmetic over a row, and arithmetic replays.

By the end of the page there is a sheet of eighteen parts and a strip of seven colours, both written by a program and compared byte for byte with the pair the book ships; a fold short enough to work on paper that turns a name and a home cell into a number under 3072, and a peel that turns the number into a head, a pair of eyes, a mouth, a hair and a colouring; the three people of the roll composed twice from two reads of the file and found identical; and the same three composed off a random stream instead, twice, so that the thing the fold prevents is on the page and not in a warning.

Eighteen parts in seven of the sixteen, drawn as letters

A face here is sixteen pixels on a side. That is the cell every sheet in this book is cut on, the walker's, the tileset's, the creature sheet's, so the loader, the frame arithmetic and the blit all take the sheet as it is; and at sixteen a face has room for what a face needs. An eye is three pixels, a white on each side of a pupil, and two eyes two pixels apart is eight; a head ten wide leaves a column of outline each side of that and two columns of hair outside the outline; a mouth is four pixels one row high; and the rows above the eyes hold a brow and a crown, the rows below a nose, a mouth, a chin and a neck. Twelve was tried, by sampling, and the section after this one says what it lost. Twenty-four was not, because nothing in the list above wants a pixel it does not have.

The face is four parts laid over one another: a head, a pair of eyes, a mouth, and the hair, in that order, so the hair falls over the brow and not under it. Each part is one cell of one sheet, one row a kind: four heads, four pairs of eyes, four mouths, six hairs. Eighteen cells, drawn once. The heads share two lines so that the other parts can be drawn once and land on all of them: the eye line is row 7 and the mouth line is row 10; and every hair is drawn wide enough to cover the widest crown, so a hair seats on any of them. What the heads differ in is the skull's width, the jaw and the ears, because that is where one face differs from another: round, long, square and narrow.

Every part is drawn in seven of the valley's sixteen colours, and the seven are a choice about what a face is made of. Ink is the outline, the pupil and the mouth, and it is a fixed point of every colouring: an edge is ink whoever wears it. The three entries of the soil ramp are the skin, shadow, midtone and lit, for the same reason a coat took a whole ramp in chapter 68: a face in one flat colour has no form in it, and a face in three has a lit brow, a midtone cheek and a shaded jaw that move together when the colouring changes. The rock ramp's shadow and midtone are the hair, dark for the sides and lit for the crown, because the light in this world has come from the upper left since the walker and the crown is what it reaches first. Bone is the eye's white and the teeth, and it is the other fixed point.

⚙ Tool — a pixel editor, if you would rather draw than type

Every part below is drawn as characters and checked as pixels at four times, which needs no editor at all. If you would rather place pixels with a pencil, LibreSprite (libresprite.github.io) or Pixelorama (github.com/Orama-Interactive/Pixelorama) will load assets/palette/valley-16.gpl as a palette, which reduces the colour picker to exactly the sixteen this world allows; draw a ninety-six by sixty-four sheet with a sixteen-pixel grid on, export it with a real alpha channel, and carry each cell into the table a character at a time. The table is what ships, because the table is what a program can rebuild.

▣ Build · stage 1 — the sheet's terms, in the package that owns the row

Create internal/village/face.go. The counts are the sheet's grammar, the way TileCols and CellSoilA were the tileset's: nothing downstream parses folk.png to find out what is on it. They live in village and not in render, because the question they answer is about a person, and render does not know what a person is.

// internal/village/face.go
package village

import (
	"theworld/internal/gene"
	"theworld/internal/render"
)

// A villager's face is worked out from the row every time it is drawn
// and is stored nowhere. Nothing on Person names a head, a hair or a
// colour, exactly as nothing on beast.Beast names a coat: appearance is
// derived from the record, and a record that has not changed cannot be
// drawn two ways.
//
// The face is four parts laid over one another, each one cell of
// assets/sprites/folk.png: a head, a pair of eyes, a mouth, and the
// hair, in that order, so the hair falls over the brow rather than
// under it. The sheet holds one row a kind, Across cells wide, and the
// rows are in the order the parts are laid down.
const (
	Cell   = 16 // a part is this many pixels on a side, and so is a face
	Heads  = 4
	Eyes   = 4
	Mouths = 4
	Hairs  = 6
	Tints  = 8
	Faces  = Heads * Eyes * Mouths * Hairs * Tints // 3072
	Across = Hairs                                 // the longest row is the sheet's width
)

// The rows of the sheet, one kind of part each, top to bottom.
const (
	HeadRow = iota
	EyesRow
	MouthRow
	HairRow
	Rows
)

// Radix is how many of each part there are, in the order a face's
// number is peeled: the head is the lowest digit and the colouring the
// highest. A face is one number under Faces, and this is its base.
var Radix = [5]int{Heads, Eyes, Mouths, Hairs, Tints}

// Strip is the sheet's own palette: seven of the valley's sixteen, in
// the order the strip lists them. Every pixel of every part on the
// sheet is one of these, and a colouring is a substitution on them.
var Strip = [7]int{gene.Ink, gene.SoilD, gene.SoilM, gene.SoilL, gene.RockD, gene.RockM, gene.Bone}

// What each entry of the strip is on the sheet, by its position in
// Strip. Line and White are fixed points of every colouring: an
// outline is ink whoever wears it, and an eye's white is bone.
const (
	Line  = iota // every outline, every pupil, every mouth
	SkinD        // the skin's shadow: under the chin, the far cheek, the nose's side
	SkinM        // most of the face
	SkinL        // the lit brow and cheek
	HairD        // the hair's sides and underside
	HairL        // the crown, which the light reaches first
	White        // the eye's white, and teeth
)

village now imports gene, and the import is for one thing: gene.Sixteen is where the palette has been read out of its file since the creature sheet, and a palette written down twice can disagree with itself. Nothing about a genome crosses. Tints is eight and Faces is 3072, and both are explained further down, where the colourings are; the constants are here because the sheet is drawn to them.

▣ Build · stage 2 — the parts, as characters, and the program that writes the pair

Create cmd/mkfolk/art.go. Every pixel is a letter, a letter is an entry of the strip, and a space is a pixel that is not there, so a part is mostly space: a pair of eyes is six pixels of a cell of two hundred and fifty-six, and everything else in the cell lets the head show through. Four of the eighteen are printed here in full; the other fourteen are in the same form, and figure 99.1 shows all of them.

// cmd/mkfolk/art.go
//
//	o  outline      ink, never remapped: every edge, every pupil, every mouth
//	s  skin shadow  the far cheek, the side of the nose, under the chin
//	k  skin midtone most of the face
//	l  skin lit     the brow and the near cheek, where the light lands first
//	h  hair dark    the sides and the underside
//	H  hair lit     the crown
//	e  white        the eye's white, and teeth

// ...

// roundHead is the founding face: a skull that closes on row 2, ears
// on rows 6 and 7, cheeks that come in one column a row from row 10,
// and a chin on row 12. The eye line is row 7 and the mouth line row
// 10, which every head keeps, and the near cheek carries the one lit
// pixel the hair does not cover.
var roundHead = []string{
	"                ",
	"                ",
	"     oooooo     ",
	"    olkkkkko    ",
	"   olkkkkkkso   ",
	"   okkkkkkkso   ",
	"  okkkkkkkkkso  ",
	"  okkkkkkkkkso  ",
	"   okkkkskkso   ",
	"   olkkkskkso   ",
	"   okkkkkkkso   ",
	"    okkkksso    ",
	"     oooooo     ",
	"      osso      ",
	"      okko      ",
	"      oooo      ",
}

// ...

// openEyes are six pixels: white, pupil, white, twice, two pixels
// apart on row 7. Three pixels is the least an eye can be and still
// have a white on both sides of its pupil.
var openEyes = []string{
	"                ",
	"                ",
	"                ",
	"                ",
	"                ",
	"                ",
	"                ",
	"    eoe  eoe    ",
	"                ",
	"                ",
	"                ",
	"                ",
	"                ",
	"                ",
	"                ",
	"                ",
}

// ...

// smileMouth is the line with a pixel raised at each end, on row 9.
var smileMouth = []string{
	"                ",
	"                ",
	"                ",
	"                ",
	"                ",
	"                ",
	"                ",
	"                ",
	"                ",
	"     o    o     ",
	"      oooo      ",
	"                ",
	"                ",
	"                ",
	"                ",
	"                ",
}

// ...

// longHair falls to row 13 down both sides, outside the face at
// columns 2 and 3 and 12 and 13. It once sat one column further in and
// took the outer white off each eye; a test in this directory now
// composes every hair over every pair of eyes and refuses that.
var longHair = []string{
	"                ",
	"     oooooo     ",
	"    oHHHHhho    ",
	"  oHHHHhhhhhho  ",
	"  oHH      hho  ",
	"  oHh      hho  ",
	"  oH        ho  ",
	"  oH        ho  ",
	"  oH        ho  ",
	"  oh        ho  ",
	"  oh        ho  ",
	"  oh        ho  ",
	"  oho      oho  ",
	"  ooo      ooo  ",
	"                ",
	"                ",
}

// ...

Read the round head against the rules. The outline is closed all the way round, ink on every boundary pixel, so the face sits on any background; the far cheek at column 11 and the neck under the chin are shadow, the second of those because the chin is above it and not because of the angle; the nose is two pixels of shadow down its right side at rows 8 and 9; and the lit pixels are the upper-left brow and the near cheek at row 9, which is the one lit pixel a fringe cannot reach. The long hair has its own outline and its own row 1, so it covers the head's row 2 instead of joining it, and its sides run down columns 2 and 3, outside the face, with a lit strand on the near side where the crown's light continues.

Create cmd/mkfolk/main.go. Painting a part into the sheet is a lookup and a Set, and the lookup is the part that matters: a character with no strip entry behind it stops the program instead of putting a colour nobody chose into an asset. The array types are the second check, and it is free: a row with one part too many or too few does not compile.

// cmd/mkfolk/main.go
var key = []struct {
	ch   byte
	at   int
	what string
}{
	{'o', village.Line, "outline"},
	{'s', village.SkinD, "skin shadow"},
	{'k', village.SkinM, "skin midtone"},
	{'l', village.SkinL, "skin lit"},
	{'h', village.HairD, "hair dark"},
	{'H', village.HairL, "hair lit"},
	{'e', village.White, "white"},
}

// The four rows of the sheet, each the parts of one kind in the order
// the row holds them, and what each part is called when a run has to
// say which it picked. The array sizes are the package's counts, so a
// row with one part too many or too few does not compile.
var (
	heads  = [village.Heads][]string{roundHead, longHead, squareHead, narrowHead}
	eyes   = [village.Eyes][]string{openEyes, asideEyes, wideEyes, liddedEyes}
	mouths = [village.Mouths][]string{lineMouth, smileMouth, frownMouth, grinMouth}
	hairs  = [village.Hairs][]string{cropHair, longHair, bunHair, fringeHair, sweptHair, bareHair}

	// ...
)

// ...

// colour is the valley colour a strip position is drawn in.
func colour(pos int) render.Color {
	return gene.Sixteen[village.Strip[pos]]
}

// ...

// paint writes one mask into the sheet at a cell.
func paint(sh *render.Buffer, col, row int, mask []string) {
	if len(mask) != village.Cell {
		die(fmt.Errorf("row %d cell %d has %d rows, want %d", row, col, len(mask), village.Cell))
	}
	for y, line := range mask {
		if len(line) != village.Cell {
			die(fmt.Errorf("row %d cell %d line %d is %d characters, want %d", row, col, y, len(line), village.Cell))
		}
		for x := 0; x < village.Cell; x++ {
			ch := line[x]
			if ch == ' ' {
				continue
			}
			pos, ok := at(ch)
			if !ok {
				die(fmt.Errorf("row %d cell %d line %d: no palette entry for %q", row, col, y, ch))
			}
			sh.Set(col*village.Cell+x, row*village.Cell+y, colour(pos))
		}
	}
}

// ...

// build paints the whole sheet and the strip.
func build() (*render.Buffer, *render.Buffer) {
	sheet := render.NewBuffer(village.Across*village.Cell, village.Rows*village.Cell)
	for row, parts := range rows() {
		for col, mask := range parts {
			paint(sheet, col, row, mask)
		}
	}
	strip := render.NewBuffer(len(key), 1)
	for i, k := range key {
		strip.Set(i, 0, colour(k.at))
	}
	return sheet, strip
}
$ go run ./cmd/mkfolk -to .
mkfolk: folk.png, 96x64, 4 rows of parts across 6 cells at 16 pixels, 845 bytes
  pixels sha256 9bf56629912881799d6e6403038a4f2183defe4aa60ea47237a3913925621b76

  the seven entries the sheet is drawn in, by their index in the valley's sixteen
    o  entry  0  181A29  outline
    s  entry  1  4C2F22  skin shadow
    k  entry  2  75563B  skin midtone
    l  entry  3  A1875A  skin lit
    h  entry  4  323847  hair dark
    H  entry  5  5A6470  hair lit
    e  entry 15  F5EBD7  white

  part            drawn  outline   skin   hair  white
    round head      114       38     76      0      0
    long head       104       38     66      0      0
    square head     124       44     80      0      0
    narrow head     109       36     73      0      0
    open eye          6        2      0      0      4
    aside eye         6        2      0      0      4
    wide eye         12        2      0      0     10
    lidded eye       12        8      0      0      4
    line mouth        4        4      0      0      0
    smile mouth       6        6      0      0      0
    frown mouth       6        6      0      0      0
    grin mouth        6        2      0      0      4
    crop hair        34       14      0     20      0
    long hair        74       36      0     38      0
    bun hair         36       14      0     22      0
    fringe hair      68       26      0     42      0
    swept hair       34       13      0     21      0
    bare hair        16        8      0      8      0
  3072 faces the sheet can make: 4 heads x 4 eyes x 4 mouths x 6 hair x 8 colourings

mkfolk: folk-7.png, 7x1, 7 entries, 92 bytes
  pixels sha256 50f170e5c379f76d3762ba89ab2a49e64b3b5dbd26db13ae70ef3ca13d52c0a8
  pixels on the sheet the strip does not hold: 0
  folk.png is byte for byte assets/sprites/folk.png
  folk-7.png is byte for byte assets/palette/folk-7.png

Two files come out. The sheet is ninety-six pixels by sixty-four: six cells across and four rows down, with the two cells the shorter rows do not use left empty, and the count of what each row holds in the code and not in the picture. The strip is seven pixels by one, one pixel an entry, the form the valley palette and the creature strip have shipped in since they were chosen, so that the sheet's palette is a file a reader can diff. Run with -to naming a directory, the program writes the pair there and compares them with the pair the book ships, and the last two lines are the whole reason the sheet is code: nobody has to trust that the committed file is what the table makes, because the program says so every time it runs. The tally is what the parts weigh. A head is a hundred and four to a hundred and twenty-four pixels; the other three kinds together add between twenty-six and ninety-two, and the smallest part on the sheet, the line of a mouth, is four.

▣ Build · stage 3 — the sheet at four times, laid on a field

The sheet is mostly not there, so the picture of it is the sheet laid on a field of open water with a line of rock between the cells, written out at four times by -mode parts. The field and the rule are entries of the sixteen no face is drawn in, so nothing in the picture is a part that is not one.

$ go run ./cmd/mkfolk -mode parts -shot assets/frames/folk-parts.png
mkfolk: the sheet on a field, one cell a part, 103 by 69 pixels, c581890205440a60d7a8634fe8ed6372d73e2af202d0e83ed7cf615640102e72
  wrote assets/frames/folk-parts.png at 4 times, 412 by 276
A pixel drawing of a grid six cells across and four cells down on a mid-blue field with thin dark lines between the cells. The top row holds four brown heads with no hair, eyes or mouth: one round, one narrower and longer, one wide with a flat jaw, and one that tapers to a pointed chin; the last two cells are empty. The second row holds four pairs of small eyes drawn as cream whites with dark pupils: a plain pair, a pair with the pupils to the left, a taller round pair, and a pair with a dark bar above each eye; two cells empty. The third row holds four mouths in dark ink: a flat line, a line with raised corners, a line with dropped corners, and a wider mouth showing cream teeth; two cells empty. The bottom row holds six grey hairs with lit crowns: a close crop, a long fall down both sides, a crop with a knot on top, a straight fringe with sides to the jaw, a crop swept to the right, and a ring at the temples with nothing on top.
Figure 99.1assets/frames/folk-parts.png: the eighteen parts at four pixels to one, in the seven entries they are drawn in. Reading down: four heads, four pairs of eyes, four mouths, six hairs. Every head keeps its eye line on row 7 and its mouth line on row 10, so any cell of the second row and any cell of the third lands on skin on any cell of the first.

Two pixels between a line and a smile

The bar every asset in this book is held to was set when the walker was drawn, and it is one question: would you take a screenshot of this world without being asked to. At sixteen pixels a face clears it or does not on a handful of decisions, and the decisions are countable. The bench counts them. For each kind of part it takes every pair of cells in the row, counts the pixels the two differ in, and reports the closest pair, at the size the parts were drawn and at a smaller size the parts are sampled to the way the creature sheet was sampled to ten.

▣ Build · stage 4 — the closest pair of every kind, at sixteen and at twelve
$ go run ./cmd/mkfolk -mode small
mkfolk: the parts at 16 pixels, the size they were drawn, and sampled to 12

  kind     at 16  closest pair, and by how much   at 12  closest pair, and by how much
  heads       16  round and square                    3  round and square
  eyes         4  open and aside                      0  open and aside
  mouths       2  line and smile                      0  line and frown
  hair        11  crop and bun                        6  crop and swept

  the four pairs of eyes at 16, rows 5 to 8, one character a pixel, and the four mouths, rows 8 to 12
     5  ....................................................................
     6  ......................................eee..eee.........ooo..ooo.....
     7  ....eoe..eoe.........oee..oee.........eoe..eoe.........eoe..eoe.....
     8  ....................................................................
     8  ....................................................................
     9  ......................o....o........................................
    10  ......oooo.............oooo.............oooo............oeeeeo......
    11  .......................................o....o.......................
    12  ....................................................................

  the eyes sampled to 12, rows 3 to 5: the sampler reads source row y*16/12 and never reads rows [3 7 11 15]
     3  ....................................................
     4  ....................................................
     5  .............................eee.ee.......ooo.oo....

At sixteen, the smallest difference the library carries is two pixels: the line and the smile differ by the two raised corners on row 9, and the four pairs of eyes are never closer than four. On a screen that draws a frame pixel four pixels wide, which is how volume 2 opened the window, two pixels of difference is a mark eight screen pixels long, and the smile reads. At one pixel to one, the size of a full stop on this page, what reads is the hair and the colouring; the eyes are two dots and the mouth is a dash, and that is what the inspector under figure 99.1 is for.

Sampled to twelve, the table says what twelve costs, and it costs rows. The sampler reads source row y × 16 / 12 for each of its twelve rows, which reaches rows 0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13 and 14 and never rows 3, 7, 11 or 15. Row 7 is the eye line. Two of the four pairs of eyes are drawn on row 7 alone, so at twelve they are not there, and the closest pair of eyes differs by nought; the line and the frown differ on row 11 alone, so they are the same mouth. A hand-drawn twelve would place its pixels better than a sampler does, and it would still have one pixel for an eye and no room for a white on either side of it. Sixteen is the size at which an eye can be three pixels, and that is the whole of the argument for it.

Two more decisions were made by a program rather than by looking, and both are in cmd/mkfolk/art_test.go. The first composes every hair over every pair of eyes and every mouth on every head, 384 faces, and asks that every pixel the eyes and the mouth drew is still theirs afterwards. The long hair's first draft had its sides at columns 3 and 4, and column 4 is the outer white of the left eye, so every long-haired face would have had two-pixel eyes; the test is what stops the next hair doing the same. The second asks that every head has skin under every pixel an eye or a mouth can occupy, on rows 6, 7, 9, 10 and 11, and the narrow head failed it: its jaw came in a column at row 11, the frown's two dropped corners landed on the outline there, ink on ink, and a narrow-headed villager could not frown. Both parts were redrawn, and both tests are the reason a fifth head or a seventh hair cannot quietly bring either fault back.

▣ Build · stage 5 — three tests over the table, pinned
$ go test -count=1 ./cmd/mkfolk/ -run 'TestEveryPartIsSixteenSquareAndDrawnInTheStrip|TestEveryHeadHasSkinUnderTheEyesAndTheMouth|TestNoHairCoversAnEyeOrAMouth' -v
=== RUN   TestEveryPartIsSixteenSquareAndDrawnInTheStrip
--- PASS: TestEveryPartIsSixteenSquareAndDrawnInTheStrip (0.00s)
=== RUN   TestEveryHeadHasSkinUnderTheEyesAndTheMouth
--- PASS: TestEveryHeadHasSkinUnderTheEyesAndTheMouth (0.00s)
=== RUN   TestNoHairCoversAnEyeOrAMouth
--- PASS: TestNoHairCoversAnEyeOrAMouth (0.00s)
PASS
ok  	theworld/cmd/mkfolk	0.006s

The first of the three is paint's three refusals as a test, so a character outside the strip is caught before the program that would refuse it is run. The other two are the drawing rules above, held where a rule about pixels belongs: beside the pixels, in the directory that holds the table.

Seven turns of times thirty-one, and a number under 3072

Halla's row has to become one of the sheet's faces, and the sheet can make 4 × 4 × 4 × 6 × 8 of them, which is 3072. So the job is to turn a row into a number under 3072, and then to read the number as five digits: which head, which eyes, which mouth, which hair, which colouring. The second half is a mixed radix, and the book has done it twice already: a water cell's four neighbours became one number under sixteen in chapter 18, and a byte became a column and a row of the font sheet in chapter 21, both by dividing and keeping the remainder. The first half is a hash, and it is the oldest one there is.

∑ Math Interlude — the fold, worked for Halla, and the peel

Start with nought. For each value in turn, multiply what you have by 31, add the value, and keep the remainder on division by 65521. The values are the home column, then the home row, then the name a letter at a time, each letter as its byte: H is 72, a is 97, l is 108. Halla lives on 8,5.

0 × 31 + 8 = 8. Then 8 × 31 + 5 = 253. Then 253 × 31 + 72 = 7915. Then 7915 × 31 + 97 = 245462, and 245462 is 3 × 65521 + 48899, so the key is 48899. Then 48899 × 31 + 108 = 1515977, which is 23 × 65521 + 8994. Then 8994 × 31 + 108 = 278922, which is 4 × 65521 + 16838. Then 16838 × 31 + 97 = 522075, which is 7 × 65521 + 63428. Seven turns, one for each value, and the key is 63428.

63428 is 20 × 3072 + 1988, so Halla's face is number 1988. Now peel it, lowest digit first, each radix in the order the parts are laid down. 1988 divided by 4 is 497 remainder 0: head 0, the round one. 497 divided by 4 is 124 remainder 1: eyes 1, aside. 124 divided by 4 is 31 remainder 0: mouth 0, the line. 31 divided by 6 is 5 remainder 1: hair 1, long. 5 divided by 8 is 0 remainder 5: colouring 5. Run it back the other way and it is the same number: 5 × 6 is 30, plus 1 is 31; 31 × 4 is 124, plus 0; 124 × 4 is 496, plus 1 is 497; 497 × 4 is 1988, plus 0. Every number under 3072 is exactly one face and every face is exactly one number, which is what makes the radix a base and not a lookup.

Why 31, and why 65521. The multiplier is prime and small enough to multiply by hand, which is all that is asked of it; 31 is the value a great many string hashes have used since the nineties, and nothing else about it matters. The modulus does matter, and the shipped value was the second one tried. Taking the remainder on 3072 directly, so that the key was already a face number, looked simpler, and under it the fold has a habit: 2774 × 31 + 108 leaves 86 on division by 3072, and 86 × 31 + 108 leaves 2774 again, so two letters l in a row undo themselves and "Ha" and "Hall" are the same key. That is not one unlucky pair. The keys that return to themselves after "ll" under a modulus m are the solutions of 960 × k = −3456 modulo m, and 960 and 3072 share a factor of 192, so there are 192 of them: one key in sixteen. Under a prime there is one solution, one key in 65521. 65521 is the largest prime under 65536, the same modulus Adler-32 uses, and it keeps every intermediate value under seventy thousand.

keythe running value of the fold; nought before the first turn, 63428 after the last for Halla
valuewhat one turn folds in: the home column, the home row, or one letter's byte
31, 65521the multiplier and the modulus; the second is prime, and the box says why
a mod mthe remainder when a is divided by m: 245462 mod 65521 = 48899
3072how many faces the sheet can make: 4 × 4 × 4 × 6 × 8
radixthe base of one digit of a face: 4 for the head, 4 for the eyes, 4 for the mouth, 6 for the hair, 8 for the colouring, lowest first
peelremainder, then divide, once per radix: 1988 → 0, 1, 0, 1, 5
▣ Build · stage 6 — the fold and the peel, in the package that owns the row

Extend internal/village/face.go. Steps returns every turn so a bench can print the derivation and a reader can check it line by line; Key is its last value; FaceOf is the whole derivation, a row in and a face out, with no state anywhere; and Index is the peel run backwards, which a test walks for all 3072 numbers.

// internal/village/face.go — add below the strip's positions

// Face is which cell of each row a villager is drawn from, and which
// colouring the cells are put through. It is worked out from a Person
// by FaceOf and is never written back.
type Face struct {
	Head, Eyes, Mouth, Hair, Tint int
}

// The fold. A key is built from the row's fields by the oldest string
// hash there is: multiply what you have by Mult, add the next value,
// keep the remainder on division by Mod. The multiplier is small enough
// to work by hand and the modulus is the largest prime under 65536,
// prime because a multiplier and a modulus that share factors cycle:
// folded with the remainder taken on Faces instead, the letters "Ha"
// and "Hall" come to the same number.
const (
	Mult = 31
	Mod  = 65521
)

// Step is one turn of the fold, kept so a bench can print the whole
// derivation and a reader can check it line by line.
type Step struct {
	What  string // the field, or the letter
	Value int    // what was folded in
	Key   int    // the key after it
}

// fold is one turn: what there was times Mult, plus the value, mod Mod.
func fold(key, value, mod int) int {
	return (key*Mult + value) % mod
}

// Steps folds the two fields of the roll that make a person this
// person and not another, in a fixed order: the home column, the home
// row, then the name a byte at a time. The order is the whole of what
// makes the face total: the same row folded in the same order is the
// same number, and a field folded in a different place is a different
// number.
//
// The home goes in first. Whatever is folded last moves the key by
// exactly its own difference, so two rows alike in everything but that
// field differ by one, and one is the head alone. Neighbours a row
// apart are common in a village; names alike in every letter but the
// last are not.
//
// The persona is prose and stays out: it is read by people, not by
// arithmetic. The law profile stays out because a face that changed
// with it would be a law you can see, and law in this world is a file.
// Carrying stays out because it is the one number an operator is meant
// to change. The founding tick stays out because a village founded a
// tick later is the same village.
func Steps(p Person, mod int) []Step {
	var out []Step
	key := 0
	key = fold(key, p.Home.X, mod)
	out = append(out, Step{"home column", p.Home.X, key})
	key = fold(key, p.Home.Y, mod)
	out = append(out, Step{"home row", p.Home.Y, key})
	for i := 0; i < len(p.Name); i++ {
		key = fold(key, int(p.Name[i]), mod)
		out = append(out, Step{string(p.Name[i]), int(p.Name[i]), key})
	}
	return out
}

// Key is the fold's last value: one number under Mod for this row.
func Key(p Person) int {
	steps := Steps(p, Mod)
	return steps[len(steps)-1].Key
}

// FaceOf is the whole derivation: a row in, a face out, no state
// anywhere. The key is taken mod Faces, so that it names one of the
// faces the sheet can make, and then peeled.
func FaceOf(p Person) Face {
	return Peel(Key(p) % Faces)
}

// Peel writes a number under Faces in the sheet's mixed radix: the
// head is the remainder on division by Heads, the eyes the remainder of
// what is left on division by Eyes, and so on up to the colouring.
// Every number under Faces is exactly one face and every face is
// exactly one number.
func Peel(n int) Face {
	var d [5]int
	for i, r := range Radix {
		d[i] = n % r
		n /= r
	}
	return Face{Head: d[0], Eyes: d[1], Mouth: d[2], Hair: d[3], Tint: d[4]}
}

// Index is the peel run backwards: the one number under Faces this
// face is.
func (f Face) Index() int {
	d := [5]int{f.Head, f.Eyes, f.Mouth, f.Hair, f.Tint}
	n := 0
	for i := len(Radix) - 1; i >= 0; i-- {
		n = n*Radix[i] + d[i]
	}
	return n
}
$ go run ./cmd/mkfolk -mode key
mkfolk: the fold for Halla, home 8,5: times 31, plus the value, mod 65521

  folded in     value      key
  home column       8        8
  home row          5      253
  H                72     7915
  a                97    48899
  l               108     8994
  l               108    16838
  a                97    63428

  the key is 63428, and 63428 mod 3072 is 1988: face 1988 of the 3072 the sheet can make

  peeled, lowest digit first
     1988 mod 4 = 0  head      round
      497 mod 4 = 1  eyes      aside
      124 mod 4 = 0  mouth     line
       31 mod 6 = 1  hair      long
        5 mod 8 = 5  colouring light skin, brown hair
    and 1988 is 1988 back again: round head, aside eyes, line mouth, long hair, light skin, brown hair

  keys under 65521 that come back to themselves after "ll": 1 of 65521

The seven lines of the table are the seven turns of the interlude, and the peel under it is the interlude's second paragraph, so the two can be checked against each other line by line; the bench prints the modulus and the multiplier it used off the package's constants, and the last line counts the "ll" cycle under that modulus by trying every key. What the table shows about the fold's order is on its last line: the letter folded last adds itself to the key, so a row that differed from Halla's in its final letter alone would have a key one higher, and one higher is the next head. Exercise 2 runs that row. The home goes in first for exactly that reason: neighbours a row apart, which is what Halla and Mose are, get their one row of difference multiplied by 31 once for every letter that follows it, and neighbours are common in a village where a last letter's difference is not.

$ go run ./cmd/mkfolk -mode key -mod 3072
mkfolk: the fold for Halla, home 8,5: times 31, plus the value, mod 3072
  (the shipped modulus is 65521; this run is under 3072 off the flag)

  folded in     value      key
  home column       8        8
  home row          5      253
  H                72     1771
  a                97     2774
  l               108       86
  l               108     2774
  a                97       75

  the key is 75, and 75 mod 3072 is 75: face 75 of the 3072 the sheet can make

  peeled, lowest digit first
       75 mod 4 = 3  head      narrow
       18 mod 4 = 2  eyes      wide
        4 mod 4 = 0  mouth     line
        1 mod 6 = 1  hair      long
        0 mod 8 = 0  colouring dark skin, black hair
    and 75 is 75 back again: narrow head, wide eyes, line mouth, long hair, dark skin, black hair

  keys under 3072 that come back to themselves after "ll": 192 of 3072

The same seven values under the modulus that was tried first. The fourth and sixth lines are the cycle: after "a" the key is 2774, after "ll" it is 2774 again, and the last line counts a hundred and ninety-two keys under 3072 with that habit against one under 65521. Nothing else moved: under 3072 Halla is face 75, a narrow head with wide eyes and black hair, and there is nothing wrong with that face. What is wrong with the modulus is that one key in sixteen forgets two letters under it, and a fold that forgets letters is a fold whose collisions come in families instead of by chance.

Eight colourings on one strip

A face number's last digit is a colouring, and a colouring is a substitution on the strip: the three skin entries come out as one ramp and the two hair entries as one pair, and the outline and the white come out as themselves. Two skins is what sixteen colours buy, the soil ramp whole and the soil ramp moved one step toward bone, and five hairs: the rock ramp's shadow and midtone, which is how the sheet is drawn and reads as black; its midtone and lit, grey; the soil ramp's shadow and midtone, brown; soil's midtone under gold, blond; and soil's shadow under ember, red. Ten pairs of a skin and a hair, and eight of them ship.

The two that do not are the ones where the hair has no edge. Brown hair on dark skin puts the hair's lit crown, soil's midtone, on a brow that is soil's midtone, and enlarged the hair and the face were one brown lump with a darker rim; blond on dark skin puts its cap, soil's midtone again, on the same brow, which is the same pixel for the same reason. The rule that fell out of looking is that no entry of a hair may be the skin's midtone, and a test holds it, so that a ninth colouring added in a hurry cannot merge. The rule is a fact about this palette and these parts: hair meets skin along the brow with no ink between them, because an outline there reads as a hat, and where two materials meet with no line the tones have to do the separating.

▣ Build · stage 7 — the eight, as substitutions, and one face put through one of them

Extend internal/village/face.go. A colouring names five entries of the sixteen; Table is the substitution it makes on the seven, and Remap is that table as the pair of colour lists the blit takes, which is chapter 68's Look.Remap over a shorter list.

// internal/village/face.go — add below the strip's positions

// Tint is a colouring: which three entries of the sixteen the skin's
// shadow, midtone and lit come out as, and which two the hair's dark
// and lit come out as. Each is an index into gene.Sixteen.
type Tint struct {
	Name string
	Skin [3]int
	Hair [2]int
}

// The two skins and the five hairs the colourings are built from. Two
// skins is what sixteen colours buy: the soil ramp whole, and the soil
// ramp moved one step toward bone.
var (
	dark  = [3]int{gene.SoilD, gene.SoilM, gene.SoilL}
	light = [3]int{gene.SoilM, gene.SoilL, gene.Bone}
	black = [2]int{gene.RockD, gene.RockM}
	grey  = [2]int{gene.RockM, gene.RockL}
	brown = [2]int{gene.SoilD, gene.SoilM}
	blond = [2]int{gene.SoilM, gene.Gold}
	red   = [2]int{gene.SoilD, gene.Ember}
)

// Colourings are the eight the sheet may come out in. Not every pair
// of a skin and a hair is here: a hair whose entries include the skin's
// midtone has no edge against the brow, and brown hair on dark skin is
// exactly that pair, so it is left out and a test holds the rule.
var Colourings = [Tints]Tint{
	{"dark skin, black hair", dark, black},
	{"dark skin, grey hair", dark, grey},
	{"dark skin, red hair", dark, red},
	{"light skin, black hair", light, black},
	{"light skin, grey hair", light, grey},
	{"light skin, brown hair", light, brown},
	{"light skin, blond hair", light, blond},
	{"light skin, red hair", light, red},
}

// ...

// Table is the substitution this face makes on the strip: entry i of
// the seven comes out as entry Table()[i] of the sixteen. The outline
// and the white are fixed points; the skin's three and the hair's two
// come out as the colouring says.
func (f Face) Table() [7]int {
	t := Strip
	c := Colourings[f.Tint]
	t[SkinD], t[SkinM], t[SkinL] = c.Skin[0], c.Skin[1], c.Skin[2]
	t[HairD], t[HairL] = c.Hair[0], c.Hair[1]
	return t
}

// Remap is that table as the pair of colour lists the blit takes.
func (f Face) Remap() render.Remap {
	from := make([]render.Color, len(Strip))
	to := make([]render.Color, len(Strip))
	for i, j := range Strip {
		from[i] = gene.Sixteen[j]
	}
	for i, j := range f.Table() {
		to[i] = gene.Sixteen[j]
	}
	return render.Remap{From: from, To: to}
}

// Cells are the four source rectangles of the sheet this face is
// drawn from, in the order they are laid down.
func (f Face) Cells(s *render.Sheet) [Rows]render.Rect {
	return [Rows]render.Rect{
		s.Frame(f.Head, HeadRow),
		s.Frame(f.Eyes, EyesRow),
		s.Frame(f.Mouth, MouthRow),
		s.Frame(f.Hair, HairRow),
	}
}

// Draw lays the four cells over one another at (x, y) on the buffer,
// each put through the face's substitution on the way. A pixel a part
// does not hold leaves what is under it alone, which is how the eyes
// sit on the head and the hair sits on both.
func (f Face) Draw(b *render.Buffer, s *render.Sheet, x, y int) {
	m := f.Remap()
	for _, r := range f.Cells(s) {
		b.BlitMap(s, r, x, y, Cell, Cell, &m)
	}
}
$ go run ./cmd/mkfolk -mode tints
mkfolk: the 8 colourings, as substitutions on the strip's seven entries

   #  colouring                skin: shadow mid lit   hair: dark lit
   0  dark skin, black hair    4C2F22 75563B A1875A   323847 5A6470
   1  dark skin, grey hair     4C2F22 75563B A1875A   5A6470 8A979E
   2  dark skin, red hair      4C2F22 75563B A1875A   4C2F22 C75938
   3  light skin, black hair   75563B A1875A F5EBD7   323847 5A6470
   4  light skin, grey hair    75563B A1875A F5EBD7   5A6470 8A979E
   5  light skin, brown hair   75563B A1875A F5EBD7   4C2F22 75563B
   6  light skin, blond hair   75563B A1875A F5EBD7   75563B F0BE35
   7  light skin, red hair     75563B A1875A F5EBD7   4C2F22 C75938

  every colouring keeps the outline at entry 0 and the white at entry 15

  Halla's face as the sheet holds it, one character a pixel, each character a strip entry
    ................
    .....oooooo.....
    ....oHHHHhho....
    ..oHHHHhhhhhho..
    ..oHHkkkkkkhho..
    ..oHhkkkkkkhho..
    ..oHkkkkkkkkho..
    ..oHoeekkoeeho..
    ..oHkkkkskksho..
    ..ohlkkkskksho..
    ..ohkkooooksho..
    ..ohokkkkssoho..
    ..ohooooooooho..
    ..ooo.osso.ooo..
    ......okko......
    ......oooo......

  entry comes out   what it is on the sheet
     0         0   outline        181A29 -> 181A29
     1         2   skin shadow    4C2F22 -> 75563B
     2         3   skin midtone   75563B -> A1875A
     3        15   skin lit       A1875A -> F5EBD7
     4         1   hair dark      323847 -> 4C2F22
     5         2   hair lit       5A6470 -> 75563B
    15        15   white          F5EBD7 -> F5EBD7

  the same face through colouring 5, light skin, brown hair, each character an entry of the sixteen
    ................
    .....000000.....
    ....02222110....
    ..022221111110..
    ..022333333110..
    ..021333333110..
    ..023333333310..
    ..020ff330ff10..
    ..023333233210..
    ..01f333233210..
    ..013300003210..
    ..010333322010..
    ..010000000010..
    ..000.0220.000..
    ......0330......
    ......0000......

Draw is four calls to the blit chapter 68 wrote, at the cell's own size, through one substitution, and nothing in render changed for it: a composed face is a sheet cell blitted four times with the alpha channel doing the layering, which is what the alpha channel has been for since the sprite chapter. The two pictures of Halla are the same picture, and every character in the second is the first's put through the table above it: k became 3 where the table says entry 2 comes out as entry 3, h became 1, and the o of every outline and the e of each eye's white came out as themselves. The face is composed on the sheet's own colours and substituted on the way to the buffer, inside the blit, for the reason chapter 68's worked failure gave: once the pixels are down they are colours with no history, and a substitution run over a finished picture recolours whatever else happens to share an entry with a face.

▣ Build · stage 8 — the roll read twice, three faces composed twice, and three hashes that agree

The claim this page makes is that the same row always makes the same face, and the bench makes it as something that can fail: it reads the roll off the embedded file, composes a face for everyone in it, hashes the pixels, and then reads the roll again and does it all a second time.

$ go run ./cmd/mkfolk -mode faces
mkfolk: assets/sprites/folk.png, 96x64, 24 cells of 16
  parts chosen off each row: home column, home row, name, folded times 31 mod 65521

  pass 1: the roll read from the file, 3 people
  name    home   key  face  head, eyes, mouth, hair, colouring
  Halla   8,5  63428  1988  0 1 0 1 5  round head, aside eyes, line mouth, long hair, light skin, brown hair
                                     pixels sha256 c1b27d2f5782d9d2
  Ander   9,5  27844   196  0 1 0 3 0  round head, aside eyes, line mouth, fringe hair, dark skin, black hair
                                     pixels sha256 e48fca05e27fe03b
  Mose    8,6  54642  2418  2 0 3 1 6  square head, open eyes, grin mouth, long hair, light skin, blond hair
                                     pixels sha256 db7735226cb801c9

  pass 2: the roll read from the file, 3 people
  name    home   key  face  head, eyes, mouth, hair, colouring
  Halla   8,5  63428  1988  0 1 0 1 5  round head, aside eyes, line mouth, long hair, light skin, brown hair
                                     pixels sha256 c1b27d2f5782d9d2
  Ander   9,5  27844   196  0 1 0 3 0  round head, aside eyes, line mouth, fringe hair, dark skin, black hair
                                     pixels sha256 e48fca05e27fe03b
  Mose    8,6  54642  2418  2 0 3 1 6  square head, open eyes, grin mouth, long hair, light skin, blond hair
                                     pixels sha256 db7735226cb801c9

  the second pass agrees with the first for 3 of 3 faces

Three keys, three face numbers, three sets of five digits and three hashes, twice, and the second pass agrees with the first for all three. Halla is 1988, worked by hand above. Ander's key is 27844, which is 9 × 3072 + 196: round head, aside eyes, line mouth, fringe, dark skin and black hair. Mose's is 54642, which is 17 × 3072 + 2418: square head, open eyes, grin, long hair, light skin and blond hair. Halla and Ander share a head, a pair of eyes and a mouth, because 1988 and 196 leave the same remainder on division by 64, and what tells them apart is the hair and the colouring; at a glance that is what tells people apart anyway, and the test that pins this run refuses only two rows that come out as one face.

▣ Build · stage 9 — the three on a card, at four times
$ go run ./cmd/mkfolk -mode card -shot assets/frames/folk-three.png
mkfolk: the 3 people of the roll, composed off their rows
  Halla  face 1988  round head, aside eyes, line mouth, long hair, light skin, brown hair
  Ander  face  196  round head, aside eyes, line mouth, fringe hair, dark skin, black hair
  Mose   face 2418  square head, open eyes, grin mouth, long hair, light skin, blond hair
  the card 108 by 37 pixels, 285ceee38555cf3d1db6b9600c3dd70380c8ac013c1a1b368ec1becc13ee8dc1
  wrote assets/frames/folk-three.png at 4 times, 432 by 148
Three pixel-art portraits in a row on a mid-blue field, each with a name in cream capitals under it. Halla, on the left, has a round tan face with long brown hair falling past her jaw on both sides, eyes glancing to her left and a flat mouth. Ander, in the middle, has a round dark-brown face under a straight black fringe with sides down to the jaw, the same glancing eyes and flat mouth. Mose, on the right, has a wide tan face with a flat jaw, long blond hair, eyes looking straight ahead and a wide grin showing teeth.
Figure 99.2assets/frames/folk-three.png: Halla, Ander and Mose, composed off their rows, at four pixels to one. Every pixel of all three is one of the valley's sixteen, and every part on every face is a cell of figure 99.1 put through one of the eight tables.
▣ Build · stage 10 — three tests over the fold, pinned
$ go test -count=1 ./internal/village/ -run 'TestTheSameRowMakesTheSameFace|TestEveryNumberUnderFacesIsOneFaceAndBack|TestNoColouringPutsTheHairOnTheSkinsMidtone' -v
=== RUN   TestTheSameRowMakesTheSameFace
--- PASS: TestTheSameRowMakesTheSameFace (0.00s)
=== RUN   TestEveryNumberUnderFacesIsOneFaceAndBack
--- PASS: TestEveryNumberUnderFacesIsOneFaceAndBack (0.00s)
=== RUN   TestNoColouringPutsTheHairOnTheSkinsMidtone
--- PASS: TestNoColouringPutsTheHairOnTheSkinsMidtone (0.00s)
PASS
ok  	theworld/internal/village	0.005s

The first reads the roll twice and asks for the same key and the same face for everyone; then it moves each person one row south and adds a letter to each name and asks for a different key both times; then it blanks the persona, changes the law to bandit, empties the grams and moves the founding tick, and asks that the face did not move. The second walks all 3072 numbers through Peel and Index and asks that each comes back as itself and that no two peel to one face. The third is the colouring rule from above, and it also asks that every entry a colouring names is one of the sixteen and that the outline and the white are fixed points of every table.

⚠ Worked failure — parts chosen at random, run

The fold is seven lines of arithmetic, and a reader who has met a random stream knows a shorter way: draw five numbers off a stream and read them as the five digits. It costs nothing, every face on the sheet is reachable, and the bench does it off a flag. The stream is seeded, as every stream in this book is, so the run below is exact; the seed is on the flag, because there is nowhere else for it to be.

$ go run ./cmd/mkfolk -mode card -random -seed 1
mkfolk: the 3 people of the roll, parts chosen at random off seed 1, which is nothing on any row
  Halla  face 1579  narrow head, wide eyes, frown mouth, crop hair, light skin, grey hair
  Ander  face 1608  round head, wide eyes, line mouth, long hair, light skin, grey hair
  Mose   face 1163  narrow head, wide eyes, line mouth, crop hair, light skin, black hair
  the card 108 by 37 pixels, eba92a190c8bb8deb14ee4ee17268b496dd41fe8772fd43a2e784ea968f15c16
$ go run ./cmd/mkfolk -mode card -random -seed 2
mkfolk: the 3 people of the roll, parts chosen at random off seed 2, which is nothing on any row
  Halla  face  875  narrow head, wide eyes, frown mouth, long hair, dark skin, red hair
  Ander  face 2240  round head, open eyes, line mouth, bare hair, light skin, brown hair
  Mose   face 2009  long head, wide eyes, smile mouth, long hair, light skin, brown hair
  the card 108 by 37 pixels, 03fbe61344a4d310ac6f52c8bb197e54379d5f5503e552aabd6f6efe2cb9f209

Two runs, the same file, and Halla has two faces: a grey-haired crop with a frown under seed 1, and long red hair under seed 2, on a narrow head both times by luck. Start from the symptom and work back. The row did not change between the runs, so nothing that changed came from the row; what changed was the seed, and the seed is not on any row, it is on the command line, which means the face belongs to whoever started the program and not to Halla. Under one seed the run replays, and that is the trap: -mode faces -random -seed 1 reads the roll twice and agrees with itself three of three, exactly as the fold does, so a test that reads the roll twice under one seed cannot tell the two designs apart. Look at Ander instead. His digits come off the stream after Halla's, so his face depends on the order the file lists the people in and on Halla existing at all; put Mose first in the file and everyone's face moves, and found a fourth villager and the fifth's face moves. A face drawn off a stream is a fact about the run, and a face folded off a row is a fact about the row. The fix is the rest of this page.

Why faces come from row numbers

The mechanism underneath this chapter is the one under chapter 18's tileset and chapter 21's font, and it is the same move each time: several small choices are one number, and a number can be stored, compared, printed and taken apart without anybody agreeing on what its digits mean beyond the radix. Four neighbours were a mask under sixteen; a byte was a column and a row under sixteen columns; five parts are a face under 3072, with a radix a digit. What this chapter adds is the front half: the number does not have to be given, it can be made, and a hash is nothing more than a way of making one number out of several values in a fixed order so that the same values always make the same number. Every property the page argued for falls out of that order being fixed. A row read twice is the same number. A row with one field changed is a different number. A row nobody wrote down, a stream, a clock, a seed on a flag, has no number to make.

The second thing underneath is chapter 68's, unchanged: a phenotype is computed, and a computed thing cannot get out of step with what it is computed from. There is no face field on Person for a line of simulation code to assign to, no portrait file for an editor to leave stale, and no cache to invalidate when the roll changes; a headless run through two centuries of ticks never calls FaceOf once, and a run that draws the village calls it every time it draws, for a few dozen multiplications a face. The derivation lives in village because a question about what a row means belongs with the row, and the blit lives in render, which gained nothing on this page: a face is four cells of a sheet through one substitution, and the renderer already knew how to do that for an animal.

The road from a villager's row to sixteen pixels, and the two places nothing is allowed to go Five boxes in a row joined by arrows. The first is the row, listing the name Halla and the home 8,5 as the two fields that are folded, and the persona, law, grams and founding tick as fields that are not. The second is the fold: home column, home row, then the letters, each turn times 31 plus the value mod 65521, giving 63428. The third is the peel: 63428 mod 3072 is 1988, which peels to 0, 1, 0, 1, 5. The fourth is the sheet: cell 0 of row 0, cell 1 of row 1, cell 0 of row 2, cell 1 of row 3, and colouring 5 as a table over the strip. The fifth is the blit: four cells through one substitution onto sixteen by sixteen pixels of colours only. Below, two dashed crossed arrows: one from the peel down to a box reading village.Person, no face field, nothing written back; and one from a box reading a model, never asked, up to the fold. FOLDED EVERY TIME, STORED NOWHERE, ASKED OF NOBODY THE ROW Halla home 8,5 persona, law, grams, founded: not folded THE FOLD x, y, H a l l a ×31 + value mod 65521 63428 THE PEEL mod 3072 = 1988 0 1 0 1 5 head eyes mouth hair colouring radix 4 4 4 6 8 THE SHEET row 0 cell 0 row 1 cell 1 row 2 cell 0 row 3 cell 1 colouring 5 THE BLIT four cells, one table 16 × 16 colours only village.Person no face field nothing written back a model never asked THE SAME ROW, FOLDED IN THE SAME ORDER, IS THE SAME NUMBER, AND THE NUMBER IS THE FACE
Figure 99.3 — the road from a row to pixels. Two of the row's seven fields are folded and five are not; the fold's number is peeled into four cells and a table; the blit lays the cells down through the table. The two crossed arrows are the rules: nothing worked out on the way is written back onto the person, and no model is asked what anybody looks like.

What the design costs is stated on the page rather than hidden in it. Two rows one letter apart in the last letter are two faces one head apart, because the fold's last turn adds the letter; the home goes in first so that the common case, two neighbours, is not the cheap one. A roll of twenty people has sixty-four ways to combine a head, eyes and a mouth, and twenty draws from sixty-four nearly always share one, as two of these three already do, and the sheet's answer to that is more parts, not a better hash: a fifth head is a row of the table and one constant, and the tests here already refuse a fifth head with a jaw too narrow for the frown or a seventh hair that covers an eye. And a face that is arithmetic is a face an operator can change only by changing the row, which is the point and is also a limit: Halla cannot be given a different face without being given a different name or a different home, because there is nothing else about her the face is made of.

✓ Checkpoint — a sheet, a fold and three faces
  • Fold a villager's home column, home row and name by hand, seven turns of times 31 plus the value mod 65521, and check the key against -mode key turn by turn.
  • Peel a number under 3072 into a head, a pair of eyes, a mouth, a hair and a colouring, lowest digit first, and run it back to the number.
  • Say why the home is folded before the name, what a change in the last letter alone does to the key, and which digit that moves.
  • Name the seven entries the sheet is drawn in, say which two are fixed points of every colouring, and say why brown hair on dark skin is not one of the eight.
  • Say which source rows the sampler skips at twelve, why the eye line is one of them, and what that does to the closest pair of eyes and the closest pair of mouths.
  • Run the random flag under two seeds, say what changes between the runs and what does not, and say why Ander's face under a seed depends on Halla's.
⚡ Exercises — try first, then reveal
Exercise 1 — Mose, on paper. Mose lives on 8,6. Fold his row by hand, six turns, and peel the result, before running -mode key -who Mose.

0 × 31 + 8 = 8; 8 × 31 + 6 = 254; 254 × 31 + 77 = 7951; 7951 × 31 + 111 = 246592, which is 3 × 65521 + 50029; 50029 × 31 + 115 = 1551014, which is 23 × 65521 + 44031; 44031 × 31 + 101 = 1365062, which is 20 × 65521 + 54642. Then 54642 is 17 × 3072 + 2418, and 2418 peels to 2, 0, 3, 1, 6: a square head, open eyes, the grin, long hair, and light skin under blond hair. The second turn is the only one that differs from Halla's, 254 against 253, and by the third turn the two keys are 36 apart and never near each other again.

$ go run ./cmd/mkfolk -mode key -who Mose
mkfolk: the fold for Mose, home 8,6: times 31, plus the value, mod 65521

  folded in     value      key
  home column       8        8
  home row          6      254
  M                77     7951
  o               111    50029
  s               115    44031
  e               101    54642

  the key is 54642, and 54642 mod 3072 is 2418: face 2418 of the 3072 the sheet can make

  peeled, lowest digit first
     2418 mod 4 = 2  head      square
      604 mod 4 = 0  eyes      open
      151 mod 4 = 3  mouth     grin
       37 mod 6 = 1  hair      long
        6 mod 8 = 6  colouring light skin, blond hair
    and 2418 is 2418 back again: square head, open eyes, grin mouth, long hair, light skin, blond hair

  keys under 65521 that come back to themselves after "ll": 1 of 65521
Exercise 2 — one letter away. The key mode takes a name and a home that are in no roll. Before running -mode key -name Hallb -home 8,5, say what the key will be and which of Halla's five digits will move.

Every turn but the last is Halla's, because the first six values are the same; the last adds 98 where Halla's added 97, so the key is 63429 and the face is 1989. One more, lowest digit first, is the head: 1989 mod 4 is 1, the long head, and the other four digits are Halla's. The test in face_test.go adds a letter after the last one instead, which is one more turn of the fold, and there the whole key moves.

$ go run ./cmd/mkfolk -mode key -name Hallb -home 8,5
mkfolk: the fold for Hallb, home 8,5: times 31, plus the value, mod 65521

  folded in     value      key
  home column       8        8
  home row          5      253
  H                72     7915
  a                97    48899
  l               108     8994
  l               108    16838
  b                98    63429

  the key is 63429, and 63429 mod 3072 is 1989: face 1989 of the 3072 the sheet can make

  peeled, lowest digit first
     1989 mod 4 = 1  head      long
      497 mod 4 = 1  eyes      aside
      124 mod 4 = 0  mouth     line
       31 mod 6 = 1  hair      long
        5 mod 8 = 5  colouring light skin, brown hair
    and 1989 is 1989 back again: long head, aside eyes, line mouth, long hair, light skin, brown hair

  keys under 65521 that come back to themselves after "ll": 1 of 65521
Exercise 3 — twenty-four, by the same sampler. Run -mode small -at 24. Say before you run it what the closest pairs will be, and then explain why the eyes at twenty-four are not all the same width.

Nothing collapses going up: every source row is read at least once, so no two parts become one. The heads, the eyes and the mouths keep their closest pairs, with the differences grown by the sampling to 32, 6 and 3; the hair's closest pair changes, from the crop and the bun at eleven to the crop and the swept at twenty-four, because the columns the sampler reads twice fall on the two pairs differently. What twenty-four adds is unevenness. Twenty-four over sixteen is one and a half, and a pixel cannot be sampled one and a half times, so alternate source columns are read twice and once, and a three-pixel eye comes out five wide on the left and four wide on the right. An enlargement that is a whole number reads every source pixel the same number of times, which is why the figures on this page are at four and the inspector offers one, two and four.

$ go run ./cmd/mkfolk -mode small -at 24 | tail -7
  the eyes sampled to 24, rows 7 to 12: the sampler reads source row y*16/24 and never reads rows []
     7  ....................................................................................................
     8  ....................................................................................................
     9  ........................................................eeeee...eeee.............ooooo...oooo.......
    10  ........................................................eeeee...eeee.............ooooo...oooo.......
    11  ......eeoee...eooe.............ooeee...oeee.............eeoee...eooe.............eeoee...eooe.......
    12  ....................................................................................................

Three people have faces, and each face is a number a reader can work out from the roll with a pencil and check against a sheet the program rebuilds on every run. A face is sixteen pixels and Halla's name is thirty pixels of six-by-eight glyphs; what neither has is a place to be said from, and a line the hero model writes, wrapped to a width and set beside a face in a frame that stretches to fit it, is a picture the renderer has never drawn. It has a font, a blit that clips, and a text width it can measure; it does not have a box.