AIに「BASICでテトリス作って」と頼んだら、時空を超えたハルシネーションが始まった話(AIをバカにする記事ではありません。)
ホームページ制作担当のNです。
AI流行ってますよね。当社でも過去の記事でAIを使用したロボットを紹介したことがありました。
今回はcopilotとgeminiで面白いやり取りが発生したので記事にしてみました。
プログラム経験のない方には分からない内容となっていてすみません。分かる方だけ楽しんでください。
✨この記事のざっくりポイント
- 今回は「AIに N88-BASIC でテトリス作って」と頼んだら、堂々と“存在しない仕様”を語り始めたというレトロ技術者には刺さる珍事件を扱う。
- AIは時々知らない部分を“それっぽく補完”してしまうクセがあり、これはいわゆる 文脈補完型ハルシネーション の典型例。
- 特に古い言語やマイナー環境では、AIが「学習データの空白」を推測で埋めに来るため、こうした現象が起きやすい。
- なので、AIにレトロ環境の話をするときは、前提条件・制約をガッチリ明示する のが最重要。
※ここでいう「AIのハルシネーション」は、実在しない仕様や事実を“自信満々に”生成してしまう現象のこと。
はじめに:AIにレトロBASICをやらせてみたら
AIにコードを書かせると、今どきの言語ならそこそこ使えるものを出してくれます。
ところが N88-日本語BASIC(86) みたいなレトロ言語を渡した瞬間、AIの様子が怪しくなります。
例えるなら:
>「最新スマホばかり使ってきた人に、いきなり黒電話を渡す」
みたいな感じです。
受話器は持つんだけど、ダイヤルの回し方がおかしい。
今回はそんなAIに 「PC-98 の N88-日本語BASIC(86)でテトリス作って」 とお願いしてみたら、なかなか味わい深いハルシネーションが見られたのでそれを眺めてニヤニヤする記事です。
AIを笑うための記事ではなく、「AIってこうズレるんだな」という 観察日記 くらいのテンションで読んでもらえれば。
BASICは“方言の世界”だった
今のプログラミング言語は、どれもそれなりに似ています。if があって、for があって、else if があって…みたいな。
しかし、昔のBASICは 完全に方言の世界 でした。
- PC-98 の N88-BASIC
→ 高解像度グラフィック。SCREEN番号も独自の雰囲気。 - MSX-BASIC
→ スプライトが標準装備。「えっ、動くキャラが当たり前なの?」という世界。 - X1 の Hu-BASIC
→ カラーやグラフィック命令が一味違う。 - FM-7 の F-BASIC
→ 文字座標とグラフィック座標のノリが独特。 - MZ の BASIC
→ そもそもグラフィックするにはひと工夫いることも。
>「同じBASICって名乗ってるのに、標準語のつもりで話したら通じない」
そんな時代です。
AIからすると、
>「BASIC? うんうん、知ってるよ!」
>(※どのBASICとは言ってない)
という状態なので、
どの方言で答えればいいのか、けっこう迷子になります。
そこへ N88-日本語BASIC(86) というAIにとってかなりマニアックな方言をぶつけると、現代言語の癖+BASICのうろ覚え知識 が混ざっていい感じにハルシネーションが発生するわけです。
その結果、N88-BASIC(86) のようなレトロ言語を扱わせると、現代言語の癖と混ざってハルシネーションが起きやすい。
テトリスを題材にした理由
テトリスを選んだ理由はシンプルで、
- 左右に動く
- 回転する
- 落ちていく
という操作が分かりやすく、INKEY$ の説明にちょうどいいからです。
>「Aキーで左」「Dキーで右」「Sで落下」「Wで回転」
>みたいな操作は、想像しやすいですよね。
ということで、本題。
ここからは「AIが実際にやらかした美しい珍プレー集」を見ていきます。
🕹️実際に起きたAIのハルシネーション集
🕹️ ハルシネーション① INKEY$ を2回読むAI
〜そんなに好き?ってくらい INKEY$ をおかわりする〜
AIが本気を出すと、なぜか INKEY$ を2回読みたがる 傾向があります。
AI「キー入力? 任せて。1回読んで、もう1回読めば完璧でしょ!」
その結果、こうなります。
❌ AIが書きがちな誤った例
10 IF INKEY$ <> "" THEN GOSUB *CHECK_KEY
20 GOTO 10
100 *CHECK_KEY
110 A$ = INKEY$ ' ← ここで2回目のINKEY$を読んでしまう
120 IF A$ = "A" THEN GOSUB *MOVE_LEFT
130 IF A$ = "D" THEN GOSUB *MOVE_RIGHT
140 IF A$ = "S" THEN GOSUB *SOFT_DROP
150 IF A$ = "W" THEN GOSUB *ROTATE
160 RETURN
一見それっぽいです。
「INKEY$ が空じゃなかったらサブルーチンへ」 → なんか賢そうに見える。
でも、よく見ると INKEY$ を2回呼んでいる んですよね。
📘 図解:キーバッファの消費
[ キーバッファの状態 ]
┌───┬───┬───┐
│ A │ D │ S │ ← 押された順
└───┴───┴───┘
1回目の INKEY$(10行目)
→ A を取得(バッファ消費)
2回目の INKEY$(110行目)
→ D を取得(さらに消費)
【結果】
押したキー:A
判定されたキー:D
→ 「なんでやねん!」となる
>「A を押したのに D が押されたことになっているテトリス」
>…地味に遊びにくいですね。
✅ 正しい例
素直に 1回だけ読む のが正解です。
10 A$ = INKEY$
20 IF A$ = "" THEN GOTO 10
30 IF A$ = "A" THEN GOSUB *MOVE_LEFT
40 IF A$ = "D" THEN GOSUB *MOVE_RIGHT
50 IF A$ = "S" THEN GOSUB *SOFT_DROP
60 IF A$ = "W" THEN GOSUB *ROTATE
70 GOTO 10
AIに言いたいのはただひとつ。
>「INKEY$ は1日1回まで」
🧮 ハルシネーション② READ を“ループの外でまとめて代入”するAI
〜寿司レーン方式を理解していない〜
次は READ 文 の話です。
AIくん、どうやら READ を 「変数に値を入れる謎の呪文」 くらいに思っているようで“進む”という性質を忘れがち です。
❌ AIが書いた誤った例
10 DIM A(5)
20 FOR I = 1 TO 5
30 READ X
40 NEXT I
50 FOR I = 1 TO 5
60 A(I) = X
70 NEXT I
80 END
90 DATA 10,20,30,40,50
AIの脳内イメージはたぶんこうです:
>「とりあえずループで全部READして、最後の値をXに入れておいて…あとで配列にまとめて突っ込めば効率いいでしょ!」
効率どころか 全部同じ値になります。
📘 図解:READ は“進む”命令
DATA 10, 20, 30, 40, 50
READ の進み方
READ → 10
READ → 20
READ → 30
READ → 40
READ → 50
ループ外で A(I)=X を実行すると…
A(1) = 50
A(2) = 50
A(3) = 50
A(4) = 50
A(5) = 50
【結果】
全部同じ値になる
>「10、20、30、40、50と並べたいのに、全部50」
>こうなると、ただの 「50推し配列」 です。
✅ 正しい例
READ は、読んだその場で配列に入れる のがシンプルです。
10 DIM A(5)
20 FOR I = 1 TO 5
30 READ A(I)
40 NEXT I
50 END
60 DATA 10,20,30,40,50
AIにもいつかこう教えたい。
>「READ は回転寿司。後からまとめて取りに戻るんじゃなくて、流れてきたときに取ろう。」
🌀 ハルシネーション③:AIの"惜しい天才ムーブ"
〜分かってる風で分かってないコード〜
READ の話をしていたら、もうひとつ面白い事例を思い出したので紹介したい。
AIに「キー入力の反応を良くしたい」とお願いしたとき、
こんなコードを出してきた。
10 FOR I=0 TO 30
20 A$=INKEY$
30 IF A$<>"" THEN GOTO 50
40 NEXT I
一瞬「おっ?」と思う。
- キー入力だけ高速で回す
- 入力があったら即抜ける
これは “分かってる人の書き方” に見える。
ところが、AIに意図を聞いたらこう返ってきた。
>「動作速度の調整のために30回ループを用意しました」
いやいやいや。
押した瞬間にループ抜けるんだから速度調整になってないよ!
惜しい。
本当に惜しい。
「分かってる風の分かってないコード」というAIの得意技が炸裂した瞬間だった。
🔀 ハルシネーション④ ELSEIF & END IF を勝手に生やすAI
〜ここは令和じゃないんだ、N88-BASICだ〜
AIは普段、Python だの JavaScript だのブロック構文が当たり前の世界 に住んでいます。
そのノリのまま N88-BASIC に来ると平然と ELSEIF と END IF を生やしてきます。
❌ AIが最初に書いた例
10 IF A = 1 THEN
20 PRINT "ONE"
30 ELSEIF A = 2 THEN
40 PRINT "TWO"
50 END IF
AIの脳内:
>「IF の後は改行してインデントして、ELSEIF して、最後は END IF だよね!(どやぁ)」
N88-BASIC:
>「いや、そんなもん無いから。」
📘 図解:AIの思考 → BASICの仕様 → AIの誤解
【AIの内部モデル(現代言語)】
IF 条件 THEN
処理
ELSEIF 条件 THEN
処理
END IF
↓ そのまま BASIC に持ち込むと…
【N88-BASIC(86) の仕様】
・IF は 1 行で書く
・ELSEIF は存在しない
・END IF も存在しない
↓ AIの誤解
【AIの出力】
IF A = 1 THEN
PRINT "ONE"
ELSEIF A = 2 THEN
PRINT "TWO"
END IF
↓ 指摘すると…
【AIの修正】
IF A = 1 THEN PRINT "ONE"
IF A <> 1 THEN IF A = 2 THEN PRINT "TWO"
>「ELSEIF 使うなと言ったら、IF を2回に増やしてきた」
>という、ちょっとした珍プレーです。
✅ 正しい N88-BASIC の1行IF
本命はこれです。
1 行で完結させる N88-BASIC らしい書き方。
10 IF A = 1 THEN PRINT "ONE" ELSE IF A = 2 THEN PRINT "TWO"
>「1ならONE、それ以外で2ならTWO、それ以外は気にしない」
>くらいのライトな用途なら、このくらいがちょうどいい。
N88-BASIC にブロックIFを期待するのはファミコンにレイトレーシングを期待する ようなものなので素直に1行で済ませるのが平和です。
🧠 ここまでのAIの挙動をざっくりまとめると
今回のAIのハルシネーション、どれも共通しているのは:
- 現代言語の癖をそのまま持ち込んでいる
- ブロックIF
- ELSEIF
- END IF など
- レトロBASIC特有の「仕様のクセ」をちゃんと掴めていない
- INKEY$ はバッファを消費する
- READ は呼ぶたびに進む
- でも、それっぽいコードは全力で出してくる
AIは「知らないなら黙る」タイプではなく
「たぶんこうじゃない? ほら、それっぽいでしょ?」と 自信満々に言ってくるタイプ なので、こっちが 「ちょっと待て」 と突っ込んであげる必要があります。
これを「ダメだなAIは」と切り捨てるか、「いや、そのズレ方が面白いんだよ」と眺めるかで付き合い方がかなり変わってきます。
🎯 まとめ:AIとレトロ言語は相性が悪い。でも、それが楽しい
- AIはレトロBASICがあまり得意ではない
- その代わり、かなりいい感じにズレた答えを返してくる
- INKEY$ を2回読んだり
- READ を寿司レーンのラスト皿みたいに扱ったり
- N88-BASIC に ELSEIF を生やしたり
どれも真面目に見ると「間違い」なんですが、観察対象として見るとかなり愛嬌があります。
AIは完璧な先生ではなく「ちょっと天然なペアプロ相手」 くらいに思っておくとちょうどいいかもしれません。
レトロ言語は、AIにとっては異世界転生みたいなもの。
戸惑って当然です。
その戸惑いの過程を、こっちはニヤニヤしながら楽しめます。
あなたもぜひAIに昔の言語をやらせてみて、
「あー、そう来たか」
と、ツッコミながら遊んでみてください。
🔍今回の事例から見えてくる"ありがちな落とし穴"
- 古い言語・古い環境ほど、AIは「知らない部分を推測で補う」傾向が強い
→ つまり、AIの中では“80年代の仕様”が穴だらけ。 - 学習データが少ない分野では、ハルシネーションの発生率が跳ね上がる
→ レトロ技術はまさにその代表格。 - 人間側が「これくらい言わなくても伝わるでしょ」と思っている部分が、AIには全く伝わっていない
→ ここが一番の事故ポイント。


