trioskosmos's picture
Upload folder using huggingface_hub
1d0beb6 verified
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ラブカ Solo | ゲームボード</title>
<link rel="icon" href="img/icon_blade.png">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<header class="header">
<div class="header-main-row">
<h1>🎵 ラブカ Solo
<span id="room-display"
style="font-size:0.55em; opacity:1; font-weight:normal; margin-left:15px; background: rgba(255,255,255,0.15); padding: 5px 12px; border-radius: 20px; border: 1px solid rgba(255,255,255,0.3); display: inline-flex; align-items: center; gap: 10px; box-shadow: 0 2px 4px rgba(0,0,0,0.2);">
<span
style="color: #fff; font-weight: bold; letter-spacing: 0.5px; text-shadow: 0 1px 2px rgba(0,0,0,0.5);">ROOM:
<span id="room-code-header" style="color: var(--accent-gold);">---</span></span>
<button class="btn" onclick="leaveRoom()"
style="font-size: 0.75rem; padding: 3px 10px; height: auto; line-height: 1; background: var(--accent-pink); color: white; border: none; margin: 0; font-weight: bold; box-shadow: 0 1px 3px rgba(0,0,0,0.3);"
title="Exit to Lobby">🚪 Exit</button>
</span>
</h1>
<div class="info-bar">
<span class="stat" title="Connection"><span class="stat-icon">📡</span> <strong id="header-debug-info"
style="border:1px solid #555; padding:0 4px; border-radius:3px;">PvE</strong></span>
<span class="stat" title="Turn"><span class="stat-icon">🕒</span> <span class="stat-label"
data-i18n="turn">ターン</span>: <strong id="turn">1</strong></span>
<span class="stat" title="Phase"><span class="stat-icon">🎮</span> <span class="stat-label"
data-i18n="phase">フェーズ</span>: <strong id="phase">MAIN</strong></span>
<span class="stat" title="Score"><span class="stat-icon">🏆</span> <span class="stat-label"
data-i18n="score">スコア</span>: <strong id="score">0 - 0</strong></span>
<span class="stat" title="Energy"><span class="stat-icon" style="color:var(--accent-gold);"></span>
<span class="stat-label" data-i18n="energy">エネルギー</span>: <strong id="header-energy">0 /
0</strong></span>
</div>
<div class="controls">
<button id="report-btn-header" class="btn btn-primary" onclick="openReportModal()" data-i18n="report"
title="Report Issue">🐛 <span class="btn-text">バグ報告</span></button>
<button class="btn btn-settings" onclick="openSettingsModal()" title="Settings">⚙️ <span
class="btn-text" data-i18n="settings">設定</span></button>
</div>
</div>
<div class="replay-controls" id="replay-controls"
style="display:none; flex-wrap:wrap; gap:8px; padding:4px; background:rgba(0,0,0,0.3); border-radius:6px; margin-top:4px; align-items:center; width:100%; justify-content: center;">
<button class="btn" onclick="document.getElementById('replay-file-input').click()"
style="font-size:0.8rem; padding:2px 8px;">📂 Open</button>
<input type="file" id="replay-file-input" accept=".json" style="display:none"
onchange="loadReplayFromFile(this)">
<button class="btn" onclick="openPasteReplayModal()" style="font-size:0.8rem; padding:2px 8px;">📋
Paste</button>
<button class="btn" onclick="loadReplay()" style="font-size:0.8rem; padding:2px 8px;">☁️ Load</button>
<input type="text" id="replay-file" value="ai_match.json" placeholder="ai_match.json"
style="width:120px; padding:2px 6px; background:rgba(0,0,0,0.5); border:1px solid #444; color:white; border-radius:4px; font-size: 0.8rem;">
<div style="width:1px; height:20px; background:#555; margin:0 4px;"></div>
<button class="btn" onclick="replayPrevTurn()"
style="font-size:0.75rem; padding:2px 6px; background:#444;">⏮ Turn</button>
<button class="btn" onclick="replayPrevPhase()"
style="font-size:0.75rem; padding:2px 6px; background:#555;">⏪ Phase</button>
<button class="btn" onclick="replayPrev()" style="font-size:0.8rem; padding:2px 10px;"></button>
<button class="btn" id="play-btn" onclick="togglePlay()"
style="font-size:0.8rem; padding:2px 10px; min-width:60px; background:#4a9eff;">▶ Play</button>
<button class="btn" onclick="replayNext()" style="font-size:0.8rem; padding:2px 10px;"></button>
<button class="btn" onclick="replayNextPhase()"
style="font-size:0.75rem; padding:2px 6px; background:#555;">Phase ⏩</button>
<button class="btn" onclick="replayNextTurn()"
style="font-size:0.75rem; padding:2px 6px; background:#444;">Turn ⏭</button>
<span style="color:#aaa; font-size:0.8rem; margin-left:8px;">Fr: <span id="frame-num">0</span>/<span
id="total-frames">0</span></span>
<input type="number" id="jump-frame" placeholder="#"
style="width:50px; padding:2px 4px; background:rgba(0,0,0,0.5); border:1px solid #444; color:white; border-radius:4px; font-size:0.8rem;"
onchange="window.jumpToFrame(this.value)">
</div>
</header>
<div id="phase-stepper" class="phase-stepper"></div>
<div class="game-container" id="game-container">
<!-- LEFT SIDEBAR (Rule Log) -->
<div class="sidebar-left" id="sidebar-left">
<div class="sidebar-section" style="height: 100%; display: flex; flex-direction: column; gap: 10px;">
<div id="card-desc-panel" class="card-desc-panel" style="display: none; flex-shrink: 0;">
<h3 style="color: var(--accent-pink); margin-bottom: 5px;">🎴 カード能力</h3>
<div id="card-desc-content" class="card-desc-content"
style="font-size: 0.85rem; line-height: 1.4; color: #eee;"></div>
</div>
<div id="active-abilities-panel" class="active-abilities-panel"
style="display: none; flex-shrink: 0; max-height: 30%; overflow-y: auto; background: rgba(0,0,0,0.2); border-left: 3px solid var(--accent-gold); padding: 5px 10px; border-radius: 4px;">
<h3 style="color: var(--accent-gold); margin-bottom: 5px; font-size: 0.9rem;">✨ 適用中の効果</h3>
<div id="active-abilities-list" style="font-size: 0.8rem; line-height: 1.3; color: #ddd;"></div>
</div>
<div style="flex: 1; display: flex; flex-direction: column; min-height: 0;">
<h3 data-i18n="rule_log">📜 ルールログ</h3>
<div class="rule-log-list" id="rule-log" style="flex: 1;"></div>
</div>
</div>
</div>
<!-- Resizer Left -->
<div class="resizer" id="resizer-left"></div>
<!-- CENTER GAME BOARD -->
<div class="game-board">
<!-- OPPONENT SECTION -->
<div class="player-section opponent">
<div class="player-label">
<span>👤 対戦相手 <span id="opp-agent-name"
style="font-size:0.8rem; opacity:0.6; font-weight:normal;">(Player 2)</span></span>
<span class="score-badge" id="opp-score">0 ライブ</span>
</div>
<div class="board-inner">
<!-- TOP: Hand Row -->
<div class="hand-row">
<div class="hand-group">
<span class="area-count" id="opp-hand-count">0</span>
<div class="card-area hand" id="opp-hand"></div>
</div>
</div>
<!-- MID: Energy Row (Horizontal) -->
<div class="energy-row">
<div class="energy-area-container horizontal">
<span class="area-count" id="opp-energy-count">0</span>
<div class="card-area energy" id="opp-energy"></div>
</div>
</div>
<!-- BOTTOM: Field Row -->
<div class="field-row">
<!-- Left Column: Success -->
<div class="side-column left">
<div class="successful-live-area-container">
<span class="count-badge" id="opp-score-badge" style="display:none;">0</span>
<div class="card-area" id="opp-success"></div>
</div>
</div>
<!-- Center Column: Live & Stage -->
<div class="center-field">
<div class="live-group">
<div class="card-area live-zone-cards" id="opp-live"></div>
</div>
<div class="stage-group">
<div class="card-area stage" id="opp-stage"></div>
</div>
</div>
<!-- Right Column: Decks -->
<div class="side-column right">
<div class="deck-discard-group">
<div class="card-area deck" id="opp-deck" style="width: 50px; height: 70px;">0</div>
<div class="card-area energy-deck" id="opp-energy-deck"
style="width: 50px; height: 70px;">0</div>
<span class="area-count" id="opp-discard-count" style="display:none;">0</span>
<div class="card-area discard" id="opp-discard"></div>
</div>
</div>
</div>
</div>
</div>
<!-- PLAYER SECTION -->
<div class="player-section">
<div class="player-label">
<span>⭐ あなた <span id="my-agent-name"
style="font-size:0.8rem; opacity:0.6; font-weight:normal;">(Player 1)</span></span>
<span class="score-badge" id="my-score">0 ライブ</span>
</div>
<div class="board-inner">
<!-- TOP: Field Row -->
<div class="field-row">
<!-- Left Column: Success Only -->
<div class="side-column left">
<div class="successful-live-area-container">
<span class="count-badge" id="my-score-badge" style="display:none;">0</span>
<div class="card-area" id="my-success"></div>
</div>
</div>
<!-- Center Column: Live (Top) & Stage (Bottom) -->
<div class="center-field">
<div class="live-group">
<div class="card-area live-zone-cards" id="my-live"></div>
</div>
<div class="stage-group">
<div class="card-area stage" id="my-stage"></div>
</div>
</div>
<!-- Right Column: Decks -->
<div class="side-column right">
<div class="deck-discard-group">
<div class="card-area deck" id="my-deck" style="width: 50px; height: 70px;">0</div>
<div class="card-area energy-deck" id="my-energy-deck"
style="width: 50px; height: 70px;">0</div>
<span class="area-count" id="my-discard-count" style="display:none;">0</span>
<div class="card-area discard" id="my-discard"></div>
<span class="area-count" id="my-exclude-count" style="display:none;">0</span>
<div class="card-area exclude" id="my-exclude"></div>
</div>
</div>
</div>
<!-- MID: Energy Row (Horizontal) -->
<div class="energy-row">
<div class="energy-area-container horizontal">
<span class="area-count" id="my-energy-count">0</span>
<div class="card-area energy" id="my-energy"></div>
</div>
</div>
<!-- BOTTOM: Hand Row -->
<div class="hand-row">
<div class="hand-group">
<span class="area-count" id="my-hand-count">0</span>
<div class="card-area hand" id="my-hand"></div>
</div>
</div>
</div>
</div>
</div>
<!-- Resizer Right -->
<div class="resizer" id="resizer-right"></div>
<!-- RIGHT SIDEBAR (Actions) -->
<div class="sidebar sidebar-right" id="sidebar-right">
<div class="sidebar-section">
<h3>☰ アクション</h3>
<div style="margin-bottom: 10px;">
<button class="btn btn-primary" onclick="showLastPerformance()"
style="width: 100%; font-size: 0.85rem; padding: 10px; background: linear-gradient(135deg, #f59e0b, #d97706); display: flex; align-items: center; justify-content: center; gap: 8px;">
<span>📊</span> パフォーマンス確認
</button>
</div>
<div class="action-list" id="actions"></div>
</div>
<div class="sidebar-section diagnostic-section" id="diagnostic-panel"
style="display:none; border: 1px solid var(--accent-blue); background: rgba(0,0,0,0.2);">
<h3 style="color: var(--accent-blue);">🔍 診断情報 (Diag)</h3>
<div id="diag-content" style="font-size: 0.75rem; padding: 5px; color: #ccc;">
<div>Phase: <span id="diag-phase">-</span></div>
<div>Player: <span id="diag-player">-</span></div>
<div>Legal Actions: <span id="diag-actions">-</span></div>
<div>Game Over: <span id="diag-gameover">-</span></div>
<div style="margin-top: 5px;">
<button class="action-btn" onclick="forceAdvance()"
style="font-size:0.7rem; padding: 2px 8px; background: var(--accent-blue);">Force
Advance</button>
</div>
</div>
</div>
<div class="sidebar-section performance-guide" id="perf-guide-panel"
style="display:none; border: 1px solid var(--accent-gold); background: rgba(0,0,0,0.2);">
<h3 style="color: var(--accent-gold);" data-i18n="live_guide">🌟 ライブガイド</h3>
<div id="perf-guide-content" style="font-size: 0.8rem; padding: 5px; color: #ddd;">
<!-- Content populated by JS -->
</div>
</div>
<div class="sidebar-section looked-cards-panel" id="looked-cards-panel"
style="display:none; border: 1px solid var(--accent-pink); background: rgba(255,100,180,0.1);">
<h3 style="color: var(--accent-pink);" data-i18n="looked_cards">👁️ 確認したカード</h3>
<div id="looked-cards-content" style="display:flex; flex-wrap:wrap; gap:5px; justify-content:center;">
<!-- Populated by JS -->
</div>
</div>
<!-- Rule Log Removed from here -->
<div class="sidebar-section log-section">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:8px;">
<h3 style="margin:0" data-i18n="logs">📜 ログ</h3>
<div>
<button class="perf-review-btn" id="view-last-perf-btn" onclick="showLastPerformance()"
data-i18n="last_perf">前のライブ結果</button>
</div>
</div>
<div class="log-list" id="log"></div>
</div>
<div class="sidebar-section ai-analysis" id="ai-analysis-panel"
style="border: 1px solid var(--accent-pink); background: rgba(255,100,180,0.1); display: none;">
<h3 style="color: var(--accent-pink);">🤖 AI 分析 (MCTS)
<span id="ai-thinking-dots" style="font-size: 0.8rem; font-weight: normal;">...</span>
</h3>
<div id="ai-suggestions-list" style="font-size: 0.8rem; padding: 5px; color: #eee;">
<!-- Top moves will be here -->
</div>
<div style="padding: 5px; border-top: 1px solid rgba(255,255,255,0.1);">
<button class="btn" style="font-size: 0.7rem; padding: 2px 8px;" onclick="runAiAnalysis()">分析実行 (Run
Analysis)</button>
</div>
</div>
<div class="sidebar-section god-mode">
<h3 data-i18n="god_mode">🔧 ゴッドモード</h3>
<div style="margin-bottom: 8px;">
<label style="font-size:0.8rem; color: #ccc;">🤖 AI Mode:</label>
<select id="ai-selector" onchange="changeAI()"
style="width:100%; background: #222; color: #fff; border: 1px solid #444; padding: 4px; border-radius: 4px;">
<option value="random">Random</option>
<option value="smart" selected>Smart</option>
<!-- <option value="super">Super (Minimax)</option> -->
</select>
</div>
<input type="number" id="force-id" placeholder="Action ID">
<button class="btn" onclick="forceAction()" data-i18n="force">強制実行</button>
<textarea id="god-code" rows="2" placeholder="p.hand.append(p.main_deck.pop())"></textarea>
<button class="btn" onclick="execCode()" data-i18n="exec">コード実行</button>
</div>
</div>
</div>
<!-- Settings Modal -->
<div id="settings-modal" class="modal-overlay" style="z-index: 2000;">
<div class="modal-content">
<div class="modal-header">
<span class="modal-title">⚙️ <span data-i18n="settings">設定</span></span>
<button class="close-btn" onclick="closeSettingsModal()">&times;</button>
</div>
<div class="modal-body settings-grid">
<div class="settings-group">
<label>Main Actions</label>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 8px;">
<button class="btn" onclick="fetchState()" title="Update State">🔄 <span class="btn-text"
data-i18n="update">更新</span></button>
<button class="btn btn-primary" onclick="resetGame()" title="Reset Game">🔄 <span
class="btn-text" data-i18n="reset">リセット</span></button>
</div>
</div>
<div class="settings-group">
<label>Game Controls</label>
<button class="btn" onclick="location.href='/deck_builder.html'"
style="background: linear-gradient(135deg, #9b59b6, #8e44ad);" data-i18n="deck_creator">🛠
デッキ作成</button>
<button class="btn" onclick="openDeckModal()"
style="background: linear-gradient(135deg, #4a9eff, #2a7edd);" data-i18n="set_deck">🎴
デッキ設定</button>
<button id="pvp-btn" class="btn" onclick="toggleHotseat()"
style="background: linear-gradient(135deg, #444, #222); border-color: #777;">Shared Screen:
OFF</button>
<button id="switch-btn" class="btn" onclick="togglePerspective()"
style="background: linear-gradient(135deg, #6366f1, #4338ca);">Switch View (P1/P2)</button>
</div>
<div class="settings-group">
<label>View & Support</label>
<button id="live-watch-btn" class="btn"
style="background: linear-gradient(135deg, #cc4444, #882222); border-color: #ff6666;"
onclick="toggleLiveWatch()" data-i18n="live_watch">🔴 ライブ監視: OFF</button>
<button id="friendly-abilities-btn" class="btn"
style="background: linear-gradient(135deg, #2ecc71, #27ae60); border-color: #76d672;"
onclick="toggleFriendlyAbilities()" data-i18n="friendly_abilities">読みやすい能力テキスト: ON</button>
<button id="lang-btn" class="btn" onclick="toggleLang()"
style="border:1px solid #aaa;">English</button>
<button class="btn" onclick="openHelpModal()"
style="border:1px solid var(--accent-gold); color:var(--accent-gold);">❓ ヘルプ</button>
</div>
<div class="settings-group">
<label>Tools</label>
<button class="btn" onclick="toggleReplayMode()" data-i18n="replay_mode">🎬 リプレイモード Toggle</button>
</div>
</div>
</div>
</div>
<!-- Performance Result Modal -->
<div id="performance-modal" class="modal-overlay" style="display:none; z-index: 3000;">
<div class="modal-content" style="max-width: 600px;">
<div class="modal-header">
<div class="modal-title" id="perf-title">ライブ結果</div>
<button class="btn" onclick="dismissPerformanceModal()"></button>
</div>
<div class="modal-body" id="perf-content" style="max-height: 70vh; overflow-y: auto;">
<!-- Performance results will be rendered here -->
</div>
<div class="modal-footer">
<button class="btn btn-primary" onclick="dismissPerformanceModal()">閉じる</button>
</div>
</div>
</div>
<!-- Selection Modal (for deck search, discard pick, etc) -->
<div id="selection-modal" class="modal-overlay" style="display:none; z-index: 4000;">
<div class="modal-content" style="max-width: 800px; width: 90%;">
<div class="modal-header">
<div class="modal-title" id="selection-title">カード選択</div>
<button class="btn" onclick="document.getElementById('selection-modal').style.display='none'"></button>
</div>
<div id="selection-description" style="padding:0 20px 10px; font-size:0.9rem; opacity:0.8;"></div>
<div class="modal-body" id="selection-content"
style="display:grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap:15px; padding:10px;">
<!-- Choice cards will be rendered here -->
</div>
<div class="modal-footer" id="selection-footer">
<!-- Cancel button if optional -->
</div>
</div>
</div>
<!-- Reporting Modal -->
<div id="report-modal" class="modal-overlay" style="display:none; z-index: 3000;">
<div class="modal-content">
<div class="modal-header">
<div class="modal-title">Report Issue / Save State</div>
<button class="btn" onclick="closeReportModal()"></button>
</div>
<div class="modal-body">
<p style="font-size: 0.85rem; color: var(--text-dim);">
Describe what happened or the failure point. The current game state and your last few actions will
be saved for debugging.
</p>
<textarea id="report-explanation" class="report-textarea"
placeholder="Explain the issue here..."></textarea>
</div>
<div class="modal-footer">
<button class="btn" onclick="downloadReport()"
style="margin-right:auto; border:1px solid var(--accent-blue); color:var(--text);">💾 Download
JSON</button>
<button class="btn" onclick="closeReportModal()">Cancel</button>
<button class="btn btn-primary" onclick="submitReport()">Submit to Server</button>
</div>
</div>
</div>
<!-- Help / FAQ Modal -->
<div id="help-modal" class="modal-overlay" style="display:none; z-index: 3000;">
<div class="modal-content" style="max-width: 700px;">
<div class="modal-header">
<span class="modal-title">❓ ヘルプ & FAQ (Help)</span>
<button onclick="closeHelpModal()"
style="background:none;border:none;color:white;font-size:1.5rem;cursor:pointer;">×</button>
</div>
<div class="modal-body" style="line-height: 1.6; font-size: 0.9rem;">
<h3 style="border-bottom:1px solid #444; padding-bottom:5px; margin-top:0;">🃏 デッキのセット方法 (Deck Setup)
</h3>
<ul style="padding-left:20px; color:#ddd;">
<li><b>Deck Log:</b> Bushiroad Deck Log からHTMLをコピーして「Option 2」に貼り付けます。</li>
<li><b>Test Deck:</b> 「🧪 Load Test Deck」ボタンで、テスト用(2倍量)デッキを読み込みます。</li>
<li><b>Random Deck:</b> 「🎲 Generate Random Deck」ボタンで、ランダムな有効デッキを生成します。</li>
</ul>
<h3 style="border-bottom:1px solid #444; padding-bottom:5px; margin-top:15px;">📱 モバイル操作 (Mobile)</h3>
<ul style="padding-left:20px; color:#ddd;">
<li>画面右下の <b>☰ ボタン</b> でサイドバー(アクション履歴、ログ)を開閉できます。</li>
<li>手札やステージなどのゾーンは横スクロール可能です。</li>
</ul>
<h3 style="border-bottom:1px solid #444; padding-bottom:5px; margin-top:15px;">🎮 ゲーム操作 (Controls)</h3>
<ul style="padding-left:20px; color:#ddd;">
<li><b>更新 (Update):</b> ゲームの状態を再取得します。</li>
<li><b>リセット (Reset):</b> ゲームを初期状態の最初からやり直します。</li>
<li>カードをクリックして使用・移動します。</li>
<li>アクションを選択したら、サイドバーの「Do Action」等は自動で進む場合があります。</li>
</ul>
</div>
<div class="modal-footer">
<button class="btn btn-primary" onclick="closeHelpModal()">閉じる</button>
</div>
</div>
</div>
<!-- Deck Setup Modal -->
<div id="deck-modal" class="modal-overlay" style="display: none; z-index: 3000;">
<div class="modal-content" style="width: 600px;">
<div class="modal-header">
<span class="modal-title">🎴 デッキセット (Set Deck)</span>
<button onclick="closeDeckModal()"
style="background: none; border: none; color: white; font-size: 1.5rem; cursor: pointer;">×</button>
</div>
<div class="modal-body">
<label style="display: block; margin-bottom: 8px;">プレイヤー選択:</label>
<select id="deck-player-select"
style="width: 100%; padding: 8px; margin-bottom: 15px; background: var(--bg-zone); border: 1px solid var(--border); color: white; border-radius: 5px;">
<option value="0">プレイヤー1 (あなた)</option>
<option value="1">プレイヤー2 (AI)</option>
<option value="both">両方 (Both)</option>
</select>
<div
style="background: rgba(74, 158, 255, 0.1); border: 1px solid var(--accent-blue); padding: 10px; border-radius: 8px; margin-bottom: 15px; font-size: 0.8rem;">
<div style="color: var(--accent-blue); font-weight: bold; margin-bottom: 5px;">📍 デッキデータの取得方法:</div>
<ol style="padding-left: 20px; color: #ccc;">
<li><a href="https://decklog.bushiroad.com/search?c=11" target="_blank"
style="color: var(--accent-pink);">デッキログ (ラブライブ!Solo)</a> にログイン。</li>
<li>デッキを選択し、虫眼鏡アイコン 🔍 をクリック。</li>
<li><b>F12</b> キーを押して開発者ツールを開く。</li>
<li>In the <b>Elements</b> tab, right-click the top <code>&lt;html&gt;</code> tag.</li>
<li>Select <b>Copy</b> &rarr; <b>Copy outerHTML</b>.</li>
<li>Paste the result below.</li>
</ol>
</div>
<div
style="margin-bottom: 15px; background: rgba(255, 255, 255, 0.05); padding: 10px; border-radius: 5px;">
<label style="display: block; margin-bottom: 5px; font-weight: bold;">Option 1: Upload File</label>
<input type="file" id="deck-file-input" accept=".html,.txt,.json"
style="width: 100%; font-size: 0.9rem;">
<button class="btn"
style="width:100%; margin-top:10px; background:linear-gradient(135deg, #a855f7, #6b21a8);"
onclick="loadTestDeck()">
🧪 Load Test Deck (Doubled)
</button>
<button class="btn"
style="width:100%; margin-top:10px; background:linear-gradient(135deg, #f59e0b, #d97706);"
onclick="loadRandomDeck()">
🎲 Generate Random Deck
</button>
</div>
<label style="display: block; margin-bottom: 8px;">Option 2: Paste Deck HTML:</label>
<textarea id="deck-html-input" class="report-textarea" style="height: 200px;"
placeholder="Paste the HTML content from a deck page here..."></textarea>
<div id="deck-preview" style="margin-top: 10px; font-size: 0.8rem; color: var(--text-dim);"></div>
</div>
<div class="modal-footer">
<button class="btn" onclick="closeDeckModal()">Cancel</button>
<button class="btn btn-primary" onclick="submitDeck()">Apply Deck</button>
</div>
</div>
</div>
<!-- Paste Replay Modal -->
<div id="paste-replay-modal" class="modal-overlay" style="display: none;">
<div class="modal-content" style="width: 600px;">
<div class="modal-header">
<span class="modal-title">📋 Paste Replay JSON</span>
<button onclick="closePasteReplayModal()"
style="background: none; border: none; color: white; font-size: 1.5rem; cursor: pointer;">×</button>
</div>
<div class="modal-body">
<p style="color:#ccc; font-size:0.8rem; margin-bottom:8px;">Paste the full JSON content of a replay file
here.</p>
<textarea id="paste-replay-input" class="report-textarea" style="height: 300px; font-family:monospace;"
placeholder='{"game_id": 123, "states": [...]}'></textarea>
</div>
<div class="modal-footer">
<button class="btn" onclick="closePasteReplayModal()">Cancel</button>
<button class="btn btn-primary" onclick="submitPasteReplay()">Load Replay</button>
</div>
</div>
</div>
<!-- Game Setup Modal -->
<div id="setup-modal" class="modal-overlay" style="display: none; background: rgba(0,0,0,0.95); z-index: 10000;">
<div class="modal-content" style="width: 700px; max-height: 90vh; overflow-y: auto;">
<div class="modal-header">
<span class="modal-title">⚔️ Game Setup</span>
<button onclick="closeSetupModal()"
style="background:none;border:none;color:white;font-size:1.5rem;cursor:pointer;">×</button>
</div>
<div class="modal-body">
<div id="setup-mode-display"
style="text-align: center; margin-bottom: 15px; font-size: 1.1rem; font-weight: bold; color: var(--accent-gold);">
Mode: Solo (PvE)
</div>
<!-- Deck Selection Grid -->
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
<!-- Player 1 (You) -->
<div class="setup-column"
style="background: rgba(255,255,255,0.05); padding: 15px; border-radius: 8px;">
<h4 style="margin-top: 0; color: var(--accent-blue);">👤 Player 1 (You)</h4>
<label style="display:block; margin-bottom:5px; font-size:0.9rem;">Select Deck:</label>
<select id="p0-deck-select" onchange="onDeckSelectChange(0)"
style="width: 100%; padding: 8px; background: #222; color: white; border: 1px solid #555; margin-bottom: 10px;">
<option value="random">🎲 Random Deck</option>
<option value="paste">📋 Paste Deck List...</option>
</select>
<div id="p0-paste-area" style="display:none;">
<textarea id="p0-deck-paste" placeholder="Paste deck list here..."
style="width: 100%; height: 100px; background: #111; color: #ddd; border: 1px solid #444; font-size: 0.8rem;"></textarea>
</div>
<div id="p0-deck-preview" style="font-size: 0.8rem; color: #aaa; margin-top: 5px;"></div>
</div>
<!-- Player 2 (Opponent) -->
<div id="p2-setup-column" class="setup-column"
style="background: rgba(255,255,255,0.05); padding: 15px; border-radius: 8px;">
<h4 style="margin-top: 0; color: var(--accent-pink);">🤖 Player 2 (AI)</h4>
<label style="display:block; margin-bottom:5px; font-size:0.9rem;">Select Deck:</label>
<select id="p1-deck-select" onchange="onDeckSelectChange(1)"
style="width: 100%; padding: 8px; background: #222; color: white; border: 1px solid #555; margin-bottom: 10px;">
<option value="random">🎲 Random Deck</option>
<option value="paste">📋 Paste Deck List...</option>
</select>
<div id="p1-paste-area" style="display:none;">
<textarea id="p1-deck-paste" placeholder="Paste deck list here..."
style="width: 100%; height: 100px; background: #111; color: #ddd; border: 1px solid #444; font-size: 0.8rem;"></textarea>
</div>
<div id="p1-deck-preview" style="font-size: 0.8rem; color: #aaa; margin-top: 5px;"></div>
</div>
</div>
<div style="margin-top: 20px; text-align: center;">
<button class="btn" onclick="submitGameSetup()"
style="padding: 10px 30px; font-size: 1.1rem; background: linear-gradient(135deg, #2ecc71, #27ae60); font-weight: bold; width: 100%;">
🚀 Start Game
</button>
</div>
</div>
</div>
</div>
<!-- Room Selection Modal -->
<div id="room-modal" class="modal-overlay" style="display: flex; background: rgba(0,0,0,0.9); z-index: 9999;">
<div class="modal-content" style="width: 400px; text-align: center;">
<div class="modal-header" style="justify-content: center;">
<span class="modal-title">🏠 マルチプレイ ロビー (Lobby)</span>
</div>
<div class="modal-body">
<p style="color:#ccc; margin-bottom: 20px;">新しいルームを作成するか、既存のルームに参加してください。</p>
<div style="margin-bottom: 10px; text-align: left; margin-left: 5px;">
<label
style="color: #ddd; font-size: 0.9rem; cursor: pointer; display: inline-flex; align-items: center;">
<input type="checkbox" id="public-room-check" style="margin-right: 8px; transform: scale(1.2);">
Public Room (Show in Lobby)
</label>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 20px;">
<button type="button" class="btn" onclick="openGameSetup('pve')"
style="padding: 12px 5px; font-size: 0.9rem; background: linear-gradient(135deg, #2ecc71, #27ae60); font-weight: bold;">
Solo (vs AI)
</button>
<button type="button" class="btn" onclick="openGameSetup('pvp')"
style="padding: 12px 5px; font-size: 0.9rem; background: linear-gradient(135deg, #a855f7, #6b21a8); font-weight: bold;">
PvP (vs Human)
</button>
</div>
<div style="font-size: 0.8rem; color: #888; margin-top: -10px; margin-bottom: 20px;">対戦相手を選択してルームを作成
</div>
<div style="height: 1px; background: #444; margin: 20px 0;"></div>
<!-- Public Rooms Section -->
<div style="margin-bottom: 20px;">
<div
style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
<span style="color: #aaa; font-size: 0.9rem; font-weight: bold;">🌍 Public Rooms</span>
<button class="btn" onclick="fetchPublicRooms()"
style="font-size: 0.7rem; padding: 2px 8px;">Refresh</button>
</div>
<div id="public-rooms-list"
style="background: rgba(0,0,0,0.3); border: 1px solid #444; border-radius: 4px; height: 120px; overflow-y: auto; padding: 5px; text-align: left;">
<div style="color: #666; font-size: 0.8rem; text-align: center; padding-top: 20px;">Loading...
</div>
</div>
</div>
<div style="height: 1px; background: #444; margin: 20px 0;"></div>
<div>
<input type="text" id="room-code-input" placeholder="Enter Room Code (e.g. ABCD)"
style="width: 100%; padding: 10px; font-size: 1.2rem; text-align: center; text-transform: uppercase; margin-bottom: 10px; border-radius: 4px; border: 1px solid #555; background: #222; color: white;"
maxlength="4" oninput="this.value = this.value.toUpperCase()">
<button type="button" class="btn" onclick="joinRoom()"
style="width: 100%; padding: 10px; font-size: 1rem; background: linear-gradient(135deg, #3498db, #2980b9);">
🚪 Join Room
</button>
</div>
<!-- Offline Mode for Testing -->
<div style="margin-top: 30px;">
<button type="button" class="btn" onclick="startOffline()"
style="font-size: 0.9rem; padding: 8px 16px; background: linear-gradient(135deg, #f59e0b, #d97706); opacity: 1; font-weight: bold; width: 100%;">
🚀 Start Offline (WASM)
</button>
</div>
</div>
</div>
<!-- Perspective Selection Modal -->
<div id="perspective-modal" class="modal-overlay" style="z-index: 3000;">
<div class="modal-content" style="max-width:400px; text-align:center;">
<div class="modal-header">
<span class="modal-title">Select Your Seat</span>
</div>
<div class="modal-body">
<p style="color:#ccc; margin-bottom:20px;">Which player are you?</p>
<div style="display:grid; grid-template-columns:1fr 1fr; gap:15px;">
<button class="btn" onclick="setPerspective(0)"
style="background: linear-gradient(135deg, #3b82f6, #1d4ed8);">
Player 1 (Host)
</button>
<button class="btn" onclick="setPerspective(1)"
style="background: linear-gradient(135deg, #ef4444, #b91c1c);">
Player 2 (Joiner)
</button>
</div>
</div>
</div>
</div>
<div id="mobile-action-bar"></div>
<button id="mobile-sidebar-toggle" onclick="toggleSidebar()"></button>
<script>
let currentAiSims = 0;
let analysisInterval = null;
async function runAiAnalysis(sims = 10) {
const roomCode = localStorage.getItem("roomCode");
const panel = document.getElementById("ai-analysis-panel");
panel.style.display = "block";
const dots = document.getElementById("ai-thinking-dots");
dots.textContent = "考え中...";
try {
const res = await fetch("/api/ai_suggest", {
method: "POST",
headers: { "Content-Type": "application/json", "X-Room-Code": roomCode },
body: JSON.stringify({ sims: sims })
});
const data = await res.json();
if (data.success) {
renderSuggestions(data.suggestions);
currentAiSims += sims;
dots.textContent = `(${currentAiSims} sims)`;
}
} catch (e) {
console.error("AI suggest failed", e);
}
}
function renderSuggestions(suggestions) {
const list = document.getElementById("ai-suggestions-list");
list.innerHTML = "";
// Show top 5
suggestions.slice(0, 5).forEach(s => {
const item = document.createElement("div");
item.style.marginBottom = "5px";
item.style.display = "flex";
item.style.justifyContent = "space-between";
const winRate = (s.value * 100).toFixed(1);
const color = s.value > 0.6 ? "#2ecc71" : s.value < 0.4 ? "#e74c3c" : "#f1c40f";
item.innerHTML = `
<span>${s.desc}</span>
<span style="color: ${color}; font-weight: bold;">${winRate}% (${s.visits})</span>
`;
list.appendChild(item);
});
}
// Polling logic: if it's player's turn, run analysis occasionally
setInterval(() => {
const phase = document.getElementById("phase").textContent;
if (phase && phase !== "TERMINAL" && phase !== "SETUP") {
// Auto run small analysis if panel is visible
if (document.getElementById("ai-analysis-panel").style.display === "block") {
runAiAnalysis(10);
}
} else {
currentAiSims = 0;
}
}, 5000);
</script>
<script src="js/layout.js"></script>
<script src="js/ability_translator.js"></script>
<script src="js/main.js?v=7"></script>
</body>
</html>