Skip to main content

Chess (terminal)

Chess against the computer, in a terminal. It is the second version of the game, beside web/. It runs on the magmacrunch engine's terminal backend, either as a cabinet in the magmacrunch arcade or as its own command, and plays the same either way.

pipx install magmacrunch-chess
chess                                   # the title, where the level and clock are set
chess --play --level hard --clock blitz # straight into a game

For working on it, from this folder:

pip install -e ".[dev]"
python -m neon_chess

The command is chess. The import package is neon_chess, after the page's Neon Edition, because chess is python-chess's and a player may well have it installed.

Keys

key
← ↑ ↓ → move the cursor
ENTER pick up the piece under the cursor; on a marked square, put it down
Q R B N when a pawn promotes, what it becomes (or ← → and ENTER)
Esc put the piece back; with nothing picked up, the title (and from there, the arcade)
R new game, same level and clock
Q quit

Your pieces are cyan capitals, the computer's pink small letters, as notation writes them: K Q R B N P. So the two sides stay apart with no colour at all, and under --ascii. Once a piece is picked up, a green · marks every empty square it can go to, and a square it can take on is tinted green. The last move is tinted yellow and a king in check red. The cursor is bracketed as well as shaded, so it shows under NO_COLOR. On the title, ← → change the level (Easy, Medium, Hard) and the clock (none, Blitz 5, Rapid 15, Classical 30). The panel shows the clocks, whose turn it is, and the move list in the page's notation.

The computer starts thinking 0.3 seconds after your move, as on the page. It thinks on a thread of its own, so the screen and the clocks carry on while it does: under a second at Easy and Medium, one or two at Hard. The page freezes while it thinks, and its clock does too, so there the computer's clock hardly moves. Here it runs.

Needs a 68x19 terminal.

Playing people online (a prototype)

PLAY ONLINE on the title, or chess --online, connects to the arcade's own multiplayer server, the one behind the page's PLAY ONLINE button, so a terminal can play a browser. Type a name, then press C to create a room and read its four-letter code to your opponent, or J to join one. The first in plays white; the host presses Enter to start once both are in. Black sees the board from black's side, as on the page. You move as against the computer, a promotion asks for its piece, and X then Y resigns.

pip install "magmacrunch-chess[online]"     # websockets, only for this
chess --online
chess --online --server ws://127.0.0.1:8769  # a web/server.py on this machine

The server keeps the rules. This client sends the square a piece leaves and the square it lands on, and the piece for a promotion straight after, and draws the board the server sends back. It works out the legal moves only to mark them, with rules.py, the page's own rules, which tests/test_server_parity.py holds to the server's own, piece by piece, in over 20,000 positions with castling, en passant and promotion. The server sends no notation, so the move list is written here, from the positions before and after, as chess writes it. neon_chess/online.py holds the protocol, split into Table (the server's state, with no I/O) and Connection (the WebSocket, on its own thread). online_scenes.py reuses the computer game's screen with the server's state in place of a local game.

tests/test_online.py runs web/server.py in-process on a free port and plays it over real sockets. It covers:

  • a hundred moves of random play, promotions to every piece included. After every move both clients' boards, castling rights and en passant must match a shadow kept with rules.py, and the notation must match;
  • checkmate, a promotion to a knight, a resignation, out-of-turn and illegal moves, a wrong room code, a player leaving and a dead address;
  • two complete terminal sessions, by keys alone: the lobby, a move each (black's on the turned board) and a resignation.

It never contacts the live server. By hand, the real page in headless Chromium played a terminal client both ways through a local web/server.py: as white for eight moves, and as black for eleven with a capture, a check and both kings moving. Every board on both sides matched the position the moves give.

What the page gets wrong online, seen in that run:

  • The page used to castle across a swept square, and then hang. Fixed in both; see below.
  • The page's move list online has only your own moves. It writes a move when you make it and nothing when the server reports your opponent's: the page as white listed e4 Nf3 g3 Bh3 O-O.
  • The host's START button shows before anyone has joined. Pressed early, it starts nothing, and says nothing.

The server's rules, which a prototype can only follow:

  • The lobby's clock does nothing. The host may pick a time control; the server stores it and runs no clock, and neither does the page. So this client offers none.
  • Nobody can take a leaver's place. A player leaving ends the game, and the one left is told they win, as on the page; the server records no result.

What a prototype has not done yet:

  • Nobody has played the live server from a terminal, only a copy of it run locally. The default address is wss://magmacrunch.duckdns.org/chess, which is what mpServerFor('chess', 8769) gives the public site.
  • No reconnect. A dropped connection says so, and the game is lost.
  • No chat, and no watching, which the browser has.

It is the browser's game, and the browser's opponent

neon_chess/rules.py is web/js/config.js, board.js, ai.js and game.js, ported function for function: the squares searched in the same order, the moves listed in the same order, the same evaluation and the same alpha-beta, so the computer picks the same move as the page's in every position. Two tests hold it there:

  • tests/test_oracle.py. tools/js_oracle.mjs loads those files unmodified and plays two kinds of game through them:

    • 12 games against the computer, through Game's own API as main.js drives it: 6 at Easy, 4 at Medium and 2 at Hard. Half have a random player; half a careful one, who opens at random and then takes the biggest capture it can. The computer won every game that finished.
    • 200 games of random moves for both sides, through Board alone, up to 300 moves each. They end in 21 checkmates and 12 stalemates, and cover 360 promotions to every piece, 15 castlings and en passant.

    The test replays all 56,000 moves through the port. After each one it requires the same board, castling rights, en passant square and check, and the same list of legal moves in the page's order. In the computer games the game state, turn, move list and result must match too. Changing the bishop's value from 330 to 320 fails it, at Easy, move 34.

  • tests/test_rules.py. It sets up by hand the cases worth pinning, including the page's own rules below, so that fixing one shows as a change.

The port is quicker than a straight copy. It looks outward from a square for an attacker rather than asking every enemy piece, undoes a trial move rather than copying the board, and adds up the evaluation tables once. Each gives the page's answer, which the oracle checks.

The computer's promotions, fixed in both

The page's computer would not promote a free pawn, at any level. Inside its search a pawn reaching the last row stayed a pawn: Board.applyMove promotes only to a piece the move names, and a move names none until it is played. The pawn table rates a pawn one row short at 50 and one on the last row at 0, so the search preferred to hold a pawn back. With a pawn on h2 and nothing to stop it, Easy, Medium and Hard all moved their king instead. Nor could it see your promotions coming: with your pawn on b7, Easy played Kg8 and let it queen for nothing.

Now a promotion tried inside the search is a queen, which is what the computer plays when it makes the move. All three levels queen the h2 pawn, and every level stops yours, Easy with a check and Medium and Hard with a rook behind it. This is fixed in web/js/ai.js (searchMove) and here (_search_move) together. tests/test_oracle.py asks the page's own ai.js both positions at every level and requires the port's answers. The ai.js from before the fix fails that test: it moves its king. In headless Chromium, the fixed page played a game opening with no errors, and its AI.chooseMove queened the pawn at all three levels.

Castling across an attacked square, fixed in both

The page's bishops, rooks and queens attacked only occupied squares. getSlidingAttacks in board.js listed the first piece in each direction and none of the empty squares before it. Check was unaffected, since a king stands on its square, but you or the computer could castle across a square a slider swept. web/server.py gets this right and refuses that castle.

Online, that hung the game. The page moves its king before the server answers, and the server ignores a move it refuses without a word, so the page waited on its opponent for good while the server and the opponent waited on it. In headless Chromium against a terminal client, after 1.e4 b6 2.Nf3 Ba6 3.g3 Nc6 4.Bh3 Nf6, the page offered O-O across f1, which the bishop on a6 sweeps. It drew its king on g1 and said "Waiting for opponent...", with the server's king still on e1 and white to move.

Now getSlidingAttacks lists every square up to and including the first piece. In the same game the fixed page does not offer the castle. Clicking g1 leaves it on "Select a piece to move", with its board still the server's and white still to move. The port matches it (Board.attacked), so against the computer the rule is chess's too, and the online client needs no rules of its own: tests/test_server_parity.py compares the port with the server directly. tests/test_oracle.py asks the page's own board.js for the king's moves with a rook sweeping f1, and the old board.js fails it by offering O-O. tests/test_rules.py covers a rook, a bishop and a queen sweeping f1, and a knight covering it.

The page's rules

These are the page's own, kept because the oracle requires them. Each is a place where the page is not chess:

  • The computer's moves are written without their piece. formatMove looks for the piece on the square it has just left, so the move list has c6 for Nc6 and xe5 for Bxe5. Your moves are never disambiguated, because it looks for a second piece that could reach the square after yours has taken it: two rooks to d1 is written Rd1.
  • There is no draw but stalemate. No repetition, no fifty-move rule, no insufficient material: a king against a king plays on until R.
  • Game over is asked of you first. After your move, if you would have no legal move, the game ends in stalemate, though it is the computer's turn.

Two of the page's clicks work differently here. On the page, a second piece can only be picked up once the first is put back; here Enter on it picks it up. And the page's clock stops while the computer thinks, as above.

There is no high-score table, because the page keeps none.

Licence

PolyForm Noncommercial 1.0.0, as for the rest of this repository. See LICENSE and NOTICE.

Metadata

Release files for magmacrunch-chess 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for magmacrunch-chess 0.1.1
File Size Uploaded Provenance
magmacrunch_chess-0.1.1.tar.gz 46.6 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for magmacrunch-chess 0.1.1
File Interpreter ABI Platform
magmacrunch_chess-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 83.2 kB

Release files / magmacrunch_chess-0.1.1.tar.gz

Download URL magmacrunch_chess-0.1.1.tar.gz
Size 46.6 kB
Tags Source
SHA-256 checksum
How to use checksums
e8eebc2e2461ff95911fed6ab56c4c8adefcac694fd3d34d0f8f7c4b130ba659
BLAKE2b-256 checksum
How to use checksums
0af80ed96456a7e87dd4a80959d079e484115c6c6a8dc33d1e0c9363795c2ca6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / magmacrunch_chess-0.1.1-py3-none-any.whl

Download URL magmacrunch_chess-0.1.1-py3-none-any.whl
Size 36.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e40cbe6ecfadbda260dfaff2494a1c409fa10c324250c19d7fff0729b223ac5a
BLAKE2b-256 checksum
How to use checksums
0a33de3ae9a0c8b5dad2adc575eee4883d3acd29bb4d3990e7d639f664f31a0d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Security for magmacrunch-chess 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for magmacrunch_chess-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

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