Move the round strip out from under the opponent hand; let undo cross turns
Deploy web client / build (push) Waiting to run
Deploy web client / deploy (push) Blocked by required conditions

Two fixes to the last change:

- The round strip sat top-center, exactly where the opponent's hand is, so its
  cards covered it. Moved it under the rival plaque on the left, clear of the hand.

- Undo/redo was capped at the current turn. When the setting is on it now walks the
  whole timeline -- back through committed moves, the rival's replies, and earlier
  rounds. The rival stays suspended whenever there are moves ahead to redo, so
  reviewing never makes it replay the move being looked at. Menu label updated to
  "전체 되감기".

Verified in a browser: the strip no longer overlaps the opponent hand, and undo
from mid-game walks back eight steps across a rival turn to the opening.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XBQKgvBbxbheiTF1AVy1Sh
This commit is contained in:
2026-07-15 18:18:47 +09:00
co-authored by Claude Opus 4.8
parent 774faf2b51
commit 7fc15ff46a
2 changed files with 14 additions and 19 deletions
+8 -14
View File
@@ -42,8 +42,8 @@ function loadMode(): Mode {
} }
// Off by default: taking moves back is a training aid, not how the game is played, // Off by default: taking moves back is a training aid, not how the game is played,
// and the default should be the honest game. When on, it is limited to the current // and the default should be the honest game. When on, undo/redo walk the whole
// turn (see turnFloor) -- you can revise a misclick, not rewind the rival. // timeline -- across the rival's moves and earlier rounds, not just your turn.
const UNDO_KEY = "lost-cities.undo"; const UNDO_KEY = "lost-cities.undo";
function loadUndoEnabled(): boolean { function loadUndoEnabled(): boolean {
@@ -154,17 +154,11 @@ function App() {
const { state: match, selection } = frames[cursor]; const { state: match, selection } = frames[cursor];
// The board on screen is the round in play; the match is what decides the game. // The board on screen is the round in play; the match is what decides the game.
const state = match.round; const state = match.round;
// The start of the current turn: the most recent committed move at or before the // When enabled, undo/redo walk the whole timeline -- back through your committed
// cursor (a rival move, or your own draw). Undo cannot cross it, so you can take // moves, the rival's replies, and earlier rounds, not just the current turn. The
// back a card selection or placement within your turn but never rewind into the // rival is held whenever there are moves ahead to redo, so stepping back never
// rival's move or an earlier turn. // makes it replay the move you are reviewing.
const turnFloor = useMemo(() => { const canUndo = undoEnabled && cursor > 0;
for (let index = cursor; index > 0; index -= 1) {
if (frames[index].move) return index;
}
return 0;
}, [frames, cursor]);
const canUndo = undoEnabled && cursor > turnFloor;
const canRedo = undoEnabled && cursor < frames.length - 1; const canRedo = undoEnabled && cursor < frames.length - 1;
const latestMatch = useRef(match); const latestMatch = useRef(match);
@@ -503,7 +497,7 @@ function App() {
checked={undoEnabled} checked={undoEnabled}
onChange={(event) => setUndoEnabled(event.target.checked)} onChange={(event) => setUndoEnabled(event.target.checked)}
/> />
<span> / · </span> <span> / · </span>
</label> </label>
</div> </div>
)} )}
+6 -5
View File
@@ -692,22 +692,23 @@ button.card:disabled { cursor: default; }
/* Match mode: which round is live, and what is already banked. The board only /* Match mode: which round is live, and what is already banked. The board only
ever shows the round in play, so without this the score plaques would be the ever shows the round in play, so without this the score plaques would be the
only hint that two more rounds are coming. */ only hint that two more rounds are coming. */
/* Tucked under the rival plaque on the left, clear of the opponent hand which
sits centered along the top and would otherwise cover it. */
.round-strip { .round-strip {
position: absolute; position: absolute;
top: 16px; top: 88px;
left: 50%; left: 24px;
transform: translateX(-50%);
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
padding: 6px 12px; padding: 6px 14px;
border-radius: 999px; border-radius: 999px;
background: rgba(18, 14, 10, 0.72); background: rgba(18, 14, 10, 0.72);
border: 1px solid rgba(214, 188, 140, 0.22); border: 1px solid rgba(214, 188, 140, 0.22);
font-size: 11px; font-size: 11px;
letter-spacing: 0.12em; letter-spacing: 0.12em;
color: rgba(214, 188, 140, 0.55); color: rgba(214, 188, 140, 0.55);
z-index: 4; z-index: 9;
pointer-events: none; pointer-events: none;
} }