Skip to main content

George Boole Has Entered The Chat — terminal version

The third sibling to web/ (adenosine, browser) and wii/ (magnolia, C99). Runs entirely in a shell — no graphics, just characters — in the tradition of AsciiPatrol, Cataclysm:DDA and the rest of the command-line-only canon.

pipx install magmacrunch-george-boole
george-boole

pipx rather than pip because it puts the command on your PATH in its own virtualenv; plain pip install only reaches your PATH inside an activated venv. It is also a cabinet in the magmacrunch arcade — pipx install magmacrunch gets this and the other two — and plays identically either way.

For working on it:

pip install -e ".[dev]"
python -m boole          # or the installed `george-boole` command

Published as magmacrunch-george-boole — prefixed because PyPI has no scoping like the npm @magmacrunch/… packages, and unprefixed names get taken (adenosine and magnolia both already belong to someone else there). The import package stays plain boole.

That opens the title screen, where you pick one of the eight modes. Naming a mode is an instruction to play it, so --mode skips straight into a game:

python -m boole --mode gauntlet
python -m boole --mode byte --seed 42     # a reproducible run

How to play is the last row of the mode list, or H from anywhere on the title screen. It carries the browser build's quick rules and a gate table — the gates are in the HUD during a game, but the HUD is not where you go to find out what they mean. It scrolls, because the rules are longer than a standard terminal is tall.

High scores are kept on disk, so a record outlives the session. One board for the whole game with the mode on each row, rather than eight — crumb and byte are not different games, they are the same game at different widths, and a single ranked list says which width somebody was brave enough to play at. Filed under george-boole, the same key the browser build posts to. Reach it from the menu or with B.

On the title screen

key
↑ ↓ / W S choose a mode
Enter start
28, G jump straight to a mode
Esc back to the arcade, when the arcade started this
Q quit

In a game

key
arrows / WASD move
R restart this mode
Esc back to the mode menu
Q quit

Best scores are kept per mode for as long as the process runs, and shown on both screens.

Needs a terminal at least 59x20 for the board, 44x18 for the menu. Below that it says so rather than drawing a clipped screen. Anything roomier than the minimum centres the board in the window rather than pinning it to a corner. Truecolor is used for the tile ramps but not required.

When the terminal cannot draw the glyphs

Not every console can encode what these games draw. Windows' two common codepages are the ones that bite: cp1252 has none of the block elements, arrows or suits, and cp437 has the blocks and none of the arrows, stars or suits. The engine asks the terminal what it can encode and substitutes what it cannot, one group at a time -- so a set of related glyphs never comes back half translated, and a terminal that can draw the blocks keeps them even though it has lost the arrows.

Detection is automatic. Two ways to override it, for the case no probe can see -- an encoding that accepts the character in a font that has no picture for it:

boole --ascii              this game, this run
MAGMACRUNCH_ASCII=1      every cabinet, always

Every substitute is exactly one cell wide, so a plain screen has the same layout as a fancy one rather than a reflowed approximation of it.

This game needs that more than its siblings do. The gate glyphs are the board rather than its decoration, and neither Windows codepage can encode AND, OR or XOR -- so an unhandled terminal here is not an untidy game, it is an unplayable one. The plain forms are the ones a programmer already reads:

NOT ¬ !
AND &
OR |
XOR ^

All four move together even where the terminal could manage ¬ -- which both codepages can. One set of operators in two alphabets is harder to read than either alphabet alone.

Launchable by an arcade

The game declares itself through an entry point, so anything enumerating magmacrunch.games finds it:

[project.entry-points."magmacrunch.games"]
george-boole = "boole.arcade:GAME"

It does not own the terminal. A magmacrunch.engine.core.tui_host.TuiHost does, and BooleApp is handed one — which is what lets the same code run as its own command and be seated by a launcher without knowing which happened. Esc from the mode menu ends a standalone session and returns to the arcade menu under a launcher, and the game does not have to know the difference: it pops a scene and the host decides what that means.

How it is built

The engine is magmacrunch.engine, which arrives with the magmacrunch package this one depends on — so installing the game installs the engine, and installing the arcade installs both. The game draws through the engine's Renderer/UISurface protocols and never touches a terminal library directly, so the planned hand-written ANSI backend will be a swap rather than a rewrite.

The engine used to be texastoast and its [tui] extra. It was extracted into magmacrunch.engine and the dependency now runs the other way: the games depend on the arcade rather than on a third package.

boole/
  board.py   the Boolean rules — pure Python, no engine, no terminal
  modes.py   bit modes and their tuning tables
  theme.py   palette and layout, in character cells
  scenes.py  MenuScene and GameScene — the two screens
  app.py     wiring: the game, the renderer, the scene stack
tests/
  test_board.py   the rule set, pinned
  test_app.py     the screens, driven headlessly

board.py and modes.py import nothing outside the standard library. That is enforced by a test, and it is what lets the rules be checked in under a second.

Modality is the stack, not a flag. MenuScene sits at the bottom of a SceneStack; choosing a mode pushes a GameScene on top, and Esc pops back. Nothing anywhere holds an in_menu boolean — a game that has been popped stops receiving frames because the stack does not call it, which is the rule the engine's scene.py exists to enforce.

The mode menu is the engine's own magmacrunch.engine.ui.menu.Menu, given layout metrics in cells instead of its pixel defaults. Navigation, selection and the callbacks are the widget's; only the numbers and the palette are the game's.

The rules came from wii/, not web/

wii/source/board.c is the version of these rules already separated from its renderer, and it was checked against the web game's own assertions when it was written. web/js/game.js has the same rules tangled through ~25 document.* call sites and a constructor that caches DOM nodes, so porting from it would have meant extracting the logic first.

tests/test_board.py is wii/tests/test_board.c's assertion table, ported. All three builds have to agree on every one of these or the same game plays differently in three places, and that divergence is invisible until a player notices.

The gold personal-best tile, and how it differs from web/

The tile holding the best value ever built by merging is plated gold, and it shimmers — the web sweeps a gradient across it every 2.5s, and a cell that can only be one colour at a time does the same sweep by changing colour. Only the bright half of the web's gradient is used: its dark stops are corner shading that is never the whole tile there, and here they would be, which both makes the number hard to read and leaves the best tile on the board looking duller than a lesser one beside it. tests/test_app.py pins both as ratios.

Which tile gets it is asked of the valueBoard.is_personal_best — the way wii/source/render.c asks it, rather than tracked as a parallel board of booleans that slides and merges alongside the values the way web/js/game.js does. So the web golds whichever tile reached the value first, and this golds every tile holding it. Cosmetic: the height bonus is the same in all three.

Asking about the value cannot accidentally gild a spawned tile, which is the case the web's implementation is careful about. tests/test_board.py checks it exhaustively rather than by argument: every value every spawn table can hand out, at every width, against that width's height floor.

The rainbow tile — the tile that earned a Gauntlet promotion — is in all three, and takes precedence over the gold when one tile is both.

Every mode wears a console

2-bit is a Game Boy, 3-bit a NES, 4-bit a SNES, then Genesis, an arcade cabinet, a Neo Geo and a PS1; Gauntlet is the Matrix, and stays green across every width it climbs through, because the mode is the throughline and not the bit count. Choosing a mode repaints the whole screen, and arrowing down the menu previews each one.

The values come from wii/source/palette.c, which is web/css/themes.css already flattened into a table indexed by mode — the same reason the rules came from wii/. Re-deriving them from the stylesheet would have been a fourth opinion about what they are.

Two things a terminal needs that the other ports do not:

  • Ink is chosen, not declared. The web sets a text colour per value and the Wii is read from across a room; here a cell is one background with one glyph on it, and the Wii's own table has tiles that come out below 2:1 taken at face value — #ffd700 on the PS1's silver ramp, #00ff00 on the Matrix's near-white NOT gate. Palette.ink takes the most in-family colour that reads, and tests/test_app.py checks every tile in every mode.
  • The bar for a tile is the large-text one, 3:1 rather than 4.5:1. That is not a loophole. The Game Boy is four shades of one green by design, and at the body-text bar most of that board comes out white — off-joke, and incoherent beside the two tiles that keep their green. At 3:1 it reads green numerals on its dark steps and dark ones on its light steps, which is what a Game Boy looks like. Sentences are still held to 4.5:1.

Not ported

board_move() on the Wii also fills in a TileMove list recording where every tile came from, so the renderer can slide tiles instead of teleporting them. It is written but never read by the rules, and a terminal redrawing a 4x4 grid does not animate, so it is omitted. Omitting it cannot change behaviour.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

magmacrunch_george_boole-0.5.0.tar.gz (52.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

magmacrunch_george_boole-0.5.0-py3-none-any.whl (39.0 kB view details)

Uploaded Python 3

File details

Details for the file magmacrunch_george_boole-0.5.0.tar.gz.

File metadata

  • Download URL: magmacrunch_george_boole-0.5.0.tar.gz
  • Upload date:
  • Size: 52.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for magmacrunch_george_boole-0.5.0.tar.gz
Algorithm Hash digest
SHA256 7e75c5b4440f1846208f9fdc55303c1d0f0415001a579863a5be1d137f558dd4
MD5 8eb820310f109e9752b46d5f2189ce98
BLAKE2b-256 97780069b4bf06d815a1b5a9aa627862a5fd44926666accc2d4c75d9465225b0

See more details on using hashes here.

Provenance

The following attestation bundles were made for magmacrunch_george_boole-0.5.0.tar.gz:

Publisher: release.yml on magmacrunch-media/george-boole

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file magmacrunch_george_boole-0.5.0-py3-none-any.whl.

File metadata

File hashes

Hashes for magmacrunch_george_boole-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 938f6f9ba4c6b79de74644b9f251098936135c2df9a70409b301dd94dca96c60
MD5 9f131993ae1731eb4a75a2c79a3032c8
BLAKE2b-256 22e9834212c87878bf066cdee7cd3085d93e4805924a0d1128951c5098299960

See more details on using hashes here.

Provenance

The following attestation bundles were made for magmacrunch_george_boole-0.5.0-py3-none-any.whl:

Publisher: release.yml on magmacrunch-media/george-boole

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.5.1

2 files

This release

0.5.0 This release

2 files

0.4.0

2 files

0.3.1

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page