Konami's Mahjong

Thirty-two kilobytes in which the main thread does nothing: it starts up, hooks the interrupt and settles into a jump to itself forever. And the opponent, which plays well, does not think either: its hand is built one tile short of complete, and what goes into its river is a tile drawn at random from the wall through a filter that makes it look human.

Konami · © Konami 1984 · An RC-707 32 KB cartridge · MSX1 · pages 1 and 2 · Dump 24cb5bda…

Every picture here is a screenshot of the cartridge. And not one was taken by hand: a script boots the ROM in openMSX with nothing being drawn, dumps video memory at a few fixed instants, and the PNG is built from the dump. The first pass does not press a single key, because the demo plays itself. The listing and the numbers come from the binary and are reproducible with make.

The game in numbers

100%of the binary explained
340routines identified
38named yaku
15,432bytes of code
17,336bytes of data
0bytes unidentified

What turned up when we took it apart

The opponent plays well and never thinks once

It declares riichi, calls pon and chi, defends itself when it is losing and wins expensive hands. But it never evaluates its hand, and the two pieces holding it up are equally brazen.

The first: its hand is not drawn, it is built. Before anything is dealt, 0x78CE assembles fourteen tiles to order —a suit, a few triplets, runs or pairs, and a pair at the end— and then takes one away. The machine starts every hand one single tile short of completing it, and the copies it spends are deducted from the counters so the player cannot draw them later.

The second: it does not discard from its hand. Its thirteen tiles never move; what goes into its river is a tile drawn at random from the wall (0x583C) and put through a filter: the first four discards are honours, the next four ones, twos, eights and nines, never one of its own waits and never from the suit it is going for. Which is the order a person discards in, arrived at without looking at the hand.

The empty slot in its hand is theatre

When the opponent's face-down hand is drawn, one of the tiles is shown as a gap, and it looks like it is telling you where it has just drawn. Half the time that is not true: 0x553C picks that gap either at random or as the drawn tile's, depending on bit 0 of the seed, and it only becomes honest once the machine is in riichi.

Three instructions that have not run since 1984

Next to the discard filter there is a check meant to avoid throwing terminals, and it is written wrong. It compares the tile's number with 1 and, if it is not a 1, returns; and if it is, it compares that same 1 with 9, which does not match either, and returns just the same.

5961:  cp 1
5963:  jr nz,5987      ; not a 1 -> accepted
5965:  cp 9            ; A is 1: it is never 9
5967:  jr nz,5987      ; -> accepted anyway
5969:  call ...        ; put it back and draw another:
596C:  call ...        ; THREE instructions that never run

The redraw below is perfectly well formed and never executes.

The scores do not add up to 60,000, and that is on purpose

With tsumo, the payment comes from the «on the draw» tables, which are what a single player would pay at a four-seat table. But 0x5B85 loads the same figure into both pending amounts and then only reduces the payer's, not the collector's: the loser pays one player's share and the winner collects the full ron figure.

Points are created out of nothing, and the scoring screen prints it without flinching, with ハライ (paid) and トクテン (collected) on two separate lines. In the demo 6,000 are paid and 18,000 collected, and the two scores end at 23,000 and 48,000.

The same 8 is both a state and a difficulty

When the demo starts, the cartridge writes an 8 into the state byte. That 8 never gets dispatched —the next instruction does an inc, so the state that runs is 9— and yet it is written:

418C:  ld a,008h
418E:  ld (0E000h),a   ; the state... which will turn into 9
418F:  rra             ; the same 8, rotated: out comes a 4
4190:  ld (0E040h),a   ; and that 4 is THE DIFFICULTY

As a side effect, the demo plays on the middle difficulty: 0xE040 is 4 for the whole cycle, and the top bar labels it セミプロ, while a game started with key 1 reads アマ in the same place.

The table's text lives in the gap inside the tiles

Every tile is drawn with six characters, two wide by three tall, and the rows always fall across two thirds of the screen. In the middle third you only see the bottom row of the tiles above and the top row of the tiles below: the middle row of each tile is never drawn there.

And that is where the text is. Crossing the tile table with the name tables of 124 video memory dumps, of the 97 tiles the central bar uses 56 are exactly the middle pair of some tile. The same tile number is half a mahjong tile in one third and a kanji in another.

The demo does not think: it reads one hundred and four bytes

There is no separate demo mode. When nobody touches anything, the cartridge walks the same state machine a real game does, through the same routines; the only thing that changes is where the keypresses come from. 0x416B hooks the block at 0x4AE8 —one hundred and four bytes— up in place of the keyboard, with the very bit masks the real reader builds and a variable-length format: the low nibble of each entry says whether it takes one byte or two.

That is why it comes out the same every time: two independent cold boots give the same trace, instant for instant. What is not constant is how long each lap takes —163.53, 168.96 and 170.56 seconds were measured between passes through state 0—, because the random seed comes from the memory refresh register R, and with it changes the hand the machine builds for itself.

It does not carry Konami's hidden mark

Many Konami cartridges of this period hide their RC-7xx catalogue number and the game's title in katakana at the end of the ROM; it was Manuel Pazos (@ManuelPazosMSX) who found that out.

This one does not. In all 32768 bytes there is not one RC-7 in ASCII, nor the word KONAMI: the content ends at 0x9FE4, in the semitone table, and behind it there are only 8,219 bytes of 0xFF. The RC-707 comes from the catalogue, not from the binary.

What the cartridge draws

Under each picture is the game state the screenshot was taken in and what is on it.

State 5 — the title, 麻雀道場, with the copyright written in the game's own font and the three difficulties in romaji. Whichever key you press here ends up in 0xE040, and it does not change for the rest of the game
State 5 — the title, 麻雀道場, with the copyright written in the game's own font and the three difficulties in romaji. Whichever key you press here ends up in 0xE040, and it does not change for the rest of the game
State 11, step 1 — the table with the deal starting: both scores at 30,000, the wind and hand number (東一局), the two indicator tiles, the table's riichi stick counter at zero (0本) and the call menu in the cyan panel
State 11, step 1 — the table with the deal starting: both scores at 30,000, the wind and hand number (東一局), the two indicator tiles, the table's riichi stick counter at zero (0本) and the call menu in the cyan panel
State 11, step 2 — just dealt. Thirteen tiles face down on top and fourteen below, sorted: five characters, four circles, two bamboos and three honours, which are codes 02 06 08 08 09 · 11 13 15 17 · 22 22 · 31 31 33
State 11, step 2 — just dealt. Thirteen tiles face down on top and fourteen below, sorted: five characters, four circles, two bamboos and three honours, which are codes 02 06 08 08 09 · 11 13 15 17 · 22 22 · 31 31 33
State 11, step 2 — the hand well along, both rivers full. The top score has dropped to 29,000 and there is a stick on the table: the machine has declared riichi. In the cyan box, the カン or discard prompt
State 11, step 2 — the hand well along, both rivers full. The top score has dropped to 29,000 and there is a stick on the table: the machine has declared riichi. In the cyan box, the カン or discard prompt
State 11, step 7 — the scoring: 親 (the dealer wins), 30 fu, 7 han, ハライ 6,000 and トクテン 18,000, the list of yaku on the right and the hand split into sets below, each with its fu
State 11, step 7 — the scoring: 親 (the dealer wins), 30 fu, 7 han, ハライ 6,000 and トクテン 18,000, the list of yaku on the right and the hand split into sets below, each with its fu
State 14 — 終局, the end of the game, written over a wall of tiles that is built up tile by tile in the previous state
State 14 — 終局, the end of the game, written over a wall of tiles that is built up tile by tile in the previous state
State 11 in a real game, started with key 1. It is the same screen as the demo's with one difference: where the demo reads セミプロ, this reads アマ
State 11 in a real game, started with key 1. It is the same screen as the demo's with one difference: where the demo reads セミプロ, this reads アマ