From b172440a41e958ced98903bb8f4c2e4b423e1356 Mon Sep 17 00:00:00 2001 From: Thomas Hallock Date: Wed, 29 Oct 2025 14:14:07 -0500 Subject: [PATCH] feat(rithmomachia): add helpful error messages for failed captures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a capture attempt fails because no mathematical relation works, show a detailed error dialog explaining why each relation type can't be used. This helps players understand the mathematical requirements for captures. Changes to relationEngine.ts: - Updated all relation check functions to return explanation messages on failure - EQUAL: Shows actual values and why they don't match - MULTIPLE/DIVISOR: Shows attempted division result - SUM/DIFF/PRODUCT/RATIO: Shows what helper value is needed Changes to RithmomachiaGame.tsx: - Added CaptureErrorDialog component for displaying capture failures - Shows red error dialog when availableRelations.length === 0 - Lists all relations and specific explanations for why each failed - Includes Close button to dismiss the dialog Example error messages: - "9 ≠ 12 (values are not equal)" - "9 does not divide 12 evenly (12÷9=1.33...)" - "Helper 3 doesn't satisfy sum (need 3 but got 3)" - "SUM: No friendly piece can serve as helper" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../components/RithmomachiaGame.tsx | 157 +++++++++++++++++- .../rithmomachia/utils/relationEngine.ts | 45 +++-- 2 files changed, 191 insertions(+), 11 deletions(-) diff --git a/apps/web/src/arcade-games/rithmomachia/components/RithmomachiaGame.tsx b/apps/web/src/arcade-games/rithmomachia/components/RithmomachiaGame.tsx index a0feb44c..56914e76 100644 --- a/apps/web/src/arcade-games/rithmomachia/components/RithmomachiaGame.tsx +++ b/apps/web/src/arcade-games/rithmomachia/components/RithmomachiaGame.tsx @@ -24,6 +24,147 @@ import { } from '../utils/relationEngine' import { PieceRenderer } from './PieceRenderer' +/** + * Error dialog when no capture is possible + */ +function CaptureErrorDialog({ + targetPos, + cellSize, + moverPiece, + targetPiece, + onClose, + closing, +}: { + targetPos: { x: number; y: number } + cellSize: number + moverPiece: Piece + targetPiece: Piece + onClose: () => void + closing: boolean +}) { + const moverValue = getEffectiveValue(moverPiece) + const targetValue = getEffectiveValue(targetPiece) + + // Get explanations for why each relation failed + const explanations: string[] = [] + if ( + moverValue !== undefined && + moverValue !== null && + targetValue !== undefined && + targetValue !== null + ) { + explanations.push(checkEqual(moverValue, targetValue).explanation || '') + explanations.push(checkMultiple(moverValue, targetValue).explanation || '') + explanations.push(checkDivisor(moverValue, targetValue).explanation || '') + explanations.push('SUM: No friendly piece can serve as helper') + explanations.push('DIFF: No friendly piece can serve as helper') + explanations.push('PRODUCT: No friendly piece can serve as helper') + explanations.push('RATIO: No friendly piece can serve as helper') + } + + const entranceSpring = useSpring({ + from: { scale: 0, opacity: 0 }, + scale: closing ? 0 : 1, + opacity: closing ? 0 : 1, + config: { tension: 280, friction: 20 }, + }) + + return ( + `translate(${targetPos.x}, ${targetPos.y}) scale(${s})` + )} + > + +
e.stopPropagation()} + > +
+ ❌ Capture Not Possible +
+
+ No mathematical relation works: +
+
+ {explanations.filter(Boolean).map((exp, i) => ( +
+ • {exp} +
+ ))} +
+ +
+
+
+ ) +} + /** * Main Rithmomachia game component. * Orchestrates the game phases and UI. @@ -2018,7 +2159,7 @@ function BoardDisplay() { ) } - // Phase 1: Show relation options + // Phase 1: Show relation options OR error if no valid relations if (captureDialogOpen && targetPos && !selectedRelation) { console.log('[Render] Showing CaptureRelationOptions') console.log('[Render] availableRelations:', availableRelations) @@ -2036,6 +2177,20 @@ function BoardDisplay() { return null } + // Show error message if no valid relations + if (availableRelations.length === 0) { + return ( + + ) + } + return (