TinyGames · how it works

Sjoelbak

Dutch shuffleboard. Thirty wooden discs, a bar with four gates across the far end of a two-metre board, three rounds. Slide every disc; whatever did not get through a gate is picked up and slid again, and then once more. Each complete set of one disc in every compartment scores 20; the rest score their compartment's value. The compartments read, from the player's left, 2 - 3 - 4 - 1.

Landscape only. The board is five times longer than it is wide and the player looks down it from the near end; held upright the shell puts up its rotate card.

sjoelbak/
  index.html      markup
  style.css       the frame around the canvas
  js/sjoel.js     the board, the discs, the bar and the score
                  - no pixels, no engine, no DOM
  js/sjoelbak.js  the playable layer
  test-sjoel.js   node test-sjoel.js

Built from src/sjoelbak/; the JavaScript here is generated and never edited. js/sjoel.js is shared with Sjoelen 3D, which is the same board seen from where the player stands: one rules module, two games.


The words

The bar is the plank across the board near the far end. The gates are the four openings cut in it, each 6.5 cm for a 5.2 cm disc. The compartments are the numbered scoring areas behind them. A disc scores by passing through a gate into a compartment, and it lies "in the 4" - never "in gate 4".

The line that decides everything

A disc is IN once its trailing edge has cleared the back edge of the bar. Short of that line by any amount at all - a millionth of a unit, one pixel - is not in: under the bar in a gate is not in, against the front of it is not in, stopped short is not in. A trailing edge exactly on the line is in. At the end of a round every disc that is not in goes back into the hand, and is never left lying in the gate or the compartment. A disc that hits the back wall and comes to rest still inside its compartment counts; one that bounces back out through the gate does not.

The test suite rebuilds that line as a table of the four compartments as y-intervals and sweeps the whole area against the shipped rule, then samples shortfalls from 1e-6 up to three units and checks each one is refused and returned. A mutant that grants half a unit of grace is caught.

The bar is a plank

The bar is five pieces of solid wood - two ends and three between the gates - and four openings, each only a little wider than a disc and centred on its compartment. A disc that meets the wood bounces off it like any wall. One that fits the opening slides through. One that catches the corner of an opening is either funnelled in by the rounded corner or turned back: measured, a disc up to about 1.3 cm off a gate's centre goes in, and from 2 cm off it always comes back. Nothing ever comes to rest half in the wood.

The suite writes the plank out by hand as a table of wood and air, checks the shipped geometry is exactly its complement, then slides discs along the rails (they strike the ends of the plank), at the wood between gates, down the middle of every gate at every power in the window, and at the corners. A mutant that widens the gates to the whole compartment - the old open bar - is caught by the rail slides; one that closes them is caught everywhere.

The tidy between rounds

When a round ends, every disc that is in is pushed to the back of its compartment, as a player does on a real board: a column against the back wall, centred on the gate, touching, from the back forward. Five fit. Six or more overlap like roof tiles into a pile, which the picture draws with an offset shadow per disc so that nine read as nine. The physics treats a pile as one body: its discs never push each other apart, a disc slid into the pile strikes the front disc, which rides back over its mates, and a full pile stops the disc that struck it under the bar. The counts and the score are what they were; nothing is moved that was not in, and nothing is dropped. Three hundred random boards are tidied in the suite and every one of those things checked; a mutant that lays each column one compartment over and one that drops a disc are both caught.

The score can be added up two ways

The shipped rule is a closed form over the smallest compartment count. The suite strips one set at a time in a loop, using its own copy of the values, and also checks the paper identity: every disc at its compartment's value plus ten a set, because a set of 2 + 3 + 4 + 1 is worth twenty rather than ten.

Nothing ever leaves the board, and everything stops

A disc at full pace covers its own width in a frame and a divider between two compartments is under a unit thick, so a frame advanced in one go steps clean over it. Every step is cut into substeps small enough that no disc moves more than a quarter of its radius, and the budget is the root-sum-of-squares of the speeds rather than the fastest disc - a collision can send one disc out faster than either went in.

Friction takes a fixed amount off the speed per second and snaps to a stop below a threshold. A per-frame multiplier never gets there, and the suite shows it: a 0.98 multiplier is still moving after a hundred thousand frames.

$ node test-sjoel.js
    2104 slides in 30 games - fullest compartment 8 discs, best random score 92, longest settle 95 frames

144 passed, 0 failed

Three thousand single discs on an empty board at every lane, angle and power, then thirty whole games of thirty discs and three rounds - half the slides wild, half aimed at a gate so the compartments fill and the piles form: every disc came to rest, none left the board or entered the wood, the board's energy never grew between slides, and no two loose discs ever overlapped by more than a quarter of a radius.

The window

A straight slide down the middle of a gate on an empty board stops short of the bar below about 0.65 power and comes back out through the gate above about 0.90; between the two it is in. That is set by the wall bounce, and the suite sweeps the whole range so it cannot drift. Full power is deliberately too much: a game where hardest is best is not sjoelen. Once a compartment has discs in it the arithmetic changes, because they absorb the blow, and that is the game.

Mutation run

Every rule above is checked against a deliberately broken copy of the shipped file - a set worth ten, the compartments numbered the other way, no friction, walls that add speed, no substepping, two rounds, a slide allowed backwards, "in" meaning past the front of the bar, a round that clears the whole board, gates as wide as the compartments, gates closed, half a unit of grace at the line, a tidy that lays columns in the wrong compartment, a tidy that drops a disc - eighteen in all, and each one is caught. A wrapper that changes nothing passes, which is what shows the suite is not failing on nothing.


Controls

Drag back anywhere, release slide: the disc leaves along the line from finger to start, as hard as the pull
Drag the waiting disc across choose the lane
← → move the lane
↑ ↓ power
Space slide straight down the lane
Escape / P pause
R start again

A finger that lands on the disc is not decided until it has moved: across the board is a lane, back along it is a pull. Sound is synthesised - clicks, knocks and a wooden tok for a compartment - and switched off from the config sheet.

A saved game is offered on the title card between slides and between rounds; a slide in flight is never saved. A save from before the bar became a plank is dropped rather than loaded: its discs could lie where there is now wood.

Things deliberately left undone