From 8f6feec4f21d0af0d1c98daf5017eddd91d3d578 Mon Sep 17 00:00:00 2001 From: Thomas Hallock Date: Thu, 23 Oct 2025 21:50:32 -0500 Subject: [PATCH] feat(card-sorting): shrink/fade cards in correct suffix as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extended the shrink and fade behavior to apply to cards in both the correct prefix AND the correct suffix of the sorted sequence. **Examples:** Correct order: [10, 20, 30, 40, 50] Sequence: [10, 20, 30, 50, 40] - Shrink/fade: 10, 20, 30 (correct prefix) Sequence: [20, 30, 40, 50, 10] - Shrink/fade: none (no correct prefix or suffix) Sequence: [30, 20, 40, 50, 10] - Shrink/fade: 40, 50 (correct suffix) Sequence: [10, 20, 50, 40, 30] - Shrink/fade: 10, 20 (correct prefix) Sequence: [30, 10, 20, 40, 50] - Shrink/fade: 40, 50 (correct suffix) **How suffix checking works:** For each card at position i: - Calculate offset from end: (length - 1 - i) - Check if all positions from i to end match the corresponding positions in the correct order (counting from the end) - If yes → card is part of correct suffix A card shrinks/fades if it's in either the correct prefix OR correct suffix. This provides better visual feedback as players work from both ends toward the middle, which is a common sorting strategy. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../components/PlayingPhaseDrag.tsx | 51 ++++++++++++++----- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/apps/web/src/arcade-games/card-sorting/components/PlayingPhaseDrag.tsx b/apps/web/src/arcade-games/card-sorting/components/PlayingPhaseDrag.tsx index 0090704d..87d4a805 100644 --- a/apps/web/src/arcade-games/card-sorting/components/PlayingPhaseDrag.tsx +++ b/apps/web/src/arcade-games/card-sorting/components/PlayingPhaseDrag.tsx @@ -160,12 +160,12 @@ function ContinuousSequencePath({ const CARD_HALF_WIDTH = CARD_WIDTH / 2 const CARD_HALF_HEIGHT = CARD_HEIGHT / 2 - // Helper to check if a card is part of the correct prefix (and thus scaled to 50%) + // Helper to check if a card is part of the correct prefix or suffix (and thus scaled to 50%) const isCardCorrect = (card: SortingCard): boolean => { const positionInSequence = sequence.findIndex((c) => c.id === card.id) if (positionInSequence < 0) return false - // Check if all positions from 0 to positionInSequence are correct + // Check if card is part of correct prefix let isInCorrectPrefix = true for (let i = 0; i <= positionInSequence; i++) { if (sequence[i]?.id !== correctOrder[i]?.id) { @@ -174,7 +174,20 @@ function ContinuousSequencePath({ } } - return isSpectating ? spectatorEducationalMode && isInCorrectPrefix : isInCorrectPrefix + // Check if card is part of correct suffix + let isInCorrectSuffix = true + const offsetFromEnd = sequence.length - 1 - positionInSequence + for (let i = 0; i <= offsetFromEnd; i++) { + const seqIdx = sequence.length - 1 - i + const correctIdx = correctOrder.length - 1 - i + if (sequence[seqIdx]?.id !== correctOrder[correctIdx]?.id) { + isInCorrectSuffix = false + break + } + } + + const isCorrect = isInCorrectPrefix || isInCorrectSuffix + return isSpectating ? spectatorEducationalMode && isCorrect : isCorrect } // Get all card positions (card centers) with scale information @@ -1884,27 +1897,37 @@ export function PlayingPhaseDrag() { // Find the position of this card in the inferred sequence const positionInSequence = inferredSequence.findIndex((c) => c.id === card.id) - // Check if this card is part of the correct prefix - // A card is in the correct prefix if: - // 1. It's in the inferred sequence - // 2. All cards before it (positions 0 to positionInSequence-1) are also correct - // 3. This card itself matches the correct order at its position - let isInCorrectPrefix = false + // Check if this card is part of the correct prefix or suffix + let isInCorrectPrefixOrSuffix = false if (positionInSequence >= 0) { - // Check if all positions from 0 to positionInSequence are correct - isInCorrectPrefix = true + // Check if all positions from 0 to positionInSequence are correct (prefix) + let isInCorrectPrefix = true for (let i = 0; i <= positionInSequence; i++) { if (inferredSequence[i]?.id !== state.correctOrder[i]?.id) { isInCorrectPrefix = false break } } + + // Check if all positions from positionInSequence to end are correct (suffix) + let isInCorrectSuffix = true + const offsetFromEnd = inferredSequence.length - 1 - positionInSequence + for (let i = 0; i <= offsetFromEnd; i++) { + const seqIdx = inferredSequence.length - 1 - i + const correctIdx = state.correctOrder.length - 1 - i + if (inferredSequence[seqIdx]?.id !== state.correctOrder[correctIdx]?.id) { + isInCorrectSuffix = false + break + } + } + + isInCorrectPrefixOrSuffix = isInCorrectPrefix || isInCorrectSuffix } // Show green border based on educational mode for spectators const isCorrect = isSpectating - ? spectatorEducationalMode && isInCorrectPrefix - : isInCorrectPrefix + ? spectatorEducationalMode && isInCorrectPrefixOrSuffix + : isInCorrectPrefixOrSuffix // Get draggedByPlayerId from server state const serverPosition = state.cardPositions.find((p) => p.cardId === card.id) @@ -1919,7 +1942,7 @@ export function PlayingPhaseDrag() { isResizing={isResizing} isSpectating={isSpectating} isCorrect={isCorrect} - isCorrectPosition={isInCorrectPrefix} + isCorrectPosition={isInCorrectPrefixOrSuffix} draggedByPlayerId={draggedByPlayerId} localPlayerId={localPlayerId} players={players}