Skip to content
HN On Hacker News ↗

Sortis - A paper empire game

▲ 36 points 5 comments by jhylands 3w ago HN discussion ↗

Pangram verdict · v3.3

We believe that this document is fully human-written

3 %

AI likelihood · overall

Human
100% human-written 0% AI-generated
SEGMENTS · HUMAN 6 of 6
SEGMENTS · AI 0 of 6
WORD COUNT 1,881
PEAK AI % 4% · §5
Analyzed
Jun 16
backend: pangram/v3.3
Segments scanned
6 windows
avg 314 words each
Distribution
100 / 0%
human / AI fraction
Verdict
Human
Pangram v3.3

Article text · 1,881 words · 6 segments analyzed

Human AI-generated
§1 Human · 0%

I settled on the name Sortis from the latin because you don't play every turn in the game instead you skip ahead and calculate what happened at the point you want to make a genuine change to what's going on. Its a way of having the mechanics of the computer adding 1 wheat each turn without you having to manually add 1 wheat each turn. The literal translation is "of the lot/ of fate/ of oracle". Its etymology stretches back to a series, chain or row; which is equally relevant to this game. I'd love for the word to come to mean computationally reducible, a generalisation of closed form.

I have been working on a game recently that is played on paper but has the emergence of a procedural game like Minecraft, without forcing the player to do all the computation that would normally require.

What I wanted from this game was the feeling of progression, automation and discovery without needing anything other than pen and paper. I also wanted it to be something I could engage with that wouldn't rot my brain, but that I could actively do while very tired.

I feel I have achieved what I set out to.

If you are trained in computer science you will already know enough of the primitives to find the rules simple and memorable. If you haven't, then concepts like XOR and hexadecimal may need a little research. If you feel up to the effort, none of the concepts in this game are challenging to grasp.

The game is based on a grid world where each square is naturally water, forest or mountain. Forests can be cleared to build on, and there are a number of buildings. The aim of the game is to get the workshop to the highest level possible, and you do this using ever higher grades of ore. Ore is mined at a mine built on a mountain square. The build progression was inspired by OGame (a browser strategy game whose costs all climb on powers of two), so the formulas are all some form of \(2^n\). As the only player (the game is played alone in a notebook) you coordinate every agent in the game, of which you start with one.

The mapThe page with the map from one play through - coloured in.

The core aspect of the game that I found difficult to produce was an effectively procedurally generated map, without too much computation by hand and without needing dice or a calculator.

§2 Human · 1%

The ethos of the game is that everything can be done with just pen and paper, with no step much more complex than sudoku. The algorithm I stumbled across that worked for this was an LFSR random number generator, specifically over a single byte. Written out it looks complicated, but it reduces to something very simple.

To build the map you start by picking two numbers from 0–255, or 0x0–0xFF. One is for X and the other for Y. You then step these numbers as you increase X or Y using the following formula:

$$\text{step}(s) = \big((s \ll 1)\ \&\ \text{0xFF}\big) \mid (b_8 \oplus b_7 \oplus b_2 \oplus b_1)$$

That is: given a number \(s\) written in binary, take the XOR of the first two and last two digits, append that XOR to the end of the number, and drop the first digit so it stays 8 binary digits long. (Number the bits from either end you like, as long as you're consistent - the tap positions are symmetric, so it doesn't matter which.)

That gives you two number sequences starting from your two seeds, one for X and one for Y. To get the value for square \((x, y)\) you take the \(x\)-th number from the X sequence and the \(y\)-th number from the Y sequence and XOR them:

$$v(x, y) = \text{LFSR}^{x}(s_x) \oplus \text{LFSR}^{y}(s_y)$$

What we end up with is a random number at every square in the grid. The following rule converts a number into terrain:

ValueTerrain \(v < \text{0x75}\)Water \(\text{0x75} \le v < \text{0xE0}\)Forest \(v \ge \text{0xE0}\)Mountain

Because we XOR the two random numbers there are side-by-side correlations, which leads to water gathering into lakes and mountain ranges forming. For map-building rules, that's exactly what I wanted.

§3 Human · 1%

Also, given the cutoffs, you only need to calculate the first nibble of a square's number (so long as it isn't 0) to know what the square is. This speeds up map generation when I'm playing.

There is a further detail to the mountains whose importance becomes clear when I explain the mechanics. The number of trailing zeros of the square's value is the ore level of that square. So a mountain with an odd number has 0 trailing zeros and is ore(0), or stone. A number like E2, F2 or FA has 1 trailing zero, so its ore is ore(1). You might notice the highest possible ore on the map is ore(5), at E0. This is similar to how the Bitcoin algorithm gets harder as more people mine, and has the nice property that on average ore(n+1) is twice as rare as ore(n).

Exploring the map costs only the time you spend doing the XOR calculation and extending one of the sequences. Interestingly, the seeds you choose don't change the world you play in - there is precisely one world, 256×256 large. What the seeds do is place you randomly on it.

A seed of \(x+1\) is not a translation of the world from seed \(x\) by one square; it's a new random value. Since you'd never calculate all 65,536 squares by hand, it might as well be a new world to you.

Buildings

I wanted to keep the rules as simple as possible: enough to support an emergent playing style, but otherwise minimal. Buildings have levels, and I'll write L(N) for "level N" throughout - so a workshop L(3) is a level-3 workshop. To that end the buildings are:

House Workshop - whose max level is the aim of the game Extractor (sawmill or mine) Smelter (for getting past level 5) Road segment

And two vehicles: the wagon and the boat.

It's more building types than I would have hoped, but I think having both wood and ore as resources is needed (here I've folded both extractors into a single building type anyway). The house adds interesting limits on the number of agents through geography, which I think justifies its place.

§4 Human · 2%

The road could have been removed, but some late-game mechanics justify its existence; for the most part it can be ignored. Likewise the smelter - before level 5, smelting is a challenging way to expand when exploration is so cheap.

The house

Each agent (except the first) needs to be housed; they spawn when there is housing space. Houses have levels, each level allowing one more agent to live there, and each level costs exponentially more. A house costs \(2^n\) wood and starts at level 0, so a level-0 house costs 1 wood. That initial wood can come from clearing a forest, which yields 1 wood. To upgrade the house to level 1 you'd need 2 wood transported in, plus a level-1 workshop.

Workshop

In general, to build any building (other than a workshop) of level \(n\), you need a workshop of level \(n\). You also need the agent tasked with building or upgrading to level \(n\) to have visited a workshop of at least level \(n\). The workshop follows the same cost curve as the house, \(2^n\), but the resource required is ore(n).

Extractor

There are two resources, ore and wood. Extractor costs scale the same way as the house and workshop: \(2^n\). The sawmill requires \(2^n\) wood and the mine requires \(2^n\) ore(0). Unlike the workshop, the mine only needs low-grade ore to build or upgrade. Any higher grade ore can be used one-to-one as lower grade: if you need 1×ore(0) you can use 1×ore(1) in its place. It does not hold the other way - you cannot use ore(0) where ore(1) is required, unless you smelt it up. An extractor L(n) produces \((n+1)\) units per turn.

The smelter

To get past the natural ore limits you can smelt lower-grade ore into higher-grade ore, but it's very expensive. A smelter costs the same as a workshop of the same level: \(2^n\) ore(n). Once built, it converts \(2^n\) ore(n) + \(2^{n+1}\) wood into 1 ore(n+1). A smelter L(n) only accepts ore(n) or higher as its input.

§5 Human · 4%

There's no limit on the amount a single smelter can process, but the output isn't available until the turn after the inputs arrive. To reach the very highest levels you'll need to chain smelters together and feed the early ones truly huge amounts.

Road segment

This includes bridges, which can be built but are also very expensive. A road costs 1 ore(d) per square and must be on cleared land or on water. On land, \(d = 0\), so the cost is one ore(0) per square. For bridges, \(d\) is five plus the distance from shore: 1 square from shore requires ore(6), 2 squares from shore requires ore(7). Since the map tops out at ore(5), every bridge tile demands ore you can only reach by smelting - which is why bridges create a late game that almost no one will reach.

Playing the game

So far there's been a lot of explanation for a game I claimed is easy to remember and needs only pen and paper. The principle behind the agents is that they must travel to a square to act on it. The agents do the actions.

With that, let me start a game with you. We need a seed: \(x_\text{seed} = 01\), \(y_\text{seed} = 77\). Let's step X forward a few times to get some map.

Binary stepHex 0000 0001 → 0000 001101 → 03 0000 0011 → 0000 011003 → 06 0000 0110 → 0000 110106 → 0D 0000 1101 → 0001 10100D → 1A

X sequence: 01, 03, 06, 0D, 1A

And for Y:

Binary

§6 Human · 4%

stepHex 0111 0111 → 1110 111177 → EF 1110 1111 → 1101 1110EF → DE 1101 1110 → 1011 1101DE → BD 1011 1101 → 0111 1010BD → 7A

Y sequence: 77, EF, DE, BD, 7A

That's enough for a 5×5 grid. To get square (1,1) we take the first number of each sequence and XOR them: 77 XOR 01. You can convert to binary and go bit by bit, but here I spot that since the first nibble of X is 0, the first nibble of the answer is 7. Since it's a 7 we check the second nibble to see whether it's under 75 (water). For the XOR of 7 and 1, I know the 1 makes 7 even, so it's 6: 76, so this square is forest. Again you can fall back to binary, but you'll learn the hex XOR quickly. I do keep the binary expansions of A–E written at the top of the page:

HexBinaryDecimal A101010 B101111 C110012 D110113 E111014

The grid so far (rows are Y seeds, columns are X seeds):

0103060D1A 777674717A6D EFEEED    DE      BD      7A

Happily (1,1) is forest, so our agent can start there. From here they can leave it as forest and travel, clear the forest, or build a house.