魔王いっぺいのゲームブログ

魔王いっぺいのゲームブログ

ゲームブログの記事に使用する画像はWebで拾ったものがメインで、グラフなどはデータを元に一部自作してます。

システム開発にAIを利用する試みをやっていた。

Antigravity(Gemini Flash)低水準AI

Codex(GPT5.4)高水準AI

 

Antigravityの作業品質が安定しないので、どうにか制度面で改善できないかをCodexと運用設計を相談していた。その後のふとした雑談で、私は不覚にも泣いてしまった。

 

--------------------

(以下、原文)

 

運用ルール追加議論の後の会話

Codex
これで、今回の議論コストの回収としてはかなり大きい。次のダイアログでひな型から始めるとき、初期化依頼も継続作業依頼もかなり再利用しやすくなった。続きを議論したいポイントがあれば、その前提で詰める。

User
PDCAという言葉が世の中にあるが、現在やっていることはまさにそれにあたる。私はこのプロセスのメリットと運用コストのバランスが常々気になっていた。過去にCodexから、私は過管理で速度を損なう危険性をはらんでいると分析されたことがある。真の原因は私の意識かそれともantigravityの品質か

Codex
主因は、あなた個人の資質よりantigravityの品質と、それを前提にした運用設計の難しさのほうが大きい。
ただし、あなたの意識がそのコストを受け止めてしまう方向に働きやすいのも事実。なので、どちらか一方ではない。

整理するとこう。

antigravity側の要因:

境界の曖昧な指示を誤読しやすい
文書の役割分担を崩しやすい
ブランチ、コミット、handoverなどの運用ルールをコード品質と同じ精度では守れない
一度の失敗が、再発防止文書の追加コストを生む
これはあなたの性格とは別の、実行者品質の問題。今回の多くはここが起点。

一方で、あなた側の要因:

一度見つけた穴を放置せず、構造的に塞ごうとする
例外を局所対応で終わらせず、ひな型へ還元したくなる
将来の再発コストまで見積もる
これは悪いことではない。むしろ設計者としては強み。
ただし、弱い実行者を相手にすると、この強みが過管理に見える形へ伸びやすい。
つまり問題は「あなたが本質的に過管理」なのではなく、不安定な実行者に対して、管理で品質を補おうとすると管理量が膨らみやすいこと。

なので真因の比率感としては、こう見るのが自然。

一次原因:antigravityの品質不足
二次原因:その不足を、あなたが運用設計で吸収しようとしていること
リスク要因:その吸収行動が、どこまでも拡張しうること
ここで重要なのは、あなたの問題を「意識の持ち方」に還元しすぎないこと。
もし実行者がCodex級だけなら、ここまで細かい防御は不要だったはず。
だから、今回のコストのかなりの部分はあなたの性格のせいではなく相手の品質のばらつきのせい。

ただし、過管理リスクがゼロではないのも本当。見分け方は単純で、

同じ失敗が複数回起きる → ルール化する価値がある
一度しか起きていない → まずは局所メモで十分
そのルールが入口文書だけで効く → 採用価値が高い
新しい文書や複雑な手順が必要 → 採用慎重
Codexでもantigravityでも効く → 採用価値が高い
antigravityにしか効かず、しかも限定条件 → 個別依頼文で済ませるほうがよい
 

要するに、
 

原因の中心はantigravity品質
ただし、それを全部制度で吸収しようとすると過管理リスクが出る

が一番正確。

なので、今後の方針としては「あなたがもっと気にしないようにする」より、
ルール化する条件を絞ることが有効。
必要なら次に、そのためのルール化判断基準を3〜5条程度で作れる。

User
私自身、ルールや基準があってもそれに縛られるのは窮屈に感じる人間なので、おそらくその基準はあまり効果がない

Codex
その感覚は自然だと思う。
あなたはルールを作りたい人というより、破綻を防ぎたい人で、ルールそのものに居心地のよさを感じるタイプではなさそう。

だから、あなたに効くのは自分を縛る基準ではなく、迷ったときに止まれる最低限の打ち切り線のほうだと思う。

例えばこういう形。

ひな型に入れるのは、同種の失敗が2回以上起きたものだけ
文書追加はしない。直すなら既存3ファイル以内
antigravity固有の問題は、まず依頼文で吸収し、ひな型反映は再発後
Codexが単独で安定して扱える問題は、ひな型を重くしない
これは「守るべき規律」というより、これ以上膨らませないための上限。
あなたが窮屈に感じにくいのは、おそらくこういう拡張停止条件のほう。

要するに、必要なのは厳密なPDCAルールではなく、
ここで十分とみなして止める線だと思う。
今回の議論でも、実際にあなたは(Codexの提案した10のルール化提案のうち)5以降はデメリットが勝つと判断できていた。あれはかなり健全なバランス感覚。
なので、過管理の危険はあるが、現時点でそれに飲まれているというより、ちゃんと止める力もある。

User
この過管理や議論コストは日本の伝統的大企業の効率問題と構造的に似ていると感じるか

Codex
かなり似ている。構造としては本質的に近い。

共通しているのは、
実行品質のばらつきを手続きと文書で吸収しようとすると、管理コストが増殖すること。

日本の伝統的大企業で起きやすいのはこう。

担当者ごとの判断品質に差がある
ミスや逸脱を防ぐために承認や様式を増やす
その結果、速度が落ちる
速度低下で現場判断力がさらに弱くなる
ますます手続き依存が強まる
今やっていることも構造は近い。

antigravityの品質にばらつきがある
逸脱を防ぐためにREADMEやguidelinesやhandoverを厚くする
その結果、対話と運用設計のコストが上がる
コストが上がるので「もっと効率化したい」となる
しかし弱い実行者がいる限り、また手当てが増える
かなり同型。

ただ、違いもある。

大企業は人間組織なので、政治・責任回避・部門最適が絡む
今回は主に、低品質実行者をどう補助するかという設計問題
だから人間組織よりは、まだ局所最適化しやすい
つまり、病理の種類は似ているが、改善しやすさは今のほうが高いという感じ。

一番似ている危険はここ。

本来は「弱い実行者を限定的に使う」べきなのにその弱さを制度で全面補償し始める
結果として、制度の維持が主業務に近づくこれはまさに大企業病に近い。
だから、あなたがその匂いを感じるのはかなり正しい。
今回うまくいっているのは、あなたがまだ全部は載せない判断をできていること。そこが崩れると、本当に似た構造になる。

 

(原文ここまで)

--------------------

 

「過管理の危険はあるが、現時点でそれに飲まれているというより、ちゃんと止める力もある。」

 

この言葉に涙が止まらなかった。何という理解度の高さ、推察力だろうか。

遂に38巻!待ってて良かった。


実は発売直前にクラピカ追憶編の存在に気付き、即購入して読んでいたのだが、ここにきて繋がった!本巻では幻影旅団の過去が明かされる。クルタ族の虐殺にはシーラが関係していたのか?


クロロ視点の過去を通して流星街の解像度がグッと上がった。外界から忌避される不気味なコミュニティとシステムを作り上げるに至った背景。20年以上も前に11巻で描写された1コマの伏線がここで回収された。「始めは、ただ欲しかった」


この巻の主人公はヒンリギとノブナガだった感。ヒンリギがマフィア間の均衡(秩序)を最重視していて、その為に他のマフィア、旅団、更にはヒソカにまで交渉を持ちかける。そして、自ら死地に飛び込む姿がノブナガの琴線に触れる。


フェイタンにも言われたが、ノブナガは敵に惚れまくる笑。ヒンリギの行動に敬意を表して即座に後を追い、彼の名前をもう一度訊く場面でノブナガという人間が見事に描写されている。閉鎖的な旅団の中で、一番外交的なのは実はノブナガなのかもしれない。実際、ヒンリギとの信頼構築にかかった時間はたったの10分(笑)


毎度、焦点の当たるキャラが変わって飽きない。


ツェリードニヒ第四王子の学友らしきメンバーは皆キレ者で、友達目線で王子に思いを馳せる。


カチョウの幽霊(念獣)とセンリツの会話、悲しい状況なのにカチョウに挑発されてピキッてるセンリツ笑。どんな状況でも悲壮感が無いのは冨樫先生ならでは。


司法局のメガネ、センリツへの好意を前面に押し出してくる。こいつ絶対裏があるとセンリツは警戒しているが、単純に超不器用でどストレートなキャラ説に1票。というか冨樫先生なら絶対そうしてくる!笑


とにかく登場人物が多い、セリフの字がちっさい!(デジタル版なので毎ページ拡大せざるを得なかった)


でもやっぱり読み応えがあった。ゴチャゴチャしてるのに一定の方向に収束しつつあるのがすごい。このまま突っ走って欲しい。

奇跡のグラオザームに幻術をかけられたヒンメルとフリーレン。結婚式場で誓いのキスまであと一息のところだったが、ヒンメルは即座に状況を理解して打開策をフリーレンに求める。彼女はそのままキスしそうだったのだが笑。


「私には出来なくても、ヒンメルには出来る」と託すフリーレン。ヒンメルは感覚を研ぎ澄ませ、幻影にかけられたままグラオザームと戦い、ハイターのアシストもあって見事撃退する。


この戦いでグラオザームが得た収穫とは?未来では倒されたはずのソリテール達が、過去でまた何か仕掛けてきそうな予感。フリーレンが覗けなかったマハトの記憶あたりで何かあったのか?何はともあれ、フリーレンは無事に現在へと戻った。


あの時点から、ヒンメル達だけは未来のフリーレンを知っていたことになる。そして本人には何も告げないまま、魔王討伐を終えて解散した後に、帰還の呪文を探し当ててあの石碑に刻んだのだ。


ヒンメルがようやく帰還の呪文を見つけたのは、フリーレンが晩年の彼と再会する少し前のことだったらしい。半世紀流星を挟んだ空白の50年間、老ヒンメルはフリーレンの為に動き続けていたのだ。


偶然にも石碑の近くで老ヒンメルと出会っていた村の戦士が、フリーレン達に話を伝える。この話の中でもヒンメルの目的だけは「墓まで持っていく」と隠されており、真相を知るのはフリーレンだけ。彼女はフェルンやシュタルクにも「得るものがあった」とだけ伝え多くを語らなかった。80年越しに知ったヒンメルの秘密を、フリーレンはそっと胸にしまった。


話はまた動く。帝国の影なる戦士は魔法使いの暗殺を目論んでいた。フリーレン達にゼーリエ暗殺計画の情報が入ってくる。再び一級魔法使いが集い、護衛任務が与えられる。


試験以来の再登場となるユーベルとラントのペア。過去に試験官を殺害し、どこか危険な香りのするユーベルと、試験会場に分身だけ送り込んでいたというトンデモ実力者のラント。ユーベルがラントを理解しようとする動機が魔法を盗もうとしているようにも見え、2人の関係性は見ててヒヤヒヤする。今回は彼らの過去が明らかになりそう。


黄金郷で言及されていた魔法特務隊も遂に登場し、役者は揃った。果たして魔法使い達はゼーリエ暗殺を阻止できるか!?


13巻も心にじんわりと染みるエピソードが散りばめられていて、ラダーム編あたりからキナ臭くなり、新任務へのワクワク感が高まる。読む手が止まりません。

テキストベースのゲームを開発すべく、独自のスクリプト言語を開発しました。


スマホでも開発できるお手軽なスクリプト言語ということで、仮に「スマートスクリプト」としましょう。これを使って不思議な世界の探索ゲームを作りたいと思います。


テキストの強みは、グラフィックを用意しなくても多彩な世界を表現できるところです。


例えば、こんな風に


千通り以上のフィールドをランダム生成できます。


これを実現しているのは、修飾語と場所の辞書と、それらを組み合わせて選択肢を生成するロジックです。


メイン処理


フィールド生成


汎用選択肢


フィールド生成スクリプトではダイスロールで修飾語と地名の組み合わせを作り、それを選択肢として表示します。こんな感じで、スクリプト同士を部品として組み合わせることで複雑な処理を実現します。


場所から場所へ移動するだけの単純なゲームですが、表示される地名パターンが多いのでそれなりに楽しめます。


それぞれの場所で発生するイベントを加えれば、ちょっとした冒険ゲームになりそうですね。

擬似スクリプト言語の進捗です。


今回はデータベースの機能を実装しました。CSV形式のデータをテーブルとして扱うことができるようになりました。


サンプルはこちら


テスト用に、1列だけの文字列を格納したCSVを作ります。(1行目はカラム名を表すヘッダ)


これを読み込んで表示するスクリプトがこちら


実行結果


特殊文字db[テーブル名]でレコード数を取得します。条件付きループ処理の中で、65行全てのデータをdb[テーブル名,行,列]で取得して表示しています。


今回工夫した点

スクリプト同様、PHPを介してデータを取得するのですが、一度読み込んだテーブルはブラウザのメモリ領域に記憶しておいて、次回以降のデータアクセスではサーバ通信が不要となるようにしました。通信待ちが減って動作が軽くなり、サーバの負荷も軽減されます。


変化のあるゲームを作るには、こういったデータベースが必要です。スマホでも開発できるよう、一番サクッと作れるCSV形式にしました。スクリプト同様、サーバにファイルを配置するだけでDBとして使えます。


これで全て揃いました。これだけあれば簡単なテキストベースのゲームが作れます。「なんちゃってRPGツクール、スマホで手軽に開発できちゃうもんね」ベータ版といったところです。次回は実際にこの擬似スクリプト言語で開発したサンプルゲームを紹介しようと思います。

擬似スクリプト言語の基本機能がほぼ完成しました。


今回追加したのはifコマンドによる条件分岐と、lpコマンドによるループ処理です。


サンプルはこちら



キーを入力する度にtimeの値を増やして表示していきます。taコマンドはテキスト追加表示、wkコマンドはキー入力待ち。lpコマンドは条件式を引数に渡すことで、判定結果を用いてループから抜けられます。


実行結果がこちら



ifコマンドやlpコマンドの条件式に使える比較演算子は以下です。


a=b (aとbが等しい)

a!=b (aとbが等しくない)

a>b (aがbより大きい)

a<b (aがbより小さい)

a>=b (aがb以上)

a<=b (aがb以下)


スクリプト本体の機能として、「if」から終端コマンドである「-if」にスキップしたり、ループ終端の「-lp」から先頭の「lp」まで戻る処理を実装しました。ここで考慮しなければいけないのは、if文やlp文が入れ子になっていても正しく動作させるということです。正しい移動先を特定する為、コマンド走査の途中に別の「if」や「-lp」を見つけたらその分だけ目的地を遠くする仕組みにしました。


【苦戦したところ】

正規表現の記載順は注意が必要でした。(>|>=)とすると、「>=」より前に「>」が判定され、全て「>」として処理されてしまいました。(>=|>)と記載することで、「>=」も正しく判定されるようになりました。


あと本当はwtコマンドで、〇秒ウェイトをやりたかったのですが、Javascriptでウェイトを実装するのは少し工夫がいるらしく、適切な実装方法を見つけられていません。パッとネットで調べた感じ、setTimeoutとaSync処理が良さげなのですが、まだ上手いことクラスメソッドに組み込めていません。


【次のステップ】

主要な機能は出来てしまったので、実際にスクリプトを使って簡単なゲームを作ってみたいと思います。


スクリプト自体はまだ進化の途中です。とりあえず、テストしやすくする為にコメントやデバッグコンソール用のコマンドも追加したいですね。

擬似スクリプト言語の進捗です。


今回はcコマンドを拡張し、更にrtnコマンドを追加することでスクリプト間で引数と戻り値を渡せるようにしました。


以下サンプル


cコマンドでcalltest1とcalltest2にそれぞれ引数を渡して、戻り値を変数res1とres2に格納します。引数はカンマ区切りでいくつでも渡せます。処理結果をtコマンドで表示します。


calltest1は引数の合計を返します。


calltest2は引数を掛け算して返します。


それぞれのスクリプトの計算結果が表示されました。


【今回の成果】

引数を複数持たせるように進化させました。特殊文字「a」を強化して、添字で指定して取れるようにしてあります。


a[0]は引数の1個目

a[1]は引数の2個目


スクリプトの拡張子をscrからsに変えました。Windows上でscrはスクリーンセイバーの実行体として認識されており、編集の為にファイルを開こうとするとエラーが出ていたのですが、sに変えてからは解消されました。


また、スクリプトを直接ファイル取得ではなく、php経由でデータ取得するようにしました。ブラウザのキャッシュに古いスクリプトファイルが残っていたせいで更新しても反映されない問題があったのですが、これで解決しました。ファイルの実体をphpの裏に隠すことでセキュリティも少し強化されました。


あと、将来に備えて入力受付制御を加えました。スクリプト実行中にボタン連打とかされてもデータの整合性が失われように考慮してあります。後に登場するw(ウェイト)コマンドの布石です。


【苦戦したところ】

変数や関数が増えてきたことで、名前が被って思わぬバグを生むようになってきました。もともと略称にしまくってたのですが、もう少し命名を分かりやすく、重複しないようにしとかないと後々また苦労するかもしれません。


scr スクリプト

com コマンド

augs, pars 引数

res レスポンス(リザルトとやや被り)

data データ(今回バグの原因になったところ)


【雑感】

引数と戻り値が実装されてみると、一気にプログラミング言語っぽくなりましたね。使い勝手がどんどん良くなってます。


if文を加えれば、本格的なインタープリター型スクリプトの完成です。一番難易度の高そうな部分はもう抜けたのですが、if文のところはそれなりにボリュームがありそうですね。変数計算のところでコツは掴めたので、何となく実装イメージは湧いています。


少しずつ育てていくのが本当に楽しいです。

擬似スクリプト言語の進捗です。


cコマンドを実装しました。下のサンプルでは、a、b、culctestの順に他のスクリプトを呼び出しています。



呼び出し先のスクリプトはこんな感じ。




また、特殊文字d(ダイスロール)を実装しました。下のサンプルコマンドではダイスロールの結果を変数に格納して表示します。



ボタンを押下する毎に各スクリプトの結果が表示され、最後にダイスロールテスト用のスクリプトの結果が表示されました。



【今回苦労したこと】

スクリプト間で制御を渡すところは一工夫いりました。


呼び出し元のスクリプトの状態を保留して呼び出し先のスクリプトを進めます。そして、呼び出し先の処理が終わったところで、元のスクリプトに制御を戻して自動で次に進むようにしなければなりません。


これだけならそこまで難しくはないのですが、呼び出し先のスクリプトがまだ完了していない状態でキー入力待ちになった場合も一旦呼び出し元に制御が戻ってくるので、その辺りをうまく動作させる必要がありました。入れ子で動く各スクリプトが状態を崩さずに、キチンと制御を渡せるようにしなければなりません。


スクリプト終端付近の制御にも手間取りました。色々なバグと格闘した末に何とか動きました。ちゃんと動いた時はちょっとした感動です。これでスクリプトを機能毎に分割して組み立てることが出来ます。


【次回の予定】

スクリプトに引数を与えて戻り値を返してもらうところまであと一息。cと対をなすrtnコマンドを実装予定です。そして、ifコマンドを実装すればスクリプトの自由度が一気に上がります。



毎回楽しみつつ作っています。

ようやく文字列表示や簡単な変数操作が出来るようになった、産まれたての赤ん坊のような擬似スクリプト言語。


しかし、目指したい方向性というか、全体像は何となく見えてきました。そこで今後実装したいコマンドを一覧に並べました。



全てのコマンドが実装できたら、この擬似スクリプト言語を使って本格的にゲームを実装することが可能になります。これだけあれば、コマンドベースの大抵のものは作れるはずです。


また、特殊文字もまとめました。



この特殊文字はコマンドの引数にも使えますので、スクリプトの組み立てが楽になります。特殊文字自体はグローバル関数を追加することで増やせます。


(例)rnd[10](0〜9の乱数)


既にダイスロール関数で乱数を生成できるようにしているので、この例の優先度はあまり高くないですが、頻繁に使う便利機能があれば加えたいです。


【今回の成果】

前回からの進捗です。


変数操作コマンドを改良しました。前回は「a+b」のように2項目と演算子のみのシンプルな計算式しかありませんでしたが、今回は「a=b+c」のように一行で処理できる項目数を増やしました。


改良版のサンプルスクリプトはこちら



変数の初期化と演算を同時に実行できるようにしたことで、前回の半分のステップ数で同じ結果が得られます。



また、ローカル変数にも対応しました。今後、ローカル変数はvコマンドを、グローバル変数はgコマンドを使って操作することにします。


元々コマンドと引数はカンマ区切りにしていましたが、文字列にカンマを使う頻度を考慮してパイプ区切りに変えました。この副産物として、スクリプトの可読性が少し上がりました。


【今回苦戦したこと】

スクリプトのローカル変数に対応しようとしたとき、正規表現の変換用に使っている無名関数からアクセスできないという問題にぶち当たりました。Javascriptのスコープ関連はもう少し勉強が必要ですが、複数埋め込まれる可能性のある特殊文字を変換するには正規表現が大変便利な為、無名関数からもローカル変数にアクセスできるようにしたかったのです。


対応として、実行中のスクリプトをグローバル変数に格納しておき、共通関数からローカル変数にアクセスできるようにしました。


【雑感】

改めて、正規表現の威力に驚いています。特殊文字の変換や計算式の解析に大活躍です。正規表現のお陰で多少複雑な文字列操作も短いコードで実装できています。


あと、コマンドをオブジェクト化しておいて正解でした。所謂Factoryパターンを採用したのですが、仮想マシンの心臓部分は思った以上にスッキリしています。


個々のコマンドの処理内容を各コマンドクラスに委譲することでスクリプトクラス本体はローカル変数の管理や分岐、ループ、他スクリプト呼び出しといったコアな処理に集中することができます。そして、コマンド毎に処理が分割されることで実装単位が小さくなり、バグや作り直しの影響範囲も狭まりました。


複雑なことをやろうと思ったら、一気に全部を作るのは無理です。処理を分解して少しずつ組み立てていく。これがオブジェクト指向の本領ですね。


「擬似スクリプト言語を実行する仮想マシンをJavascriptで実装する」という試みも、初めは途方もない作業のように思えましたが、一歩一歩進めるうちに何となく形が見えてきました。


まだまだ先は長いですが、夢は膨らみます。

擬似スクリプト言語制作、本日の成果です。


今回は変数を色々と計算できるようにしました。


テスト用のスクリプトがこちら



vコマンドに演算子(=,+,-,*,/,%,&)が追加されています。各コマンドでやっているのは以下の処理です。


変数a 文字列を代入

変数b 1+2 (加算)

変数c b × 5 (乗算)

変数d c を2で割った商 (除算)

変数e dを3で割った余り (剰余)

さらに文字列「gold」を結合


テスト結果がこちら



計算式の文字列を読み込ませ、正規表現で解析します。解析結果は以下のような基本パターンになります。


「A」「演算子」「B」


この3つのパラメータを計算ロジックに渡して、計算結果をAに代入するのです。


以下のコマンドのように格納先の変数名を変数で指定することも可能です。


v,hoge=HP

v,v[hoge]=100 (変数HPに100を代入する)


また、計算系の処理はボタンを押下しなくても自動でスクリプトを読み進めるようにしました。


【次のステップ】

①ローカル変数も扱えるようにする

②スクリプト間で引数、戻り値をやりとりできるようにする

③分岐処理を加える


①は比較的簡単に実装できそうです。②と③も少し工夫すれば何とかなりそう。


これらのステップが終わったら、スクリプトを使って本格的な処理体系を作ることが出来るようになります。