World space & grids

Racing track grid

racing-track-grid · an adoption of Grid and direction, version 1

Tests included

Use in your game

Opens the authoring tool with these answers and settings already filled in. You still add your game's own rules and tuning.

What is in the ZIP

The ZIP holds the adoption and its acceptance tests. In the authoring tool, choose Add contract and pick this ZIP. If you keep your design as files, put them in contracts/.

The contract behind it

Covers square grids and the direction words your game uses. It says where numbering starts, which cells touch, and how a position belongs to a cell. It says how rules measure distance, choose between equal cells, list cells in order, and turn. Grid edges, pathfinding, non-square cells, and a third axis stay with your game.

Read the full Grid and direction contract →

Questions

The supplied answer is marked on each question. Pick other answers to see what changes. Nothing is saved here: the ZIP and the authoring tool use the supplied answers.

Where is this grid's first cell, and which way do its row and column numbers grow?

Choices for Where is this grid's first cell, and which way do its row and column numbers grow?
Supplied answer The first cell is the top-left corner. Column numbers grow right, and row numbers grow down.
The first cell is the bottom-left corner. Column numbers grow right, and row numbers grow up.
There is no first cell or corner. The grid continues through negative and positive numbers. Columns grow right, and rows grow down from the cell your game calls zero.
There is no first cell or corner. The grid continues through negative and positive numbers. Columns grow right, and rows grow up from the cell your game calls zero.
Why this is asked

Every later rule needs one shared reading of row and column numbers. This contract only carries columns that grow right; state a left-growing grid in your own prose.

When you write a cell with two numbers, does the row or column come first?

Choices for When you write a cell with two numbers, does the row or column come first?
Supplied answer The column comes first. The pair (3, 5) means column 3, row 5.
The row comes first. The pair (3, 5) means row 3, column 5.
The game never names a cell with a pair of numbers. It uses a layout, cell contents, or another name instead.
Why this is asked

Swapping the two numbers turns rows into columns. A square grid can hide that mistake, so the order must be clear.

Do the first row and column use zero or one?

Asked when
Origin and axes is Top left or Bottom left.
Choices for Do the first row and column use zero or one?
Supplied answer The first row and column are numbered zero. A ten-cell row runs from zero through nine.
The first row and column are numbered one. A ten-cell row runs from one through ten.
Why this is asked

Starting at zero or one changes every written cell address. Naming it prevents an off-by-one shift between the design and the build.

A point lies exactly on the line between two cells. Which cell owns it?

Choices for A point lies exactly on the line between two cells. Which cell owns it?
Supplied answer The cell with the larger number owns the line. The line where cell five ends and cell six begins belongs to cell six, on either side of zero.

Divide the position by cell-size and round down, then add one when counting-starts-at is one. A boundary position belongs to the cell with the larger coordinate.

The cell farther from zero owns the line. The zero cell reaches one cell-size to each side, so it is twice as wide as the others.

Divide the position by cell-size and truncate toward zero, then add one when counting-starts-at is one. Coordinate zero spans one cell-size on each side.

Whole numbers mark cell centres. A point halfway between two centres belongs to the cell with the larger number.

Cell coordinates name centres. Divide the position by cell-size and round to the nearest whole coordinate, taking an exact half toward the larger coordinate, then add one when counting-starts-at is one.

Your rules only use whole cells, never positions between them. No boundary choice is needed.
Why this is asked

A boundary point needs one owner. Different rounding rules can place the same point in different cells, especially beside zero.

When your rules say nearest or within some distance, how do they measure between cells?

Choices for When your rules say nearest or within some distance, how do they measure between cells?
Add the steps across and down the grid (Manhattan). A cell two across and one up is three steps away.
Count the larger of the across and down steps (Chebyshev). A cell two across and one up is two steps away.
Straight steps cost one, and diagonal steps cost the square root of two (octile). The distance is the cheapest mix of those steps. Your game's comparison rule decides when two distances count as equal.

For absolute coordinate differences dx and dy, multiply the smaller difference by the square root of two minus one (about 0.414), then add the result to the larger difference. Equal means equal at whatever precision this game compares its distances with. For straight-line and octile distance, the adoption must state that comparison rule in the distance test's verification scope.

Measure a straight line between the cell centres (Euclidean). Use position units when positions exist; otherwise use cells. Your game's comparison rule decides when two distances count as equal.

Equal means equal at whatever precision this game compares its distances with. For straight-line and octile distance, the adoption must state that comparison rule in the distance test's verification scope.

Supplied answer No rule measures distance between cells. Rules may still use neighbours, named shapes, or links.
Why this is asked

Games often use several distance rules. This answer only controls what your written rules mean by nearest or within a distance.

From one cell, which other cells can a thing reach in one step?

Choices for From one cell, which other cells can a thing reach in one step?
Only the four cells sharing an edge are one step away. A diagonal cell cannot be reached in one step.
All eight surrounding cells are one step away. A thing may move across an edge or diagonally across a corner.
Supplied answer Nothing moves one cell at a time. Things are placed directly or move freely while the grid only reads their final cell.
Why this is asked

Movement neighbours do not follow automatically from distance or effect range. A game can use different cells for each.

When a rule says two cells are next to each other, do corners count?

Choices for When a rule says two cells are next to each other, do corners count?
Supplied answer Only cells sharing an edge count as neighbours. Two cells touching only at a corner are not next to each other.
All eight surrounding cells count as neighbours. Cells touching only at a corner are still next to each other.
No rule uses next to by itself. Each rule names the cells it means, or no rule asks whether cells are neighbours.
Why this is asked

Movement and effects can count neighbours differently. This answer keeps words such as next to from changing meaning between rules.

In what order does an authored layout list its cells?

Choices for In what order does an authored layout list its cells?
Supplied answer List every cell in one row before starting the next row. Start with the smallest row and column numbers. A text map with one line per row already uses this order.
List every cell in one column before starting the next column. Start with the smallest row and column numbers.
List cells inside blocks such as chunks, regions, or screens. Your game's prose states block size, block order, and the order inside each block.
No authored layout lists the grid's cells. No order is needed for the material designers write and read.
Why this is asked

Drawing, updates, and save files may use different orders. This answer covers only layouts designers write and read.

A rule rates two cells equally and must pick one. How does it decide?

Choices for A rule rates two cells equally and must pick one. How does it decide?
Supplied answer The cell with the smaller column number wins. Between a cell in column 2 and a cell in column 4, the column-2 cell wins and the column-4 cell loses. If columns match, the smaller row number wins.
The cell with the smaller row number wins. Between a cell in row 2 and a cell in row 4, the row-2 cell wins and the row-4 cell loses. If rows match, the smaller column number wins.
Walk the grid-fixed direction words in their chosen order. The first direction that points to a tied neighbour wins. Use another answer when tied cells are not neighbours.
The candidate that arrived first wins. Your game names whether arrival means creation, placement, storage, or entering play. The same run repeats the choice, but save and reload follow your persistence rules. The validator (the checking tool) cannot check this; a reviewer does.
The candidate kind listed first in your game's priority order wins. Cell position never decides.
Either candidate may win, and players must not depend on which one. Replaying the same run repeats the choice, but loading a save may not.
Draw one candidate from a random stream declared by your game. The same run and replay draw the same candidate. The validator cannot check this; a reviewer does.
The player chooses the candidate. If the game cannot ask, the rule does nothing instead of guessing. The validator cannot check this; a reviewer does.
No rule ever chooses one of two equal candidates. The situation cannot happen, or the rule affects every tied candidate.
Why this is asked

Equal choices are common and rarely written down. A fixed answer stops two builds from choosing different cells.

When your rules turn a facing by an amount, which way does the amount go on the grid?

Choices for When your rules turn a facing by an amount, which way does the amount go on the grid?
Supplied answer A positive turn goes clockwise on the grid. A rotated view may show it differently, but the grid rule stays the same.
A positive turn goes counter-clockwise on the grid. A rotated view may show it differently, but the grid rule stays the same.
No rule turns a facing by an amount. A piece may still snap directly toward movement or a target.
Why this is asked

Axis direction does not decide turn direction. Naming clockwise or counter-clockwise prevents equivalent formulas from reading as opposite rules.

Numbers1 number

Each value is either a number set here or a reference to one of your tuning keys.

Cell size = 4

fixed as written

cell-size

The length of one cell in your position units. For centre-based cells, measure from one centre to the next. Use a positive size when rules read positions. Use zero when they only read whole cells. Changing this number changes which cell holds a position.

Rules1 rule

A rule is a check between the numbers. Validation reports a rule that fails.

  • cell-size >= 0
Lists1 list

Each list holds the rows this adoption supplies. A list can be empty.

Directions

directions

IdFramePointsOrder
rightwardgridright
downwardgriddown
forwardpiece
rightpiece
Test inputsscope and seeds

Some tests need a scope or seeds from the adoption before they can run.

every-position-has-one-cell

Every position has one cell

Scope
the car's position at the start and end of every tick over one run, and every wake sample point read along a tick's sweep, including positions off the declared grid and on both sides of zero
Seeds
["racing-track-position-a","racing-track-position-b"]

next-to-means

Next to means

Scope
the layout rules that require the track cells to form one joined-up group and each route band to form one joined-up group, checked over both declared layouts and over deliberately broken copies of them
Seeds
["racing-track-neighbours-a","racing-track-neighbours-b"]

tie-break-settles

Tie break settles

Scope
from cell (4, 4), candidate cells (3, 5) and (5, 3) take equal route travel; cell (3, 5) wins and cell (5, 3) loses
Acceptance tests13 tests apply

The contract comes with 22 tests. A test that runs once per row is counted once for each row. Tests that do not apply to these answers are still listed, with the reason.

axes-grow

the numbers grow one way

scenarioonce

Applies to racing-track-grid.

In racing-track-grid the two numbers grow right across rows and down columns, one per cell. The layout this is read against is the one this package declares, not the finished picture: a build may draw the grid any way its presentation chapter allows and still has to number it this way.

Test steps and diagnostics
Given

racing-track-grid as this package lays it out, with at least two rows and at least two columns

When
  • a cell is located in the layout
  • the cells one step from it across and down are located
Then
  • the numbers grow right across rows and down columns
  • moving one cell that way raises exactly one of the two numbers by one and lowers neither
  • moving one cell the opposite way lowers exactly one of them by one
Diagnostics
  • racing-track-grid-cell-addresses
  • racing-track-grid-declared-layout

the-first-cell-is-in-one-corner

the grid has a first cell, in one named corner

scenarioonce

Applies to racing-track-grid.

racing-track-grid is a bounded rectangle whose first cell — the one whose two numbers are both smallest — is the top-left corner of the grid as this package lays it out. A build that numbers from the opposite corner fails this test even when every layout still loads.

Test steps and diagnostics
Given

racing-track-grid as this package lays it out

When
  • the cell whose two numbers are both the smallest on the grid is located in the layout
Then
  • that cell is the top-left corner of the grid as this package lays it out
  • no other corner of racing-track-grid holds a smaller pair of numbers
  • the grid is bounded: every cell of it lies inside the declared number of rows and columns
Diagnostics
  • racing-track-grid-cell-addresses
  • racing-track-grid-declared-layout

the-grid-has-no-first-cell

the grid runs on in every direction

scenarioonce

Does not apply to racing-track-grid: origin and axes is top left, not unbounded right and down or unbounded right and up.

coordinate-reading

a written pair names the cell this package means

scenarioonce

Applies to racing-track-grid.

In racing-track-grid, the first number is the column, counted across the grid, and the second is the row, counted down it, and the first row and the first column are numbered 0. The test asks for a grid whose rows and columns differ in number on purpose: on a square grid a build that reads the pair backwards passes every test anyone would think to write, and ships transposed. One surveyed game numbers its authored map files from one and its engine from zero, and records that nowhere but a source comment. The numbers this test is about are the ones this package's own material writes.

Test steps and diagnostics
Given

racing-track-grid with a different number of rows and columns, so that reading a pair the wrong way round cannot land on a real cell by luck, or a stated reason why no such grid exists in this game

When
  • the build resolves a cell that this package's own material writes as a pair of numbers
Then
  • the first number is the column, counted across the grid, and the second is the row, counted down it
  • the first row and the first column are numbered 0
  • the cell the build resolves is the cell this package's material means
  • the same pair with its two numbers swapped resolves to a different cell, or to no cell at all
Diagnostics
  • racing-track-grid-resolved-cell
  • racing-track-grid-source-reference

every-position-has-one-cell

every position belongs to exactly one cell

generalonce

Applies to racing-track-grid.

Within this adoption's verification scope — the car's position at the start and end of every tick over one run, and every wake sample point read along a tick's sweep, including positions off the declared grid and on both sides of zero — every position of racing-track-grid lands in exactly one cell, never in two and never in none, and the cell is found by dividing by cell-size = 4 and rounding down — then adding 1 where this grid counts from 1 — the same way on both sides of zero. Converting back and forth closes the loop. The scope and seeds are this game's, supplied through this adoption's verification inputs; the check and its oracle are the contract's. Rounding down and cutting the fraction off agree everywhere the numbers are positive and part company on the other side of zero, which is why the scope should reach both sides wherever this game has them.

Test steps and diagnostics
Diagnostics
  • racing-track-grid-position-to-cell-trace
  • first-position-owned-twice
Holds

the position belongs to exactly one cell of racing-track-grid, found by dividing by cell-size = 4 and rounding down — then adding 1 where this grid counts from 1 — the same way on both sides of zero; and converting that cell back to a position inside it and converting again returns the same cell

Seeds

["racing-track-position-a","racing-track-position-b"]

Scope

the car's position at the start and end of every tick over one run, and every wake sample point read along a tick's sweep, including positions off the declared grid and on both sides of zero

boundary-belongs-to-one-cell

a position on a shared line belongs to one cell

scenarioonce

Applies to racing-track-grid.

In racing-track-grid, a position exactly on the line between cells 5 and 6 is in cell 6, the cell with the larger number, and a position on a line below zero is in the cell with the larger number, by exactly the same rule as on the other side of zero. Real cell numbers are named here on purpose: this is the decision in the definition whose answers are easiest to state backwards, so the test states the winning one as a worked case rather than as a label. Cells 5 and 6 exist whether this grid counts from 0 or from 1, and where counting starts at 1 the conversion adds its one step and this case is unchanged. The second clause asks about positions below zero rather than about cells at negative numbers, and the difference is not pedantry: a bounded board numbered from zero has no negative cells, yet where the cell numbers name centres the outer half-cell band of that same board sits at negative positions — which is exactly where two of the three conversions part company. Where no rule of this game ever reads a position below zero on either axis, the clause has nothing to check. The last clause is worth reading twice: one answer, everywhere in the build, rather than one answer per system that happens to ask.

Test steps and diagnostics
Given

the cells numbered 5 and 6 on one axis of racing-track-grid, and any position your rules read that lies below zero on either axis

When
  • a position is placed exactly on the line between cells 5 and 6
  • a position below zero is placed exactly on a line between two cells
  • a position is placed exactly where four cells meet
Then
  • the position between cells 5 and 6 is in cell 6, the cell with the larger number
  • wherever a position your rules read lies below zero, the position on the line there is in the cell with the larger number, by exactly the same rule as on the other side of zero
  • neither of those positions is in any other cell
  • the position where four cells meet is in the single cell picked by applying that same rule on both axes at once
  • every rule in the build that asks which cell any of those positions is in gets the same answer
Diagnostics
  • racing-track-grid-boundary-owner-report

distance-is-measured

distance between two cells is measured one way

generalonce

Does not apply to racing-track-grid: distance metric is not applicable, not no diagonals or diagonals count the same or octile or straight line.

equal-distance-is-decided

two distances count as equal by a declared rule

scenarioonce

Does not apply to racing-track-grid: distance metric is not applicable, not straight line or octile.

one-step-moves

one step reaches exactly the neighbouring cells

generalonce

Does not apply to racing-track-grid: adjacency for movement is not applicable, not four neighbours or eight neighbours.

next-to-means

next to means the same cells in every rule

generalonce

Applies to racing-track-grid.

Wherever a rule of racing-track-grid says one cell is next to another, it means the four cells sharing an edge with it — and it means the same thing in every rule that says it. This is asked apart from movement because games answer the two differently, sometimes without noticing: one surveyed game plans routes over four neighbours while targeting by straight line, and one engine hands back four surrounding cells while its own direction list carries sixteen.

Test steps and diagnostics
Diagnostics
  • racing-track-grid-neighbour-set-per-rule
  • first-disagreeing-rule
Holds

wherever a rule of this game treats one cell as next to another, the cells it means are exactly the four cells sharing an edge with it, and the answer is the same in every such rule

Seeds

["racing-track-neighbours-a","racing-track-neighbours-b"]

Scope

the layout rules that require the track cells to form one joined-up group and each route band to form one joined-up group, checked over both declared layouts and over deliberately broken copies of them

authored-order-lists-every-cell

this package's own material lists every cell once

generalonce

Applies to racing-track-grid.

An authored layout of racing-track-grid lists every cell exactly once, one whole row at a time, counting from the smallest numbers upward, and reading that layout back gives the same cells in the same places. This does not set save-file order, drawing order, update order, or the order in which rules visit cells. Naming the authored order stops a rule from quietly depending on one of those other orders.

Test steps and diagnostics
Scope

an authored layout of racing-track-grid, with every cell distinguishable from every other, read from the first cell to the last as designers write it

Holds

the material lists every cell of racing-track-grid exactly once, one whole row at a time, counting from the smallest numbers upward, and a board written out and read back arrives cell for cell the same

Diagnostics
  • racing-track-grid-authored-order-sequence
  • first-cell-out-of-order
  • cells-listed-twice-or-never

block-layout-is-declared

the blocks this material is written in are declared

scenarioonce

Does not apply to racing-track-grid: enumeration order is rows then columns, not block tiled.

tie-break-settles

a tie between two cells settles the same way every time

scenarioonce

Applies to racing-track-grid.

When a rule of racing-track-grid must pick between two candidates it ranks equally, it picks the candidate with the smaller column number, and if those are equal the one with the smaller row number. The adoption demonstrates that answer with this worked case: from cell (4, 4), candidate cells (3, 5) and (5, 3) take equal route travel; cell (3, 5) wins and cell (5, 3) loses. The test repeats the case after reversing creation and drawing order. A choice that changed would be a different answer to this question.

Test steps and diagnostics
Given

a rule of this game that must pick one cell, and the worked pair of equally ranked candidates described here: from cell (4, 4), candidate cells (3, 5) and (5, 3) take equal route travel; cell (3, 5) wins and cell (5, 3) loses

When
  • the rule runs
  • the same situation is set up again, with the two candidates created in the opposite order and drawn in the opposite order
Then
  • the rule picks the candidate with the smaller column number, and if those are equal the one with the smaller row number
  • it picks the same candidate both times
  • the order the candidates were created in, the order they are drawn in, where the pointer is, and how the animation runs change nothing
Diagnostics
  • racing-track-grid-tie-break-report
  • racing-track-grid-candidate-set

tie-break-follows-arrival

a tie between two cells goes to whichever came first

scenarioonce

Does not apply to racing-track-grid: tie break between cells is lower column wins, not arrival order.

tie-break-is-arbitrary

a tie between two cells comes out the same way in a replay

scenarioonce

Does not apply to racing-track-grid: tie break between cells is lower column wins, not deliberately arbitrary.

tie-break-is-drawn

a tie between two cells is drawn from a declared stream

scenarioonce

Does not apply to racing-track-grid: tie break between cells is lower column wins, not random from a declared seed.

tie-break-asks-the-player

a tie between two cells is put to the player

scenarioonce

Does not apply to racing-track-grid: tie break between cells is lower column wins, not player chooses.

no-tie-ever-arises

no rule ever faces a tie between two cells

generalonce

Does not apply to racing-track-grid: tie break between cells is lower column wins, not not applicable.

a-positive-turn-goes

a positive turn goes one way

scenarioonce

Applies to racing-track-grid.

In racing-track-grid, a positive turn moves a facing clockwise on the declared grid, and turning back by the same amount returns the facing exactly. Naming the turn on the grid is deliberate: two corpus packages describe this same turn in opposite words, one counting from an axis and one naming the clock, and a reader has to do arithmetic to find out they agree.

Test steps and diagnostics
Given

something standing on racing-track-grid that has a facing, with that facing recorded

When
  • it turns by a positive amount
  • it then turns by the same amount the other way
Then
  • the first turn moves its facing clockwise on the grid as this package lays it out
  • the second turn brings the facing back exactly to where it started
  • every rule of this game that turns something turns it the same way for a positive amount
Diagnostics
  • racing-track-grid-facing-before-after
  • racing-track-grid-turn-log

grid-direction-points · rightward

rightward points toward the right of the declared grid

scenarioper directions row

Applies to the rightward row.

In racing-track-grid, the word rightward means the direction toward the right of the declared grid. It is fixed to the grid: it points the same way whoever uses it, and it never follows anything's facing. Naming it says nothing about whether anything may move that way — the movement question decides that, and a game whose pieces move to four neighbours may still name a diagonal for an effect or a line of sight. Writing the word down here is what stops a second document in this package using it for a different direction. One surveyed format ships eight named compass directions and never says where any of them points.

Test steps and diagnostics
Given

a cell of racing-track-grid with a cell on every side of it

When
  • a rule of this game moves something, points something, or reads a cell rightward of that cell
Then
  • the cell it uses is the one toward the right of the declared grid
  • the word rightward means that same direction in every rule of this package and never another
  • the direction does not change with whatever is using it
Diagnostics
  • racing-track-grid-direction-resolution
  • racing-track-grid-cell-addresses

grid-direction-points · downward

downward points toward the bottom of the declared grid

scenarioper directions row

Applies to the downward row.

In racing-track-grid, the word downward means the direction toward the bottom of the declared grid. It is fixed to the grid: it points the same way whoever uses it, and it never follows anything's facing. Naming it says nothing about whether anything may move that way — the movement question decides that, and a game whose pieces move to four neighbours may still name a diagonal for an effect or a line of sight. Writing the word down here is what stops a second document in this package using it for a different direction. One surveyed format ships eight named compass directions and never says where any of them points.

Test steps and diagnostics
Given

a cell of racing-track-grid with a cell on every side of it

When
  • a rule of this game moves something, points something, or reads a cell downward of that cell
Then
  • the cell it uses is the one toward the bottom of the declared grid
  • the word downward means that same direction in every rule of this package and never another
  • the direction does not change with whatever is using it
Diagnostics
  • racing-track-grid-direction-resolution
  • racing-track-grid-cell-addresses

direction-walk-order

Row.id takes place Row.order in the direction walk

scenarioper directions row

Does not apply to racing-track-grid: tie break between cells is lower column wins, not direction order.

piece-direction-follows-facing · forward

forward is read from the facing of whatever uses it

scenarioper directions row

Applies to the forward row.

In racing-track-grid, the word forward is read from the facing of whatever uses it, so it points somewhere else after that thing turns, and it can mean two different directions for two things standing on the same cell. That is the whole difference from a word fixed to the grid, and it is worth stating in a package that uses both kinds.

Test steps and diagnostics
Given

a thing standing on a cell of racing-track-grid, with a facing and a cell on every side of it

When
  • a rule of this game moves it, points it, or reads a cell forward of it
  • the thing turns, and the same rule runs again
Then
  • the direction the word forward names is read from that thing's own facing, not from the grid
  • after the turn, forward names a different direction on the grid, turned by exactly as much as the facing was
  • two things with different facings, standing on the same cell, resolve forward differently
Diagnostics
  • racing-track-grid-direction-resolution
  • racing-track-grid-facing-before-after

piece-direction-follows-facing · right

right is read from the facing of whatever uses it

scenarioper directions row

Applies to the right row.

In racing-track-grid, the word right is read from the facing of whatever uses it, so it points somewhere else after that thing turns, and it can mean two different directions for two things standing on the same cell. That is the whole difference from a word fixed to the grid, and it is worth stating in a package that uses both kinds.

Test steps and diagnostics
Given

a thing standing on a cell of racing-track-grid, with a facing and a cell on every side of it

When
  • a rule of this game moves it, points it, or reads a cell right of it
  • the thing turns, and the same rule runs again
Then
  • the direction the word right names is read from that thing's own facing, not from the grid
  • after the turn, right names a different direction on the grid, turned by exactly as much as the facing was
  • two things with different facings, standing on the same cell, resolve right differently
Diagnostics
  • racing-track-grid-direction-resolution
  • racing-track-grid-facing-before-after
JSONthe adoption as one file

The adoption file as supplied. Answers you try on this page are not written into it; to change an adoption, open it in the authoring tool.

{
  "contract": "grid-and-direction",
  "version": 1,
  "origin": "https://opengdd.org/contracts/grid-and-direction-1",
  "summary": "Covers square grids and the direction words your game uses. It says where numbering starts, which cells touch, and how a position belongs to a cell. It says how rules measure distance, choose between equal cells, list cells in order, and turn. Grid edges, pathfinding, non-square cells, and a third axis stay with your game.",
  "mechanism": [
    "The mechanism is one grid of equal square cells. A row runs across it, and a column runs down it. When a game names a cell with two whole numbers, coordinate-order says which one comes first; a layout may name cells by their contents instead. The grid may be a bounded rectangle with a first cell in one corner, or run on in every direction with signed numbers and no first cell; the first question says which.",
    "The grid's own frame. Every answer below is read against the grid as this package declares it: the layout your content writes out, or your own chapter's sentence about which way the numbers grow. Up, down, left and right mean those directions on the declared grid. On a bounded grid where content writes the grid out row by row, the first written row is nearest the declared origin corner: the top row for top-left, and the bottom row for bottom-left. These directions never follow the finished picture, which a build may draw any way its presentation chapter allows. A Delegated view can never change a Fixed answer.",
    "Where a game also has positions — things resting between cells rather than on them — zero is the same place for cells and for positions, and where a cell-ownership option makes the cell at zero a different width, that option says so. Two neighbouring cells share a line, and cell-ownership says which cell the line belongs to. Every conversion below divides by the cell size and, where the grid counts from 1, adds 1. Each cell-ownership option that uses positions states how position zero and shared lines are treated.",
    "Several nearby decisions are deliberately not here — the grid's edge, sharing a cell, corner-cutting, pathfinding, a third axis, cells that are not squares, whether a sweep sees its own changes. The note at the end says where each lives."
  ],
  "questions": {
    "origin-and-axes": {
      "asks": "Where is this grid's first cell, and which way do its row and column numbers grow?",
      "rationale": "Every later rule needs one shared reading of row and column numbers. This contract only carries columns that grow right; state a left-growing grid in your own prose.",
      "options": {
        "top-left": {
          "meaning": "The first cell is the top-left corner. Column numbers grow right, and row numbers grow down."
        },
        "bottom-left": {
          "meaning": "The first cell is the bottom-left corner. Column numbers grow right, and row numbers grow up."
        },
        "unbounded-right-and-down": {
          "meaning": "There is no first cell or corner. The grid continues through negative and positive numbers. Columns grow right, and rows grow down from the cell your game calls zero."
        },
        "unbounded-right-and-up": {
          "meaning": "There is no first cell or corner. The grid continues through negative and positive numbers. Columns grow right, and rows grow up from the cell your game calls zero."
        }
      }
    },
    "coordinate-order": {
      "asks": "When you write a cell with two numbers, does the row or column come first?",
      "rationale": "Swapping the two numbers turns rows into columns. A square grid can hide that mistake, so the order must be clear.",
      "options": {
        "column-first": {
          "meaning": "The column comes first. The pair (3, 5) means column 3, row 5."
        },
        "row-first": {
          "meaning": "The row comes first. The pair (3, 5) means row 3, column 5."
        },
        "not-applicable": {
          "meaning": "The game never names a cell with a pair of numbers. It uses a layout, cell contents, or another name instead."
        }
      }
    },
    "counting-starts-at": {
      "asks": "Do the first row and column use zero or one?",
      "rationale": "Starting at zero or one changes every written cell address. Naming it prevents an off-by-one shift between the design and the build.",
      "when": {
        "flag": {
          "origin-and-axes": [
            "top-left",
            "bottom-left"
          ]
        }
      },
      "options": {
        "zero": {
          "meaning": "The first row and column are numbered zero. A ten-cell row runs from zero through nine."
        },
        "one": {
          "meaning": "The first row and column are numbered one. A ten-cell row runs from one through ten."
        }
      }
    },
    "cell-ownership": {
      "asks": "A point lies exactly on the line between two cells. Which cell owns it?",
      "rationale": "A boundary point needs one owner. Different rounding rules can place the same point in different cells, especially beside zero.",
      "options": {
        "next-cell-along": {
          "meaning": "The cell with the larger number owns the line. The line where cell five ends and cell six begins belongs to cell six, on either side of zero.",
          "semantics": "Divide the position by cell-size and round down, then add one when counting-starts-at is one. A boundary position belongs to the cell with the larger coordinate."
        },
        "truncate-toward-zero": {
          "meaning": "The cell farther from zero owns the line. The zero cell reaches one cell-size to each side, so it is twice as wide as the others.",
          "semantics": "Divide the position by cell-size and truncate toward zero, then add one when counting-starts-at is one. Coordinate zero spans one cell-size on each side."
        },
        "cell-centres-are-whole-numbers": {
          "meaning": "Whole numbers mark cell centres. A point halfway between two centres belongs to the cell with the larger number.",
          "semantics": "Cell coordinates name centres. Divide the position by cell-size and round to the nearest whole coordinate, taking an exact half toward the larger coordinate, then add one when counting-starts-at is one."
        },
        "not-applicable": {
          "meaning": "Your rules only use whole cells, never positions between them. No boundary choice is needed."
        }
      }
    },
    "distance-metric": {
      "asks": "When your rules say nearest or within some distance, how do they measure between cells?",
      "rationale": "Games often use several distance rules. This answer only controls what your written rules mean by nearest or within a distance.",
      "options": {
        "no-diagonals": {
          "meaning": "Add the steps across and down the grid (Manhattan). A cell two across and one up is three steps away."
        },
        "diagonals-count-the-same": {
          "meaning": "Count the larger of the across and down steps (Chebyshev). A cell two across and one up is two steps away."
        },
        "octile": {
          "meaning": "Straight steps cost one, and diagonal steps cost the square root of two (octile). The distance is the cheapest mix of those steps. Your game's comparison rule decides when two distances count as equal.",
          "semantics": "For absolute coordinate differences dx and dy, multiply the smaller difference by the square root of two minus one (about 0.414), then add the result to the larger difference. Equal means equal at whatever precision this game compares its distances with. For straight-line and octile distance, the adoption must state that comparison rule in the distance test's verification scope."
        },
        "straight-line": {
          "meaning": "Measure a straight line between the cell centres (Euclidean). Use position units when positions exist; otherwise use cells. Your game's comparison rule decides when two distances count as equal.",
          "semantics": "Equal means equal at whatever precision this game compares its distances with. For straight-line and octile distance, the adoption must state that comparison rule in the distance test's verification scope."
        },
        "not-applicable": {
          "meaning": "No rule measures distance between cells. Rules may still use neighbours, named shapes, or links."
        }
      }
    },
    "adjacency-for-movement": {
      "asks": "From one cell, which other cells can a thing reach in one step?",
      "rationale": "Movement neighbours do not follow automatically from distance or effect range. A game can use different cells for each.",
      "options": {
        "four-neighbours": {
          "meaning": "Only the four cells sharing an edge are one step away. A diagonal cell cannot be reached in one step."
        },
        "eight-neighbours": {
          "meaning": "All eight surrounding cells are one step away. A thing may move across an edge or diagonally across a corner."
        },
        "not-applicable": {
          "meaning": "Nothing moves one cell at a time. Things are placed directly or move freely while the grid only reads their final cell."
        }
      }
    },
    "adjacency-for-effects": {
      "asks": "When a rule says two cells are next to each other, do corners count?",
      "rationale": "Movement and effects can count neighbours differently. This answer keeps words such as next to from changing meaning between rules.",
      "options": {
        "four-neighbours": {
          "meaning": "Only cells sharing an edge count as neighbours. Two cells touching only at a corner are not next to each other."
        },
        "eight-neighbours": {
          "meaning": "All eight surrounding cells count as neighbours. Cells touching only at a corner are still next to each other."
        },
        "not-applicable": {
          "meaning": "No rule uses next to by itself. Each rule names the cells it means, or no rule asks whether cells are neighbours."
        }
      }
    },
    "enumeration-order": {
      "asks": "In what order does an authored layout list its cells?",
      "rationale": "Drawing, updates, and save files may use different orders. This answer covers only layouts designers write and read.",
      "options": {
        "rows-then-columns": {
          "meaning": "List every cell in one row before starting the next row. Start with the smallest row and column numbers. A text map with one line per row already uses this order."
        },
        "columns-then-rows": {
          "meaning": "List every cell in one column before starting the next column. Start with the smallest row and column numbers."
        },
        "block-tiled": {
          "meaning": "List cells inside blocks such as chunks, regions, or screens. Your game's prose states block size, block order, and the order inside each block."
        },
        "not-applicable": {
          "meaning": "No authored layout lists the grid's cells. No order is needed for the material designers write and read."
        }
      }
    },
    "tie-break-between-cells": {
      "asks": "A rule rates two cells equally and must pick one. How does it decide?",
      "rationale": "Equal choices are common and rarely written down. A fixed answer stops two builds from choosing different cells.",
      "options": {
        "lower-column-wins": {
          "meaning": "The cell with the smaller column number wins. Between a cell in column 2 and a cell in column 4, the column-2 cell wins and the column-4 cell loses. If columns match, the smaller row number wins."
        },
        "lower-row-wins": {
          "meaning": "The cell with the smaller row number wins. Between a cell in row 2 and a cell in row 4, the row-2 cell wins and the row-4 cell loses. If rows match, the smaller column number wins."
        },
        "direction-order": {
          "meaning": "Walk the grid-fixed direction words in their chosen order. The first direction that points to a tied neighbour wins. Use another answer when tied cells are not neighbours."
        },
        "arrival-order": {
          "meaning": "The candidate that arrived first wins. Your game names whether arrival means creation, placement, storage, or entering play. The same run repeats the choice, but save and reload follow your persistence rules. The validator cannot check this; a reviewer does."
        },
        "named-priority-list": {
          "meaning": "The candidate kind listed first in your game's priority order wins. Cell position never decides."
        },
        "deliberately-arbitrary": {
          "meaning": "Either candidate may win, and players must not depend on which one. Replaying the same run repeats the choice, but loading a save may not."
        },
        "random-from-a-declared-seed": {
          "meaning": "Draw one candidate from a random stream declared by your game. The same run and replay draw the same candidate. The validator cannot check this; a reviewer does."
        },
        "player-chooses": {
          "meaning": "The player chooses the candidate. If the game cannot ask, the rule does nothing instead of guessing. The validator cannot check this; a reviewer does."
        },
        "not-applicable": {
          "meaning": "No rule ever chooses one of two equal candidates. The situation cannot happen, or the rule affects every tied candidate."
        }
      }
    },
    "turn-direction": {
      "asks": "When your rules turn a facing by an amount, which way does the amount go on the grid?",
      "rationale": "Axis direction does not decide turn direction. Naming clockwise or counter-clockwise prevents equivalent formulas from reading as opposite rules.",
      "options": {
        "clockwise": {
          "meaning": "A positive turn goes clockwise on the grid. A rotated view may show it differently, but the grid rule stays the same."
        },
        "counter-clockwise": {
          "meaning": "A positive turn goes counter-clockwise on the grid. A rotated view may show it differently, but the grid rule stays the same."
        },
        "not-applicable": {
          "meaning": "No rule turns a facing by an amount. A piece may still snap directly toward movement or a target."
        }
      }
    }
  },
  "declares": {
    "values": {
      "cell-size": {
        "description": "The length of one cell in your position units. For centre-based cells, measure from one centre to the next. Use a positive size when rules read positions. Use zero when they only read whole cells. Changing this number changes which cell holds a position."
      }
    },
    "rows": {
      "directions": {
        "description": "List every direction word your game uses. Each row says whether it follows the grid or a piece. A grid direction also says where it points. An empty list means the game names no directions. If ties use this order, list every grid-fixed neighbour that can tie. The validator cannot check this; a reviewer does.",
        "record": {
          "id": {
            "type": "string",
            "required": true,
            "pattern": "kebab-case",
            "unique": true,
            "description": "The direction word your game uses, such as north, forward, or starboard. Write it in lowercase with hyphens between words."
          },
          "frame": {
            "type": "string",
            "required": true,
            "options": [
              "grid",
              "piece"
            ],
            "description": "Whether the direction follows the grid or a piece. A grid direction always points the same way: north stays north. A piece direction changes when that piece turns: forward, left, and behind turn with it."
          },
          "points": {
            "type": "string",
            "when": {
              "row": {
                "frame": [
                  "grid"
                ]
              }
            },
            "options": [
              "up",
              "down",
              "left",
              "right",
              "up-left",
              "up-right",
              "down-left",
              "down-right"
            ],
            "description": "Where this grid-fixed direction points on the grid. Omit it for a direction that follows a piece. This does not decide whether movement is allowed that way."
          },
          "order": {
            "type": "integer",
            "when": {
              "flag": {
                "tie-break-between-cells": [
                  "direction-order"
                ]
              },
              "row": {
                "frame": [
                  "grid"
                ]
              }
            },
            "unique": true,
            "description": "This direction's place in the tie-breaking walk. One is tried first. Give each grid-fixed direction a different number. Use it only when ties follow direction order."
          }
        }
      }
    }
  },
  "rules": {
    "cell-size-not-negative": "cell-size >= 0"
  },
  "pack": "sha256:b17529b6bce460ee83f7c460f2e73c39d5c32051637613867e42ef85b6e0996a",
  "answers": {
    "origin-and-axes": "top-left",
    "coordinate-order": "column-first",
    "counting-starts-at": "zero",
    "cell-ownership": "next-cell-along",
    "distance-metric": "not-applicable",
    "adjacency-for-movement": "not-applicable",
    "adjacency-for-effects": "four-neighbours",
    "enumeration-order": "rows-then-columns",
    "tie-break-between-cells": "lower-column-wins",
    "turn-direction": "clockwise"
  },
  "values": {
    "cell-size": 4
  },
  "rows": {
    "directions": [
      {
        "id": "rightward",
        "frame": "grid",
        "points": "right"
      },
      {
        "id": "downward",
        "frame": "grid",
        "points": "down"
      },
      {
        "id": "forward",
        "frame": "piece"
      },
      {
        "id": "right",
        "frame": "piece"
      }
    ]
  },
  "verification": {
    "every-position-has-one-cell": {
      "seeds": [
        "racing-track-position-a",
        "racing-track-position-b"
      ],
      "scope": "the car's position at the start and end of every tick over one run, and every wake sample point read along a tick's sweep, including positions off the declared grid and on both sides of zero"
    },
    "next-to-means": {
      "seeds": [
        "racing-track-neighbours-a",
        "racing-track-neighbours-b"
      ],
      "scope": "the layout rules that require the track cells to form one joined-up group and each route band to form one joined-up group, checked over both declared layouts and over deliberately broken copies of them"
    },
    "tie-break-settles": {
      "scope": "from cell (4, 4), candidate cells (3, 5) and (5, 3) take equal route travel; cell (3, 5) wins and cell (5, 3) loses"
    }
  }
}