feat: add difficulty selector to example app
Add interactive difficulty selection when game is idle: Example App Changes: - example/src/App.tsx: Add difficulty state and radio group - Import useState and Difficulty type - Radio buttons for Easy/Medium/Hard - Only visible when gameStatus === 'waiting' - Updates difficulty state on selection - Passes selected difficulty to useGame Core Changes: - src/useGame.ts: Respect difficulty changes - Add difficulty to useEffect dependencies - Regenerates board when difficulty changes UX Flow: 1. User sees difficulty selector on idle screen 2. Selects difficulty (easy/medium/hard) 3. Presses Space to start 4. Puzzle generated with selected difficulty 5. On quit, returns to selector with last selection Cell Counts: - Easy: 40 empty cells (~41 givens) - Medium: 50 empty cells (~31 givens) - Hard: 60 empty cells (~21 givens)
This commit is contained in:
+48
-1
@@ -1,9 +1,12 @@
|
|||||||
|
import { useState } from "react";
|
||||||
import { useGame } from "../../src/useGame";
|
import { useGame } from "../../src/useGame";
|
||||||
import { useKeyBindings } from "./useKeyBindings";
|
import { useKeyBindings } from "./useKeyBindings";
|
||||||
|
import type { Difficulty } from "../../src/types";
|
||||||
import '../../src/game.css';
|
import '../../src/game.css';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const gameManager = useGame({ difficulty: 'medium' }, useKeyBindings);
|
const [difficulty, setDifficulty] = useState<Difficulty>('medium');
|
||||||
|
const gameManager = useGame({ difficulty }, useKeyBindings);
|
||||||
const { containerRef, gameStatus, scoreManager } = gameManager;
|
const { containerRef, gameStatus, scoreManager } = gameManager;
|
||||||
const { timeValue, keystrokes, finalScore } = scoreManager;
|
const { timeValue, keystrokes, finalScore } = scoreManager;
|
||||||
|
|
||||||
@@ -17,6 +20,50 @@ function App() {
|
|||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center justify-around min-h-[100vh]">
|
<div className="flex flex-col items-center justify-around min-h-[100vh]">
|
||||||
<h1 className="text-6xl">VIMazing vim-sudoku example</h1>
|
<h1 className="text-6xl">VIMazing vim-sudoku example</h1>
|
||||||
|
|
||||||
|
{gameStatus === "waiting" && (
|
||||||
|
<div className="mx-auto my-4 w-fit bg-muted rounded-lg p-4">
|
||||||
|
<div className="text-center mb-4">
|
||||||
|
<div className="text-muted-foreground mb-2">Select Difficulty</div>
|
||||||
|
<div className="flex gap-4 justify-center">
|
||||||
|
<label className="flex items-center gap-2 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="difficulty"
|
||||||
|
value="easy"
|
||||||
|
checked={difficulty === 'easy'}
|
||||||
|
onChange={(e) => setDifficulty(e.target.value as Difficulty)}
|
||||||
|
className="cursor-pointer"
|
||||||
|
/>
|
||||||
|
<span>Easy</span>
|
||||||
|
</label>
|
||||||
|
<label className="flex items-center gap-2 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="difficulty"
|
||||||
|
value="medium"
|
||||||
|
checked={difficulty === 'medium'}
|
||||||
|
onChange={(e) => setDifficulty(e.target.value as Difficulty)}
|
||||||
|
className="cursor-pointer"
|
||||||
|
/>
|
||||||
|
<span>Medium</span>
|
||||||
|
</label>
|
||||||
|
<label className="flex items-center gap-2 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="difficulty"
|
||||||
|
value="hard"
|
||||||
|
checked={difficulty === 'hard'}
|
||||||
|
onChange={(e) => setDifficulty(e.target.value as Difficulty)}
|
||||||
|
className="cursor-pointer"
|
||||||
|
/>
|
||||||
|
<span>Hard</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="mx-auto my-4 w-fit bg-muted rounded-lg p-4">
|
<div className="mx-auto my-4 w-fit bg-muted rounded-lg p-4">
|
||||||
{(gameStatus === "started" || gameStatus === "game-won") && (
|
{(gameStatus === "started" || gameStatus === "game-won") && (
|
||||||
<div className="flex gap-8 text-sm font-mono items-center">
|
<div className="flex gap-8 text-sm font-mono items-center">
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ export function useGame(options: GameOptions = {}, platformHook?: unknown): Game
|
|||||||
} else if (gameStatus === 'waiting') {
|
} else if (gameStatus === 'waiting') {
|
||||||
renderBoard();
|
renderBoard();
|
||||||
}
|
}
|
||||||
}, [gameStatus]);
|
}, [gameStatus, difficulty]);
|
||||||
|
|
||||||
const gameManager: GameManager = {
|
const gameManager: GameManager = {
|
||||||
containerRef,
|
containerRef,
|
||||||
|
|||||||
Reference in New Issue
Block a user