Every machine in picochess retro.ini after the port of the chessengine interfaces to MAME 0.289: what works, known limits, levels, and the commits that reported each change. Status as of 2026-11-11 (chessengine bb17219, mame_for_picochess 14126ba).
| System | Name | Year | Elo | Levels | FEN | History | Info | Ponder |
|---|
init.lua is the chessengine plugin itself (Sandro Ronco's MAME plugin, as used by picochess). It talks UCI (or xboard) on stdin/stdout, keeps its own copy of the board, and drives the emulated machine through a per-machine interface file: pressing sensor-board squares and keys for the player's moves, and reading the machine's moves from its LEDs and displays. At machine reset it loads interfaces/<system>.lua, or the parent set's file when a clone has none. An interface can build on another with load_interface("name").
The interface files were ported to MAME 0.289 (output values through machine.devices[":"]:output(name) in place of the removed output:get_value). init.lua needed no API port, but it gained the changes below during the port. Each one is opt-in for the interfaces, so machines that don't use a hook behave as before.
| Commit | Date | Change |
|---|---|---|
| 2b25951 | 2026-10-08 | Error message when an interface uses a port or key mask that doesn't exist. |
| 0c71ed8 | 2026-10-09 | The promotion piece from test_promotion() is lowercased. Interfaces return Q/R…, which gave bestmove b7b8R, and the board didn't record the promotion. |
| 755f7da | 2026-10-15 | MAME exits cleanly on quit. The stdin reader thread stayed blocked in io.stdin:read (MAME hung after printing its speed), and on a closed stdin it looped on EOF and segfaulted. |
| c3997da | 2026-10-26 | interface.ignore_late_go: a go that arrives after the machine already answered the last position on its own is ignored. Without it, start_play made the machine move for the other side. Set on 160 interfaces after the Phase 3 late-go check (af6cb5a and later). |
| 6f4c493 | 2026-10-29 | interface.game_over(): when it returns true on the machine's turn, init.lua sends bestmove 0000 once (reset by the next position). picochess then scores mate, stalemate and dead draws itself and treats anything else as a resignation. Used by tchess, slc1, poly880s, prisma, smondial2, sexperta/sfortea family, zircon2, mentor16. |
| b642b74 | 2026-10-29 | Threefold repetition: init.lua counts positions (board + side to move). When the machine is to move in a position seen three times, or can claim before its move, and stays silent longer than twice its longest move of the game (at least 30 s emulated), it sends bestmove 0000 once. 98 of 239 machines claimed the draw silently and stopped; all now end with 0000. |
| 9452bd9 | 2026-10-30 | interface.resigned(): polled on the player's turn, because a resign sign shown together with the machine's move can be gone by the machine's next turn. When it fires, init.lua sends bestmove 0000 at the start of that turn (smondial2 rESG). |
| 3e53188 | 2026-10-30 | format_info(): one info format for all machines. show_info() returns a table {depth, seldepth, score, mate, pv} (old-style strings still work) and init.lua writes info depth D [seldepth S] score cp|mate X pv … the way python-chess parses it in picochess. Empty fields are left out, castling notations (O-O, 0-0) become e1g1 etc., a promotion without a piece becomes a queen, and the pv stops at its first illegal move (python-chess drops the whole pv otherwise). New optional interface.info_every. |
| 506d638 | 2026-10-30 | show_info runs every 10 s of emulated time (or info_every) instead of every 500 ticks, which some drivers never reached during a search. In the same commit, show_info was switched off on 16 interfaces that pressed keys while the machine thought. A press could land just as the move appeared and hide it. Most of them now read their info from RAM or a display page without key presses. |
| 542b983 | 2026-10-30 | depth 0 (shown before the first iteration) is left out of the info line. |
| da0d4a3 | 2026-11-01 | Chessmate sets (ccmk2, ccmk2a, chmate) run setup and game edits unthrottled; the talking machines stay throttled (unthrottled speech plays partly sped up). |
| f0b8554 | 2026-11-01 | Set Pos / Read Game: a replayed history leaves the machine in edit mode and idle until go (a player move arriving first is keyed in as part of the history), so it no longer moves for the player; generalizes Johan's MM V fix. The id name reports edit (e.g. (pos+edit+info)), which picochess uses to decide whether Set Pos sends the history. Talking machines in one keep_throttled table; dead sc80/sparc code removed. |
| 021277d | 2026-11-01 | interface.no_soft_reset replaces the name list that skips the soft reset on ucinewgame; clones inherit it (avrmaxg hung in a second game). |
| 9aee91d | 2026-11-04 | The player's underpromotion goes in through the position setup on queen-only machines (interface.setup_underpromotion). |
| 346cb87 | 2026-11-05 | Sound is muted while the machine runs unthrottled (sound.system_mute), for all interfaces: speech and beeps are garbled at that speed. |
| Hook | Role |
|---|---|
| setup_machine() | Runs after boot: waits for the machine to be ready, sets options (sound off, display modes, info display). |
| start_play(init) | Makes the machine move (go). stop_play() interrupts a search where the machine allows it. |
| is_selected(x, y) / select_piece(x, y, event) | Reads the machine's move from LEDs or display, and enters the player's move (lift/put or key presses). |
| set_pos(mode) | Sets up a FEN position (sensor-board rebuild, keypad entry or RAM). Absent = start position only. |
| edit_game(on) | Replays a game history into the machine (Multi-Move, Monitor or Referee mode). Absent = only a fresh position. |
| test_promotion / get_promotion / promote / promote_special | Detects the machine's promotion piece, enters the player's promotion. |
| setlevel, get_options, set_option | Levels and options as offered in picochess (the .uci file holds the level strings). |
| show_info() + info_every | Live search info (depth, score, main line) while the machine thinks. |
| show_pv_after_move_emu / _player | Older info hooks, kept only where show_info needs them (ccmk5, risc2500, super9cc; audit 6a076b4). |
| game_over(), resigned() | Game end and resignation; init.lua answers bestmove 0000. |
| ignore_late_go | Flag for machines that answer the player's move on their own. |
| setup_underpromotion | Flag for queen-only machines: the player's underpromotion goes in through the position setup. |
| no_soft_reset | Flag for machines that hang after a soft reset on ucinewgame (avrmax, kblitz, fphantom, cphantom families). |
Most older machines promote to a queen by themselves and can't take another piece as a move. On machines with a position setup, the plugin plays the move on its own board, restarts the machine and sets up the resulting position, then the machine plays on. The same happens when a move list with an underpromotion is replayed. Tested in picochess, including selecting moves before and after the underpromotion and continuing the game. The level is kept. picochess keeps the game and its own clocks. Limits on the machine's side:
bestmove ----) ending as an engine failure instead of a hang (PR #563).bestmove 0000 as a draw when threefold repetition or the fifty-move rule can be claimed (PR #567).quit and, on a timeout, a kill of their own process group, in place of pkill -9 -f mess. Settings such as the chosen artwork view persist in cfg/ (PR #569).edit marker (Johan's picochess 3e70cd8e) tested on a real board with MM V and Fidelity Excellence.set_pos). Without it the machine plays from the start position only.edit_game), so a game can continue after takebacks or a restart. Without it, picochess can only start new games or set positions. picochess sees it as edit in the engine name and then sends the move history with Set Pos and Read Game.show_info), read without key presses.ponder/brain = y in retro.ini, meaning the machine thinks on the player's time. Measured from a non-book position, not taken from the manual.These apply to almost every machine and are not repeated in each machine's list:
bestmove 0000 after a timeout.| Test | What it checks |
|---|---|
| ep_p | Player captures en passant right after a FEN position (e.p. square only in the FEN). Most machines can't take the e.p. right from a setup; this fails on almost all of them. |
| ep_p2, ep_ps, ep, ep2, ep3, ep_w | En passant after real moves, by the player and by the machine. |
| ur_b2, ub_b2, up_* | Underpromotion by the player (rook, bishop, knight; with and without capture). Many machines only know queen promotion. |
| promo_* | Promotions by machine and player, also inside a replayed history. |
| kn_k, ka_* | Dead draws (K+minor vs K, bare kings). Many machines just stop thinking there. |
| kc_*, kp_*, a8_br, bk_h1 | Positions machines refuse to set up (king on a corner or promotion square, no pawns). A refusal counts as a pass. |
| chk_b, chk_w, only1, only2, ss_g3 | Forced and lost positions. Some ROMs resign here. |
| rep3 | Threefold repetition: the machine must end the game, not stall. |
| start, black, black_a3, fen_w, fen_b, castle* | Basic play from the start, as Black, out of book (a2a3), from FENs, castling. |
| neg, info | Live info check: machine Black a queen down must show about −9 (score from the machine's side). |
| game10, r70 | Long replays of real games (history replay stress). |