ポケモン赤でFizzBuzz
ゲームボーイ「ポケモン赤」の任意コード実行バグを使ってFizzBuzzを実装しました。 FizzBuzzとは数字を順に言っていくゲームで、ただし3の倍数ならFizz、5の倍数ならBuzz、3の倍数かつ5の倍数ならFizzBuzzを言うというものです (参考文献 [1])。

↓これは最初に作ったバージョン (低機能)
ポケモン赤でFizzBuzzを実装しました! (「ふぃずばす」でなく「ふぃすはす」なのはご愛嬌…) pic.twitter.com/TxqCJtZMHQ
— でぃぐにゃん (@fujidig) 2022年1月1日
ポケモン赤でFizzBuzzの続きです。
— でぃぐにゃん (@fujidig) 2022年1月2日
スクロールしたときポケモンの鳴き声 or 効果音が鳴ります。一番上の項目が数字ならその内部IDのポケモンの鳴き声、FizzかBuzzなら効果音、FizzBuzzならファンファーレが鳴ります。 pic.twitter.com/PjXQrJx4Va
機能
下にスクロールすることができて、一番上の項目に応じてポケモンの鳴き声 or 効果音が流れます。 数字ならポケモンの鳴き声、FizzとBuzzなら効果音、FizzBuzzならファンファーレが鳴ります。 なおメニューに戻る方法は実装していません。
実行方法
・バイナリエディタ (参考文献 [2])を導入します
・なかよしバッヂからバイナリエディタを起動し次のように書き換えます。
アドレスD985にC3 B3 D9 (jp D9B3)を書き込む
アドレスD9B3 (ボックスのポケモンのステータスが格納される場所)に以下の305バイトの内容を書き込む 18 10 00 00 a0 a0 a0 a0 a0 a0 00 00 00 00 00 00 00 00 cd 67 01 06 00 0e 10 26 d9 2e b5 16 8e 1e 50 cd bb 01 cd 81 01 06 01 c5 cd 67 38 c1 21 a0 c3 f0 b3 cb 7f 28 38 c5 c5 cd 3a da c1 fe 00 28 0e fe 01 28 14 fe 02 28 1a 78 cd b5 2d 18 1e 3e 89 cd 33 0e cd 7e 37 18 14 3e 86 cd 33 0e cd 7e 37 18 0a 3e 8e cd 33 0e cd 7e 37 18 00 c1 04 0e 00 e5 c5 cd 77 da c1 e1 3e 14 85 6f 30 01 24 0c 79 fe 12 20 ec 18 a2 af e0 95 e0 96 e0 97 78 e0 98 3e 0f e0 99 06 04 cd f0 38 f0 99 fe 00 28 1b fe 03 28 1a fe 06 28 16 fe 09 28 12 fe 0c 28 0e fe 05 28 0d fe 0a 28 09 3e 03 c9 3e 00 c9 3e 01 c9 3e 02 c9 e5 e5 f8 02 36 00 23 78 81 47 70 cd 3a da e1 fe 00 28 19 fe 01 28 2e fe 02 28 3e e5 f8 02 54 5d e1 36 f6 23 01 07 c2 cd 7d 3c 18 3f 36 cc 23 36 6e 23 36 bd 23 36 e5 23 36 ca 23 36 e5 23 36 bd 23 36 e5 18 26 36 cc 23 36 6e 23 36 bd 23 36 e5 3e 7f 23 22 22 22 77 18 12 36 ca 23 36 e5 23 36 bd 23 36 e5 3e 7f 23 22 22 22 77 e1 c9
・バイナリエディタを閉じてもう一度なかよしバッヂを使う
・FizzBuzzが実行されます
参考文献
[2] 【初代ポケモン】バイナリエディタで Do-Dai 【任意コード実行】 - Wonderland Seeker
[3] GitHub - ulrikdamm/Assembler: Assembler for Gameboy games
文献[2]のバイナリエディタのコードはFizzBuzzのコードを作成する上でも非常に参考にした。
付録
書いたアセンブリです。 文献[3]のアセンブラでアセンブルできます。 もっと短いコードに出来ると思います。
[org(0xd9b3)]
first:
jr start
tile:
db 0x00
db 0x00
db 0xa0
db 0xa0
db 0xa0
db 0xa0
db 0xa0
db 0xa0
db 0x00
db 0x00
db 0x00
db 0x00
db 0x00
db 0x00
db 0x00
db 0x00
start:
call 0x0167 ; DisableLCD
ld b, 0
ld c, 0x10aa
ld h, (tile >> 8)
ld l, (tile & 0xff)
ld d, 0x8e
ld e, 0x50
call 0x01bb ; CopyData
call 0x0181 ; EnableLCD
ld b, 1
mainloop:
push bc
call 0x3867 ; JoypadLowSensitivity
pop bc
ld hl, 0xC3A0 ; wTileMap
ld a, [0xffb3] ; hJoyPressed
bit 7, a
jr z, skipincrcounter
push bc
push bc
call judge_fizzbuzz
pop bc
cp 0
jr z, fizzbuzz
cp 1
jr z, fizz
cp 2
jr z, buzz
general0:
ld a, b
call 0x2DB5 ; PlayCry
jr endofcry
fizzbuzz:
ld a, 0x89
call 0x0e33 ; PlaySound
call 0x377e ; WaitForSoundToFinish
jr endofcry
fizz:
ld a, 0x86
call 0x0e33 ; PlaySound
call 0x377e ; WaitForSoundToFinish
jr endofcry
buzz:
ld a, 0x8e
call 0x0e33 ; PlaySound
call 0x377e ; WaitForSoundToFinish
jr endofcry
endofcry:
pop bc
inc b
skipincrcounter:
ld c, 0
loop:
push hl
push bc
call print
pop bc
pop hl
ld a, 0x14
add a, l
ld l,a
jr nc, skipincrh
inc h
skipincrh:
inc c
ld a, c
cp 0x12
jr nz, loop
jr mainloop
judge_fizzbuzz:
xor a
ld [0xff95], a
ld [0xff96], a
ld [0xff97], a
ld a, b
ld [0xff98], a
ld a, 0x0F
ld [0xff99], a
ld b, 04
call 0x38F0 ; Divide
ld a, [0xff99]
cp 0
jr z, zero
cp 3
jr z, mod3
cp 6
jr z, mod3
cp 9
jr z, mod3
cp 0x0c
jr z, mod3
cp 5
jr z, mod5
cp 0x0A
jr z, mod5
ld a, 3
ret
zero:
ld a, 0
ret
mod3:
ld a, 1
ret
mod5:
ld a, 2
ret
print:
push hl
push hl
ld hl, sp+2
ld [hl], 0
inc hl
ld a, b
add a, c
ld b, a
ld [hl], b
call judge_fizzbuzz
pop hl
cp 0
jr z, ifzero
cp 1
jr z, ifmod3
cp 2
jr z, ifmod5
general1:
push hl
ld hl, sp+2
ld d, h
ld e, l
pop hl
ld [hl], 0xF6
inc hl
ld bc, 0xc207
call 0x3C7D ; PrintNumber
jr return
ifzero:
ld [hl], 0xCC
inc hl
ld [hl], 0x6E
inc hl
ld [hl], 0xBD
inc hl
ld [hl], 0xE5
inc hl
ld [hl], 0xCA
inc hl
ld [hl], 0xE5
inc hl
ld [hl], 0xBD
inc hl
ld [hl], 0xE5
jr return
ifmod3:
ld [hl], 0xCC
inc hl
ld [hl], 0x6E
inc hl
ld [hl], 0xBD
inc hl
ld [hl], 0xE5
ld a, 0x7F
inc hl
ld [hl+], a
ld [hl+], a
ld [hl+], a
ld [hl], a
jr return
ifmod5:
ld [hl], 0xCA
inc hl
ld [hl], 0xE5
inc hl
ld [hl], 0xBD
inc hl
ld [hl], 0xE5
ld a, 0x7F
inc hl
ld [hl+], a
ld [hl+], a
ld [hl+], a
ld [hl], a
return:
pop hl
ret
付録2
機能の少ない最初のバージョンのコードも載せておきます。 DE64 (ボックスのニックネームのアドレス)に以下を書き込めばよいです。 これは159バイトなのでボックスのニックネームのメモリ領域に収まります。
06 01 c5 cd 67 38 c1 21 a0 c3 f0 b3 cb 7f 28 01 04 0e 00 e5 c5 e5 cd 8f de e1 c1 e1 3e 14 85 6f 30 01 24 0c 79 fe 12 20 ea 18 d7 e5 f8 04 36 00 23 78 81 47 70 e1 af e0 95 e0 96 e0 97 78 e0 98 3e 0f e0 99 06 04 cd f0 38 f0 99 fe 00 28 1a fe 03 28 25 fe 06 28 21 fe 09 28 1d fe 0c 28 19 fe 05 28 23 fe 0a 28 1f 18 29 36 cc 23 36 6e 23 36 bd 23 36 ca 23 36 bd c9 36 cc 23 36 6e 23 36 bd 3e 7f 23 22 77 c9 36 ca 23 36 bd 3e 7f 23 22 22 77 c9 e5 f8 04 54 5d e1 01 05 c2 cd 7d 3c c9