diff --git a/src/gameInfo.ts b/src/gameInfo.ts new file mode 100644 index 0000000..a4b7685 --- /dev/null +++ b/src/gameInfo.ts @@ -0,0 +1,158 @@ +export const gameInfo = { + name: 'VIM Sudoku', + description: 'Classic Sudoku puzzle with VIM-style modal editing', + + controls: { + navigation: [ + { keys: 'hjkl', description: 'Move cursor left/down/up/right' }, + { keys: '5j, 10l', description: 'Move with count (5 down, 10 right)' }, + { keys: '0 or ^', description: 'Jump to start of row' }, + { keys: '$', description: 'Jump to end of row' }, + { keys: 'gg', description: 'Jump to top of board' }, + { keys: 'G', description: 'Jump to bottom of board' }, + { keys: '.', description: 'Repeat last motion' }, + ], + + editing: [ + { keys: 'i', description: 'Insert digit (works on empty cells only)' }, + { keys: 'r', description: 'Replace digit (works on user-entered cells only)' }, + { keys: 'c', description: 'Change digit (works on user-entered cells only)' }, + { keys: '1-9', description: 'Enter digit (while in edit mode)' }, + { keys: 'Escape', description: 'Exit edit mode to normal mode' }, + ], + + deletion: [ + { keys: 'x', description: 'Delete digit from user-entered cell' }, + { keys: 'd', description: 'Delete digit from user-entered cell' }, + { keys: 'Delete', description: 'Delete digit from user-entered cell' }, + { keys: 'Backspace', description: 'Delete digit (only in edit mode)' }, + ], + + hints: [ + { keys: 'Shift+H', description: 'Request hint (costs 25/50/100 points by difficulty)' }, + ], + + game: [ + { keys: 'Space', description: 'Start new game (when waiting)' }, + { keys: 'q', description: 'Quit game' }, + { keys: 'p', description: 'Pause/unpause game' }, + ], + }, + + rules: { + cellTypes: [ + { type: 'Empty', canEdit: 'i only', canReplace: 'no', canDelete: 'no', description: 'Empty cell ready for input' }, + { type: 'User-entered', canEdit: 'r or c only', canReplace: 'yes', canDelete: 'yes', description: 'Digit you entered' }, + { type: 'Given', canEdit: 'no', canReplace: 'no', canDelete: 'no', description: 'Original puzzle digit (locked)' }, + ], + + modes: [ + { + name: 'Normal Mode', + indicator: 'Blue outline on cursor', + description: 'Navigate with hjkl, access all commands', + }, + { + name: 'Edit Mode (i)', + indicator: 'Yellow pulsing glow on cursor', + description: 'Type multiple digits, press Escape to exit', + }, + { + name: 'Edit Mode (r/c)', + indicator: 'Yellow pulsing glow on cursor', + description: 'Type one digit, auto-exits to normal mode', + }, + ], + + visualFeedback: [ + { indicator: 'Blue outline', meaning: 'Current cell in normal mode' }, + { indicator: 'Yellow pulsing glow', meaning: 'Current cell in edit mode' }, + { indicator: 'Red flash (500ms)', meaning: 'Invalid move or action' }, + { indicator: 'Red flash + background (1s)', meaning: 'Hint: this cell is incorrect' }, + { indicator: 'Green flash + background (1s)', meaning: 'Hint: showing correct digit' }, + ], + }, + + scoring: { + formula: 'Base Score = 1000 - (time penalty) - (keystroke penalty) - (hint penalty)', + multiplier: 'Final Score = min(1000, Base Score × difficulty multiplier)', + range: '0 - 1000 points', + + penalties: [ + { factor: 'Time', formula: 'seconds / 10', example: '60 seconds = -6 points' }, + { factor: 'Keystrokes', formula: 'total keys / 2', example: '100 keys = -50 points' }, + { factor: 'Hints (Easy)', formula: 'hints × 25', example: '3 hints = -75 points' }, + { factor: 'Hints (Medium)', formula: 'hints × 50', example: '3 hints = -150 points' }, + { factor: 'Hints (Hard)', formula: 'hints × 100', example: '3 hints = -300 points' }, + ], + + multipliers: [ + { difficulty: 'Easy', multiplier: '1.0x', description: 'No bonus' }, + { difficulty: 'Medium', multiplier: '1.5x', description: 'Can exceed base 1000, capped at 1000' }, + { difficulty: 'Hard', multiplier: '2.0x', description: 'Can exceed base 1000, capped at 1000' }, + ], + + examples: [ + { + difficulty: 'Easy', + time: '30 seconds', + keystrokes: 50, + hints: 0, + calculation: '1000 - 3 - 25 - 0 = 972 × 1.0', + score: '972 / 1000', + }, + { + difficulty: 'Hard', + time: '120 seconds', + keystrokes: 150, + hints: 2, + calculation: '1000 - 12 - 75 - 200 = 713 × 2.0', + score: '1000 / 1000 (capped)', + }, + ], + }, + + gameOver: { + conditions: [ + { + type: 'Time Limit', + trigger: '10 minutes (600 seconds) by default', + configurable: true, + message: "Time's up!", + }, + { + type: 'Hint Limit', + trigger: '500 points total hint penalty', + breakdown: 'Easy: 20 hints | Medium: 10 hints | Hard: 5 hints', + configurable: false, + message: 'Too many hints!', + }, + ], + }, + + hints: { + description: 'Press Shift+H to get help when stuck', + priority: [ + { + level: 1, + behavior: 'Show Incorrect Cell', + description: 'Randomly select a user-entered cell with wrong value and flash it red for 1 second', + reveals: 'Location of error (not the correct digit)', + }, + { + level: 2, + behavior: 'Show Correct Digit', + description: 'If no errors exist, show correct digit for a random empty cell with green flash for 1 second', + reveals: 'Correct digit temporarily (you must remember it)', + }, + ], + cost: 'Deducted from final score based on difficulty', + limit: 'Game-over after 500 points of penalties', + }, + + objective: 'Fill all empty cells with digits 1-9 such that each row, column, and 3×3 box contains each digit exactly once.', + + winCondition: 'All cells filled correctly (no validation enforced - trust yourself!)', +} as const; + +export type GameInfo = typeof gameInfo; diff --git a/src/index.ts b/src/index.ts index 24233b0..096a654 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,5 @@ export { useGame } from './useGame'; export { useGameStatus } from './useGameStatus'; export type { GameManager, GameOptions, GameStatus, GameStatusManager, Difficulty } from './types'; +export { gameInfo } from './gameInfo'; +export type { GameInfo } from './gameInfo';