Skip to content

[DO NOT MERGE] 検証用: 甲子園 全機能結合 (#741+#744)#747

Draft
takaokouji wants to merge 23 commits into
developfrom
check/koshien-all-20260613
Draft

[DO NOT MERGE] 検証用: 甲子園 全機能結合 (#741+#744)#747
takaokouji wants to merge 23 commits into
developfrom
check/koshien-all-20260613

Conversation

@takaokouji

Copy link
Copy Markdown

⚠️ 検証専用・マージ禁止(DO NOT MERGE)

#741(#746) + #743(#744) を結合した敵対的チェック用ブランチです。v2対応 + 固定値 + RemoteClient + 接続設定モーダルを1つのプレビューでまとめて確認するためのものです。実マージは個別 PR (#742/#744/#745/#741) で行います。

takaokouji and others added 11 commits June 13, 2026 03:22
甲子園拡張機能のブロックがクリック/実行時に意味のある値を返すようにした。
KoshienClient をインターフェース化し、未接続時用の固定値クライアント
MockClient を実装してブロックメソッドを接続した(将来の RemoteClient と
差し替え可能な構造)。

- map=0(空間), mapAll=15x15 全空間文字列, mapFrom=マップ文字列をパース
- targetCoordinate: player=1:1 / goal=13:13 / other_player=enemy=7:7
- calcRoute/calcGoalRoute/locateObjects は指定リスト変数へ実際に書き込む
- getMapArea/moveTo/setItem/turnOver/setMessage は安全な no-op

Refs #739

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
甲子園拡張機能の calc_route / calc_goal_route / locate_objects は、リスト引数を
バージョン非依存で list("$名前") とハードコードしており、Ruby v2 では
「list() syntax is only available in Ruby version 1」エラーになっていた。

v2 ではリストはグローバル配列変数 $名前 で表現するため:
- generator: version === '2' のとき list("$名前") ではなく $名前 を出力
- converter: v2 では引数の配列変数 ($名前 = data_variable) を convertToListBlock で
  リスト化して受理 (v1 の list() ブロックと同じリスト名に解決)

v1 の挙動は不変 (既存 roundtrip テスト緑)。v2 roundtrip テストを追加。

Refs #743

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…al server

過去にゲームサーバー再実装が「仕様不明確」で頓挫した反省を踏まえ、実ゲームサーバーの
挙動をゴールデン JSON として記録し、クライアントが従うべき契約をテストで固定する基盤を
追加する (#740)。

- tmp/smalruby-koshien/game_server (Ruby 3.1) の in-process API ドライバ
  (SpecHelper::Server) を流用した記録ドライバで、決定的シナリオ (SK_RANDOM_SEED=1) を
  実行し各 API の返り値を fixture 化:
  - move_basic: move_to は予約で、座標は turnTransition 後に確定 (before [1,1] → after [2,1])
  - get_map_area: getMapArea は 15x15 の自分マップ (未探索 -1) + enemy + other_player を返す
  - two_actions: 1 ターン 2 行動 (move + getMapArea)
- test/unit/extensions/koshien_golden_contract.js (tap): 上記の実挙動を検証し、
  将来の RemoteClient (#741) が replay できる契約の基盤とする。
- 記録ドライバ/サーバー起動手順は notes/koshien に整備 (git 管理外)。

Refs #740 / Epic #738

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…th mock fallback

甲子園拡張機能が、設定された実ゲームサーバーと通信して実際にゲームを進められるよう
にする (#741)。未接続時は固定値の MockClient にフォールバックするため、サーバーに
つながなくても AI を作成できる。

- remote-client.js: ai_lib.rb の HTTP プロトコルを JS へ移植した RemoteClient。
  - 非同期: connectGame / getMapArea / moveTo / setDynamite / setBomb /
    setMessage / turnOver。返り値で my_map / x / y / goal / enemy / other_player を更新。
  - 同期レポーター: map / mapAll / mapFrom / targetCoordinate はキャッシュ状態を読む
    (ai_lib と同じく get_map_area が my_map を埋め、map(...) がそれを参照)。
  - calc_route はダイクストラ (壁=通行不可、水=重い、未探索=さらに重い) を移植。
    locate_objects は my_map 走査。
- index.js: runtime.getKoshienRemoteOptions() が endpoint を返せば RemoteClient、
  なければ MockClient を使う (オフラインで AI 作成可能)。
- テスト: #740 のゴールデン fixture (実サーバー応答) を注入 fetch で流し込み、
  RemoteClient が実応答を正しく解釈することを検証 (契約テスト)。バックエンド選択も検証。

ベース: #739 (MockClient) + #740 (ゴールデン) の上に構築。#741 は最後にマージ予定。

Refs #741 / Epic #738

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
v2 では甲子園プログラムをクラス表現 (class < Smalruby3::Sprite) の中に置くため、
ゲーム接続をフラットな文ではなく「ブロックを取るイベント hat」で表現する。

- generator: koshien_connectGame は v2 で
  `koshien.when_connect_game(name:) do ... end` を生成し、AI 本体を do...end の
  サブスタックに包む (block.isStatement=true → scrub_ が next 連鎖を字下げ + end)。
  v1 は従来どおりフラット `koshien.connect_game(name:)`。
- converter:
  - `koshien.when_connect_game(name:) do ... end` (v2) を hat + サブスタックとして解析。
  - フラット `koshien.connect_game(name:)` は v1 で statement、v2 ではエラー
    (when_connect_game を使うよう促す)。
- v2 roundtrip テスト (when_connect_game + リスト$配列) / v2 フラットエラー /
  v1 フラット維持 を追加。

ブロック opcode/構造は不変のため、既存 sb3 プロジェクトはそのまま読み込める。

Refs #743

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…llback

接続できれば実サーバー、できなければ Mock 値、という #741 の中核挙動を実装。

- コンストラクタ: MockClient を常に保持し、endpoint 設定時のみ RemoteClient を併設。
  起動時は RemoteClient (あれば) を使う。
- connectGame: remote のときは実サーバーへ非同期接続し、失敗 (到達不可/CORS/エラー)
  したら MockClient へフォールバック (つながなくても AI が動く)。mock のときは従来どおり同期接続。
- getMapArea / setItem / turnOver が client の結果 (remote では Promise) を返すように
  変更し、シーケンサが await して順序を保てるようにした。
- テスト: 接続成功で RemoteClient 維持 + 実座標、接続失敗で MockClient へフォールバック +
  固定値。tap 全 110 assert pass。

Refs #741

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
接続先は「プログラム」ではなく「Smalruby の設定」で行う方針 (#741) の土台。
接続設定 (接続先URL / プレイヤー側 / ゲームコード) を localStorage に保存し、
VM 拡張が読む contract `vm.runtime.getKoshienRemoteOptions()` を供給する。

- src/lib/koshien-connection.js:
  - load/saveKoshienConnection: localStorage 永続化 (side は 1/2 に正規化)。
  - buildKoshienRemoteOptions: endpoint 未設定なら null (= Mock)、設定時は
    {endpoint, side, gameCode, playerId(自動生成・安定)} を返す。
  - wireKoshienRemoteOptions(vm): runtime に getter を差し込む (拡張が読む)。
  - testKoshienConnection(endpoint): 設定モーダルの「接続テスト」用の到達性確認。
- 単体テスト (jest, 5 件) pass。

後続 (本 PR or 別 PR): 甲子園メニューに「接続設定」項目 + 設定モーダル UI
(URL/側/コード/テストボタン) + wireKoshienRemoteOptions の起動時呼び出し。

Refs #741

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
接続先を「Smalruby の設定」で行う方針 (#741) の UI を実装。甲子園拡張機能を有効にすると
表示される甲子園メニューに「接続設定」項目を追加し、設定モーダルで接続先 URL / プレイヤー側
(1/2) / ゲームコードを設定する。

- src/components/koshien-settings-modal/: 設定モーダル (URL/側/コード + 接続テストボタン)。
  保存で localStorage 永続化 + wireKoshienRemoteOptions(vm) を再実行。本文に不透明背景
  (modals ルール準拠)。
- reducers/modals.js: koshienSettingsModal の open/close を追加。
- menu-bar.jsx: 甲子園メニューに「接続設定」項目 + ハンドラ + Redux 接続。
- components/gui.jsx, containers/gui.jsx: モーダルのマウントと state/dispatch マッピング。
- vm-manager-hoc.jsx: VM 初期化時に wireKoshienRemoteOptions(vm) を呼び、起動時から
  保存済み設定を拡張が読めるようにする (Smalruby マーカー付き)。
- locales (ja/ja-Hira/en) + prettier ホワイトリスト + マーカー一覧を更新。
- 単体テスト: モーダルのフィールド描画 + 保存で localStorage 永続化 + runtime getter 設置。

注: 設定変更は次回の拡張機能ロード (リロード) 時に反映される (拡張は構築時に一度読む)。

Refs #741

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…oteClient HTTP test

test:unit は `tap ./test/unit/*.js`(再帰なし)のため、test/unit/extensions/ 配下の
koshien テストは CI で実行されていなかった。mesh と同じく top-level へ移動して確実に走らせる。

- test/unit/extensions/koshien_{golden_contract,remote_client}.js を test/unit/ へ移動
  (require パス修正)。
- RemoteClient の実 HTTP 経路を検証する統合テストを追加:
  - test/fixtures/koshien/mock-server.js: CORS 付き Koshien API モックサーバー
    (canned 応答, CLI 起動可: `npm run koshien:mock-server [port]`)。
  - test/unit/koshien_remote_client_http.js: in-process モックサーバーに対して
    RemoteClient を実 fetch で駆動(connect/getMapArea/move/turnOver)。
- prettier ホワイトリスト / マーカー一覧 / package.json スクリプトを更新。
- 全 koshien vm テスト 89 assert pass、lint 緑。

Refs #741

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

takaokouji and others added 12 commits June 14, 2026 01:44
…on loaded

甲子園拡張機能を v2 対応にしたため、「koshien 有効時は Ruby バージョンを変更できない」
という guard / アラートは不要になった。settings-menu と mobile-drawer の両方から削除し、
未使用になったメッセージ koshienCannotChangeRubyVersion とロケール(ja/ja-Hira/en)も除去。

v1↔v2 切替時の「v2機能(class/module)使用中は v1 に戻せない」guard は維持。

Refs #743

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ll-20260613

# Conflicts:
#	packages/scratch-gui/src/locales/en.js
#	packages/scratch-gui/src/locales/ja-Hira.js
#	packages/scratch-gui/src/locales/ja.js
…en blocks

When not connected to a real game server the koshien blocks previously
returned flat placeholders (all-zero map, [src,dst] route, fixed [7:7]).
During the first explanation a user is almost always disconnected, so
clicking a block gave no sense of what it really returns.

Now the mock derives every value from a single source of truth — a fixed,
believable 15x15 sample map (MOCK_MAP) with walls, water, a goal and
scattered items — via new pure helpers in map-utils.js (shared-ready so the
remote client can adopt the same Dijkstra/scan logic):

- map / map_all / map_from -> real cell codes from the sample map
- calc_goal_route / calc_route -> actual shortest path (multi-waypoint),
  honoring the EXCEPT_CELLS list
- locate_objects -> the items really present within range
- target_coordinate -> positions consistent with the map

Phase 2 (pseudo state): move_to moves the mock player, set_item marks the
map, turn_over advances a counter, so repeated runs feel alive.

Reset timing: the mock world resets to its initial state on green flag
(PROJECT_START), on stop (PROJECT_STOP_ALL), and when connect_game runs —
the natural "new game" moments, so a demo can be replayed cleanly.

Tests: rewrote extension_koshien.js expectations for the believable values
and added koshien_map_utils.js for the pure helpers (146 assertions, lint
clean).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…en-all-20260613

# Conflicts:
#	packages/scratch-vm/.prettierignore
#	packages/scratch-vm/src/extensions/koshien/index.js
#	packages/scratch-vm/test/unit/extension_koshien.js
The mock sample map was a hand-made 15x15 grid. The real Smalruby Koshien
field is 17x17 surrounded by an unbreakable wall border (verified against the
2024 default map "map_01": top/left edge = code 2, bottom/right edge = code 1;
breakable walls are 5).

- MOCK_MAP is now map_01 with its item layer merged into letters (a-e/A-D),
  exactly how the real server encodes my_map (ITEM_MARKS). Player starts (5,1)
  and (10,1), goal '3' at (8,9), enemy guards the goal.
- map-utils.locateObjects: sq_size is the full square side, not a radius
  (real game uses radius = (sq_size-1)/2); fixed an over-wide scan window.

Tests updated to the real map values + a new assertion that the whole field
is bordered by unbreakable walls.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The mock sample map was a hand-made 15x15 grid. The real Smalruby Koshien
field is 17x17 surrounded by an unbreakable wall border (verified against the
2024 default map "map_01": top/left edge = code 2, bottom/right edge = code 1;
breakable walls are 5).

- MOCK_MAP is now map_01 with its item layer merged into letters (a-e/A-D),
  exactly how the real server encodes my_map (ITEM_MARKS). Player starts (5,1)
  and (10,1), goal '3' at (8,9), enemy guards the goal.
- map-utils.locateObjects: sq_size is the full square side, not a radius
  (real game uses radius = (sq_size-1)/2); fixed an over-wide scan window.

Tests updated to the real map values + a new assertion that the whole field
is bordered by unbreakable walls.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Selecting the Koshien extension while in Ruby v2 popped an alert
("only available for Ruby v1") and refused to load it. Now that koshien
supports v2 (class representation + when_connect_game), this guard is
obsolete. Removed the rubyVersion check, its message, the unused
rubyVersion prop/mapStateToProps, and the locale strings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The mock now mirrors the real game's exploration: the player's "my map"
starts fully unexplored (all -1) and is revealed 5x5 at a time by
get_map_area. map / map_all / calc_route / locate_objects all work off this
gradually-revealed my map, so locate_objects finds nothing until the area is
explored and calc_route plans through fog (unexplored = passable). moveTo
passability is checked against the ground-truth map, and set_item marks the
ground truth (visible once that cell is revealed). Reset clears the my map
back to fully unexplored.

map-utils gains createUnexploredGrid + revealArea (clamped window, matching
the server's getMapArea range). Tests reworked to the explore-then-read flow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…en-all-20260613

# Conflicts:
#	packages/scratch-vm/test/unit/extension_koshien.js
#	packages/scratch-vm/test/unit/koshien_map_utils.js
…Blockly

Extension hat blocks (koshien connect_game, micro:bit / face-sensing / boost /
ev3 "when ..." blocks, etc.) rendered with a flat top instead of the cap-hat
shape. In modern Blockly (scratch-blocks v2) the cap hat is only drawn when a
block carries the `shape_hat` extension (which sets block.hat = 'cap'); a
missing previousConnection alone is no longer enough because ADD_START_HATS
defaults to false. The built-in event blocks declare
extensions: ['colours_event', 'shape_hat'], so _convertBlockForScratchBlocks
now adds 'shape_hat' to extension HAT/EVENT blocks the same way.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ned)

Same fix as on feature/issue-743: switching to Ruby v2 with koshien loaded
is now allowed, so the stale "shows alert / blocks the change" assertion is
replaced. Makes the integration branch (#747) unit-test-gui green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant