Skip to content

Web移植: コア抽出からAI/ENDルール修正までの全実装 - #4

Merged
yf-1229 merged 1 commit into
masterfrom
nightly
Aug 1, 2026
Merged

yf-1229 merged 1 commit into
masterfrom
nightly

Conversation

@yf-1229

@yf-1229 yf-1229 commented Aug 1, 2026

Copy link
Copy Markdown
Owner

コア抽出(core/) - Pico/Web共通ロジック

  • core/coBroc_core.h/cpp: 全型・定数・ゲームロジック(合法判定/VM/AI採点)
  • core/model.h: YDFラッパー(main.hから移設、Pico非依存)
  • core/wasm_api.h/cpp: Web用C ABI(スナップショットJSON v1/base64シリアライズ)
  • core/test/core_test.cpp: ホスト決定論テスト(5シナリオ、FNV-1aハッシュ)
  • core/abi_test.cpp: ABI検証テスト
  • RNG: グローバル乱数→ProgramState.rng_seedに状態化。剰余法でクロスプラットフォーム決定論を保証
  • AI予測: g_predictor_fn関数ポインタでPico(core1バッチ)/WASM(同期)を切替

Web版(web/)

  • WASMビルド(web/CMakeLists.txt): Emscripten 3.1.69, MODULARIZE+CoBrocModule
  • フロントエンド: Vite+TypeScript、Canvasフローチャート描画、操作UI
  • セーブ/ロード(localStorage)、リプレイ(操作ログの決定的再生)
  • E2Eテスト(web/e2e/): ヘッドレスChrome 15項目
  • GitHub Pagesデプロイ(.github/workflows/web.yml)
  • 契約書(web/API_CONTRACT.md): C ABI/JSONスキーマ/シリアライズ形式

主な修正

  • main.cpp/main.h: コア参照にリファクタ。Pico依存(LVGL/赤外線)のみ保持
  • Pico Debug/Releaseビルド維持
  • パリティ検証: ネイティブ/WASMで全5シナリオ一致 (3BF544D8/F43A33F6/E01971F1/045744D7/8A0B3A3C)

AIのEND全面禁止(TODO-Web07)

  • buildCandidatesでBlockType::Endをスキップ(AIは候補から完全除外)
  • performAITurnのEND抑制ブロックを削除。AI起因のゲーム終了は盤面満杯のみ
  • プレイヤー側の完成判定: ENDで閉じてdepth==0の場合のみ色選択へ
  • モック(mock.ts)もAI_PLAYABLEからENDを除外

## コア抽出(core/) - Pico/Web共通ロジック
- core/coBroc_core.h/cpp: 全型・定数・ゲームロジック(合法判定/VM/AI採点)
- core/model.h: YDFラッパー(main.hから移設、Pico非依存)
- core/wasm_api.h/cpp: Web用C ABI(スナップショットJSON v1/base64シリアライズ)
- core/test/core_test.cpp: ホスト決定論テスト(5シナリオ、FNV-1aハッシュ)
- core/abi_test.cpp: ABI検証テスト
- RNG: グローバル乱数→ProgramState.rng_seedに状態化。剰余法でクロスプラットフォーム決定論を保証
- AI予測: g_predictor_fn関数ポインタでPico(core1バッチ)/WASM(同期)を切替

## Web版(web/)
- WASMビルド(web/CMakeLists.txt): Emscripten 3.1.69, MODULARIZE+CoBrocModule
- フロントエンド: Vite+TypeScript、Canvasフローチャート描画、操作UI
- セーブ/ロード(localStorage)、リプレイ(操作ログの決定的再生)
- E2Eテスト(web/e2e/): ヘッドレスChrome 15項目
- GitHub Pagesデプロイ(.github/workflows/web.yml)
- 契約書(web/API_CONTRACT.md): C ABI/JSONスキーマ/シリアライズ形式

## 主な修正
- main.cpp/main.h: コア参照にリファクタ。Pico依存(LVGL/赤外線)のみ保持
- Pico Debug/Releaseビルド維持
- パリティ検証: ネイティブ/WASMで全5シナリオ一致
  (3BF544D8/F43A33F6/E01971F1/045744D7/8A0B3A3C)

## AIのEND全面禁止(TODO-Web07)
- buildCandidatesでBlockType::Endをスキップ(AIは候補から完全除外)
- performAITurnのEND抑制ブロックを削除。AI起因のゲーム終了は盤面満杯のみ
- プレイヤー側の完成判定: ENDで閉じてdepth==0の場合のみ色選択へ
- モック(mock.ts)もAI_PLAYABLEからENDを除外
Copilot AI review requested due to automatic review settings August 1, 2026 02:03
@yf-1229
yf-1229 merged commit fa637c2 into master Aug 1, 2026
1 of 2 checks passed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Pico版で動いていた coBroc のゲームロジックを core/ に抽出し、同一ロジックを Emscripten/WASM 経由で Web フロントエンド(Vite+TS+Canvas)から利用できるようにする移植PRです。あわせて AI の END 設置を全面禁止し、ネイティブ/WASM の決定論パリティ検証・E2E・Pages デプロイまでを揃えています。

Changes:

  • core/ にゲームロジック・AI・VM・決定論テストを集約し、Pico側はハード/表示・予測ワーカー等の依存部に整理
  • core/wasm_api.* と web/CMakeLists.txt で Web 向け C ABI + JSON snapshot + base64 serialize/deserialize を実装
  • web/ に UI/ローダー/モック/セーブ/リプレイ/E2E を追加し、GitHub Pages へデプロイする workflow を追加

Reviewed changes

Copilot reviewed 27 out of 30 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
web/vite.config.ts Vite ビルド/開発サーバ設定を追加
web/tsconfig.json Web 向け TypeScript 設定を追加
web/src/wasm/types.ts Snapshot/ABI/Replay の型と表示用定数を定義
web/src/wasm/mock.ts 実WASM不在時の契約準拠モックコアを実装
web/src/wasm/loader.ts WASM(実)優先・失敗時モックのローダー/ラッパーを実装
web/src/ui/render.ts Canvas 2D によるフローチャート/色選択/結果描画を実装
web/src/storage.ts localStorage オートセーブと JSON export/import を実装
web/src/replay.ts seed+操作ログによる決定的リプレイを実装
web/src/main.ts Web版メインループ/入力/ターン遷移/オートAIを実装
web/package.json Web ビルド/wasm/e2e スクリプトと依存を追加
web/index.html Web UI の DOM/スタイル/エントリポイントを追加
web/e2e/run_e2e.mjs dist 配信 + puppeteer 実行の E2E ランナーを追加
web/e2e/e2e_test.mjs ヘッドレスChromeで実ゲームフローを検証する E2E を追加
web/CMakeLists.txt Emscripten ビルド(コア+ABI)の CMake を追加
web/API_CONTRACT.md WASM/フロント並行開発向けの凍結契約(ABI/JSON/保存/リプレイ)を追加
plan.md WEB移植計画/検証内容/TODO を追記
main.h Pico側ヘッダを core 参照に整理
main.cpp Pico側を core 利用 + 予測ワーカー/ハードUI中心に整理し、完成判定/決定論対応を反映
core/wasm_api.h Web向け C ABI の公開ヘッダを追加
core/wasm_api.cpp C ABI 実装、snapshot JSON、base64 serialize/deserialize を追加
core/test/core_test.cpp ホスト決定論テスト(複数シナリオ+FNV-1a)を追加
core/model.h YDF ラッパーを core に移設
core/coBroc_core.h コアの型/定数/宣言を追加
core/coBroc_core.cpp コアロジック本体(AI/VM/決定論RNG等)を追加
core/abi_test.cpp C ABI のスモーク/ラウンドトリップ検証テストを追加
CMakeLists.txt ルートの Pico ビルドに core ソース/ヘッダを追加
.gitignore web のビルド成果物/WASM生成物等を追加で無視
.github/workflows/web.yml Emscripten+Vite でビルドして Pages にデプロイする workflow を追加
Files not reviewed (1)
  • web/package-lock.json: Generated file
Suppressed comments (1)

web/src/wasm/loader.ts:69

  • toCString allocates str.length + 1, which is not the UTF-8 byte size. Use lengthBytesUTF8(str) + 1 to size the buffer correctly before calling stringToUTF8.
function toCString(mod: EmscriptenModule, str: string): number {
  const buf = mod._malloc(str.length + 1);
  mod.stringToUTF8(str, buf, str.length + 1);
  return buf;

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread web/vite.config.ts
Comment on lines +3 to +12
export default defineConfig({
root: '.',
build: {
outDir: 'dist',
target: 'es2022',
},
server: {
port: 3000,
},
});
Comment thread web/src/wasm/loader.ts
Comment on lines +30 to +34
_malloc(size: number): number;
_free(ptr: number): void;
UTF8ToString(ptr: number): string;
stringToUTF8(str: string, ptr: number, maxBytes: number): void;
}
Comment thread web/src/wasm/loader.ts
Comment on lines +49 to +63
function injectScript(src: string): Promise<void> {
return new Promise((resolve, reject) => {
const existing = document.querySelector(`script[data-cobroc-wasm]`);
if (existing) {
resolve();
return;
}
const script = document.createElement('script');
script.src = src;
script.dataset.cobrocWasm = '1';
script.onload = () => resolve();
script.onerror = () => reject(new Error('failed to load ' + src));
document.head.appendChild(script);
});
}
Comment thread web/src/storage.ts
Comment thread core/wasm_api.cpp
Comment on lines +167 to +188
bool b64Decode(const char* in, std::vector<uint8_t>& out) {
const size_t len = std::strlen(in);
if (len % 4 != 0) return false;
out.clear();
out.reserve((len / 4) * 3);
for (size_t i = 0; i < len; i += 4) {
int v[4];
for (int k = 0; k < 4; k++) {
const char c = in[i + k];
if (c == '=') v[k] = -2;
else v[k] = b64Value(c);
if (v[k] < 0 && !(c == '=' && k >= 2)) return false;
}
const uint32_t n = static_cast<uint32_t>(
(v[0] & 0x3F) << 18 | (v[1] & 0x3F) << 12 |
(v[2] > 0 ? v[2] : 0) << 6 | (v[3] > 0 ? v[3] : 0));
out.push_back(static_cast<uint8_t>((n >> 16) & 0xFF));
if (v[2] >= 0) out.push_back(static_cast<uint8_t>((n >> 8) & 0xFF));
if (v[3] >= 0) out.push_back(static_cast<uint8_t>(n & 0xFF));
}
return true;
}
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.

2 participants