ポケモン赤で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