From 81ead65680892efa4d0ab07e7f0ef77eb1bc1405 Mon Sep 17 00:00:00 2001 From: Thomas Hallock Date: Sun, 2 Nov 2025 09:43:21 -0600 Subject: [PATCH] feat: add Strategy & Tactics section to Rithmomachia guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Create StrategySection.tsx component with comprehensive strategy content - Add opening principles, mid-game tactics, victory paths, common mistakes, and advanced concepts - Include interactive board diagrams for each strategic concept - Integrate Strategy section into PlayingGuideModal navigation (between Capture and Harmony) - Use existing translation keys from strategy section already present in all locale files - Add brain emoji (🧠) icon for Strategy tab 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../components/PlayingGuideModal.tsx | 5 + .../guide-sections/StrategySection.tsx | 684 ++++++++++++++++++ 2 files changed, 689 insertions(+) create mode 100644 apps/web/src/arcade-games/rithmomachia/components/guide-sections/StrategySection.tsx diff --git a/apps/web/src/arcade-games/rithmomachia/components/PlayingGuideModal.tsx b/apps/web/src/arcade-games/rithmomachia/components/PlayingGuideModal.tsx index cd9c23f3..0f00ba7c 100644 --- a/apps/web/src/arcade-games/rithmomachia/components/PlayingGuideModal.tsx +++ b/apps/web/src/arcade-games/rithmomachia/components/PlayingGuideModal.tsx @@ -8,6 +8,7 @@ import { useAbacusSettings } from '@/hooks/useAbacusSettings' import { OverviewSection } from './guide-sections/OverviewSection' import { PiecesSection } from './guide-sections/PiecesSection' import { CaptureSection } from './guide-sections/CaptureSection' +import { StrategySection } from './guide-sections/StrategySection' import { HarmonySection } from './guide-sections/HarmonySection' import { VictorySection } from './guide-sections/VictorySection' @@ -160,6 +161,7 @@ export function PlayingGuideModal({ isOpen, onClose, standalone = false }: Playi { id: 'overview', label: t('sections.overview'), icon: '🎯' }, { id: 'pieces', label: t('sections.pieces'), icon: '♟️' }, { id: 'capture', label: t('sections.capture'), icon: '⚔️' }, + { id: 'strategy', label: t('sections.strategy'), icon: '🧠' }, { id: 'harmony', label: t('sections.harmony'), icon: '🎵' }, { id: 'victory', label: t('sections.victory'), icon: '👑' }, ] @@ -561,6 +563,9 @@ export function PlayingGuideModal({ isOpen, onClose, standalone = false }: Playi {activeSection === 'capture' && ( )} + {activeSection === 'strategy' && ( + + )} {activeSection === 'harmony' && ( )} diff --git a/apps/web/src/arcade-games/rithmomachia/components/guide-sections/StrategySection.tsx b/apps/web/src/arcade-games/rithmomachia/components/guide-sections/StrategySection.tsx new file mode 100644 index 00000000..998c8878 --- /dev/null +++ b/apps/web/src/arcade-games/rithmomachia/components/guide-sections/StrategySection.tsx @@ -0,0 +1,684 @@ +import { useTranslations } from 'next-intl' +import { css } from '../../../../../styled-system/css' +import { RithmomachiaBoard, type ExamplePiece } from '../RithmomachiaBoard' + +/** + * Helper to convert square names to crop area coordinates + * @param topLeft - e.g. 'D3' + * @param bottomRight - e.g. 'H6' + */ +function squaresToCropArea(topLeft: string, bottomRight: string) { + const minCol = topLeft.charCodeAt(0) - 65 // A=0 + const maxCol = bottomRight.charCodeAt(0) - 65 + const maxRow = Number.parseInt(topLeft.slice(1), 10) + const minRow = Number.parseInt(bottomRight.slice(1), 10) + return { minCol, maxCol, minRow, maxRow } +} + +export function StrategySection({ useNativeAbacusNumbers }: { useNativeAbacusNumbers: boolean }) { + const t = useTranslations('rithmomachia.guide') + + // Example: Good opening position with central control + const openingExample: ExamplePiece[] = [ + // White pieces controlling center + { square: 'E4', type: 'T', color: 'W', value: 20 }, + { square: 'F3', type: 'C', color: 'W', value: 9 }, + { square: 'G3', type: 'C', color: 'W', value: 16 }, + // Black pieces + { square: 'E6', type: 'T', color: 'B', value: 28 }, + { square: 'F7', type: 'C', color: 'B', value: 9 }, + ] + + // Example: Helper network for complex captures + const helperNetworkExample: ExamplePiece[] = [ + // White's helper network + { square: 'D4', type: 'C', color: 'W', value: 4 }, + { square: 'E4', type: 'C', color: 'W', value: 5 }, + { square: 'F4', type: 'C', color: 'W', value: 6 }, + // Black target that can be captured via helpers + { square: 'G4', type: 'C', color: 'B', value: 9 }, // 4+5=9 + ] + + // Example: Defensive positioning + const defensiveExample: ExamplePiece[] = [ + // White pyramid protected by support pieces + { square: 'E4', type: 'P', color: 'W', value: 36 }, + { square: 'D4', type: 'C', color: 'W', value: 9 }, + { square: 'F4', type: 'T', color: 'W', value: 20 }, + // Black attackers + { square: 'E6', type: 'S', color: 'B', value: 36 }, + ] + + // Example: Arithmetic harmony setup + const harmonySetupExample: ExamplePiece[] = [ + // White pieces forming arithmetic progression: 6, 9, 12 + { square: 'E6', type: 'C', color: 'W', value: 6 }, + { square: 'F6', type: 'C', color: 'W', value: 9 }, + { square: 'G6', type: 'T', color: 'W', value: 12 }, + ] + + // Example: Exposed pyramid (common mistake) + const exposedPyramidExample: ExamplePiece[] = [ + // White pyramid alone in Black territory + { square: 'E7', type: 'P', color: 'W', value: 91 }, + // Black pieces that can capture it + { square: 'D7', type: 'S', color: 'B', value: 81 }, + { square: 'F7', type: 'C', color: 'B', value: 10 }, + ] + + // Example: Defensive mistake - pieces too close + const defensiveMistakeExample: ExamplePiece[] = [ + // White pieces clustered together (vulnerable to same attack) + { square: 'E4', type: 'C', color: 'W', value: 25 }, + { square: 'F4', type: 'C', color: 'W', value: 25 }, + { square: 'G4', type: 'C', color: 'W', value: 25 }, + // Black piece that threatens all three + { square: 'E5', type: 'C', color: 'B', value: 25 }, + ] + + // Example: Tempo play with positional sacrifice + const tempoExample: ExamplePiece[] = [ + // White sacrifices a low-value piece to gain better position + { square: 'E5', type: 'C', color: 'W', value: 4 }, // Sacrifice target + { square: 'G3', type: 'P', color: 'W', value: 36 }, // Pyramid advancing + // Black pieces + { square: 'D6', type: 'C', color: 'B', value: 4 }, // Will capture but lose tempo + { square: 'F7', type: 'S', color: 'B', value: 49 }, + ] + + return ( +
+

+ {t('strategy.title')} +

+

+ {t('strategy.intro')} +

+ + {/* Opening Principles */} +

+ {t('strategy.openingPrinciples.title')} +

+ +
+
+

+ {t('strategy.openingPrinciples.controlCenter.title')} +

+

+ {t('strategy.openingPrinciples.controlCenter.desc')} +

+
+
+

+ {t('strategy.openingPrinciples.developCircles.title')} +

+

+ {t('strategy.openingPrinciples.developCircles.desc')} +

+
+
+

+ {t('strategy.openingPrinciples.protectPyramid.title')} +

+

+ {t('strategy.openingPrinciples.protectPyramid.desc')} +

+
+
+

+ {t('strategy.openingPrinciples.knowNumbers.title')} +

+

+ {t('strategy.openingPrinciples.knowNumbers.desc')} +

+
+
+ + {/* Opening Example */} +
+

+ Example: Good Opening Position +

+
+ +
+

+ White controls the center with mobile pieces creating flexible capture opportunities +

+
+ + {/* Mid-Game Tactics */} +

+ {t('strategy.midGame.title')} +

+ +
+

+ {t('strategy.midGame.helperNetworks.title')} +

+

+ {t('strategy.midGame.helperNetworks.desc')} +

+
+ +
+

+ {t('strategy.midGame.createThreats.title')} +

+

+ {t('strategy.midGame.createThreats.desc')} +

+
+ +
+

+ {t('strategy.midGame.thinkDefensively.title')} +

+

+ {t('strategy.midGame.thinkDefensively.desc')} +

+
+ +
+

+ {t('strategy.midGame.exchangeWhenAhead.title')} +

+

+ {t('strategy.midGame.exchangeWhenAhead.desc')} +

+
+ + {/* Helper Network Example */} +
+

+ Example: Helper Network +

+
+ +
+

+ White pieces 4, 5, 6 form a helper network that can capture Black's 9 (4+5=9) +

+
+ + {/* Defensive Positioning Example */} +
+

+ Example: Defensive Positioning +

+
+ +
+

+ White Pyramid protected by supporting pieces +

+
+ + {/* Paths to Victory */} +

+ {t('strategy.victoryPaths.title')} +

+ +
+

+ {t('strategy.victoryPaths.harmony.title')} +

+

+ {t('strategy.victoryPaths.harmony.desc')} +

+
    +
  • +
  • +
  • +
+
+ +
+

+ {t('strategy.victoryPaths.exhaustion.title')} +

+

+ {t('strategy.victoryPaths.exhaustion.desc')} +

+
+ +
+

+ {t('strategy.victoryPaths.points.title')} +

+

+ {t('strategy.victoryPaths.points.desc')} +

+
+ + {/* Harmony Setup Example */} +
+

+ Example: Arithmetic Harmony Setup +

+
+ +
+

+ White pieces 6, 9, 12 in enemy territory form an arithmetic progression (difference = 3) +

+
+ + {/* Common Mistakes */} +
+

+ {t('strategy.commonMistakes.title')} +

+
    +
  • +
  • +
  • +
  • +
+
+ + {/* Exposed Pyramid Example */} +
+

+ Example: Exposed Pyramid +

+
+ +
+

+ White Pyramid alone in enemy territory is vulnerable to capture +

+
+ + {/* Defensive Mistake Example */} +
+

+ Example: Pieces Too Close +

+
+ +
+

+ White pieces clustered together are all vulnerable to the same Black attacker +

+
+ + {/* Advanced Concepts */} +

+ {t('strategy.advanced.title')} +

+ +
+

+ {t('strategy.advanced.sacrifices.title')} +

+

+ {t('strategy.advanced.sacrifices.desc')} +

+
+ +
+

+ {t('strategy.advanced.pyramidFaces.title')} +

+

+ {t('strategy.advanced.pyramidFaces.desc')} +

+
+ +
+

+ {t('strategy.advanced.tempo.title')} +

+

+ {t('strategy.advanced.tempo.desc')} +

+
+ + {/* Tempo Example */} +
+

+ Example: Tempo Play +

+
+ +
+

+ White sacrifices a low-value piece to gain tempo and advance the Pyramid +

+
+
+ ) +}