da601bebd6
Build and Deploy / build-and-push (push) Successful in 4m24s
Engine: replace broken has_legal_moves loop (which checked buried mid-column cards without sequence validation) with a delegation to possible_instructions(), mirroring the hint system's logic exactly. WASM: add has_moves: bool to GameSnapshot, computed in snap() using the same stock/waste/possible_instructions check so the web client gets the flag in every state update at no extra round-trip cost. Web: show a non-blocking no-moves banner (slide-up toast) with Undo and New Game actions when has_moves is false and the game is not won. Banner hides automatically once a move restores legal play (e.g. after undo). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
94 lines
3.6 KiB
HTML
94 lines
3.6 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Ferrous Solitaire — Play</title>
|
|
<link rel="stylesheet" href="/web/game.css">
|
|
<!-- Matomo -->
|
|
<script>
|
|
var _paq = window._paq = window._paq || [];
|
|
_paq.push(['trackPageView']);
|
|
_paq.push(['enableLinkTracking']);
|
|
(function() {
|
|
var u = "https://analytics.aleshym.co/";
|
|
_paq.push(['setTrackerUrl', u + 'matomo.php']);
|
|
_paq.push(['setSiteId', '1']);
|
|
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
|
|
g.async = true; g.src = u + 'matomo.js'; s.parentNode.insertBefore(g, s);
|
|
})();
|
|
</script>
|
|
<!-- End Matomo -->
|
|
</head>
|
|
<body>
|
|
<header>
|
|
<div class="hud-left">
|
|
<a href="/" class="home-link" title="Home">←</a>
|
|
<span class="logo">Ferrous Solitaire</span>
|
|
<span id="hud-seed" class="muted"></span>
|
|
</div>
|
|
<div class="hud-center">
|
|
<span id="hud-score">Score: 0</span>
|
|
<span id="hud-moves">Moves: 0</span>
|
|
<span id="hud-timer">0:00</span>
|
|
<span id="hud-stock">Stock: 24</span>
|
|
</div>
|
|
<div class="hud-right">
|
|
<button id="btn-undo" title="Undo (Z)">↩ Undo</button>
|
|
<button id="btn-new" title="New game">↺ New</button>
|
|
<label class="toggle-label" title="Draw one or three cards">
|
|
<input type="checkbox" id="chk-draw3"> Draw 3
|
|
</label>
|
|
<button id="btn-theme" title="Switch card theme">Dark</button>
|
|
<a id="hud-avatar" href="/account" title="Account" class="hud-avatar-link" style="display:none">
|
|
<div class="hud-avatar-inner">
|
|
<img id="hud-avatar-img" src="" alt="" style="display:none">
|
|
<span id="hud-avatar-initials"></span>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
</header>
|
|
|
|
<main>
|
|
<section id="board">
|
|
<div id="card-area"></div>
|
|
<button id="btn-board-undo" class="board-undo" title="Undo (Z)" disabled>↩ Undo</button>
|
|
</section>
|
|
</main>
|
|
|
|
<div id="resume-overlay" class="hidden">
|
|
<div class="resume-card">
|
|
<div class="resume-title">Resume Game?</div>
|
|
<p class="resume-detail">You have an unfinished game saved. Would you like to continue where you left off?</p>
|
|
<div class="resume-actions">
|
|
<button id="btn-resume">↩ Resume</button>
|
|
<button id="btn-resume-new" class="secondary">↺ New Game</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="win-overlay" class="hidden">
|
|
<div class="win-card">
|
|
<div class="win-title">You Won!</div>
|
|
<div id="win-score" class="win-score"></div>
|
|
<div id="win-moves" class="win-detail"></div>
|
|
<div id="win-time" class="win-detail"></div>
|
|
<button id="btn-win-new">Play Again ↺</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="no-moves-banner" class="hidden">
|
|
<div class="no-moves-card">
|
|
<div class="no-moves-title">No Moves Available</div>
|
|
<p class="no-moves-detail">No legal moves remain. Undo to go back or start a new game.</p>
|
|
<div class="no-moves-actions">
|
|
<button id="btn-no-moves-undo">↩ Undo</button>
|
|
<button id="btn-no-moves-new" class="secondary">↺ New Game</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script type="module" src="/web/game.js"></script>
|
|
</body>
|
|
</html>
|