klasa 3 – świąteczna gra

import React, { useState, useEffect } from ‘react’; import { Dice5, Trophy, Timer, Milk, Calculator, BookOpen, Snowflake, TreePine, Users, ArrowRight, XCircle, CheckCircle } from ‘lucide-react’; const ChristmasMathGame = () => { // — KONFIGURACJA I STAN GRY — const [gameState, setGameState] = useState(‘setup’); // setup, playing, question, win const [teams, setTeams] = useState([]); const [currentTeamIndex, setCurrentTeamIndex] = useState(0); const [diceValue, setDiceValue] = useState(1); const [isRolling, setIsRolling] = useState(false); const [currentQuestion, setCurrentQuestion] = useState(null); const [feedback, setFeedback] = useState(null); // ‘correct’ | ‘wrong’ const [targetPosition, setTargetPosition] = useState(0); const [winner, setWinner] = useState(null); // Stałe planszy – 40 PÓL (Dłuższa gra) const BOARD_SIZE = 40; // Dostępne awatary/drużyny const AVAILABLE_TEAMS = [ { id: ‘reindeers’, name: ‘Renifery’, color: ‘bg-orange-500’, icon: ‘🦌’ }, { id: ‘elves’, name: ‘Elfy’, color: ‘bg-green-600’, icon: ‘🧝’ }, { id: ‘snowmen’, name: ‘Bałwanki’, color: ‘bg-cyan-400’, icon: ‘⛄’ }, { id: ‘penguins’, name: ‘Pingwiny’, color: ‘bg-purple-500’, icon: ‘🐧’ }, ]; // — GENERATOR ZADAŃ (POZIOM KLASY 3 – DOSTOSOWANY) — const generateQuestion = () => { const types = [‘calc3’, ‘multi_simple’, ‘word_simple’, ‘measure_simple’, ‘time_simple’]; const type = types[Math.floor(Math.random() * types.length)]; let q = { text: ”, options: [], correct: ” }; // Helper do losowania const rand = (min, max) => Math.floor(Math.random() * (max – min + 1)) + min; const shuffle = (array) => array.sort(() => Math.random() – 0.5); if (type === ‘calc3’) { // Dodawanie/Odejmowanie 3 liczb w zakresie 100 const operation = Math.random() > 0.5 ? ‘sum’ : ‘sub’; if (operation === ‘sum’) { // Suma 3 składników do 100 const a = rand(10, 40); const b = rand(10, 30); // Trzecia liczba tak, żeby suma nie przekroczyła 100 const maxC = 100 – (a + b); const c = rand(5, maxC > 5 ? maxC : 5); const res = a + b + c; q.text = `Dodawanie: ${a} + ${b} + ${c} = ?`; q.correct = res.toString(); q.options = shuffle([res, res + 10, res – 2, res + 5].map(String)); } else { // Odejmowanie od liczby <= 100 const start = rand(60, 100); const sub1 = rand(10, 30); const sub2 = rand(5, 20); // Zabezpieczenie przed wynikiem ujemnym if (start - sub1 - sub2 < 0) { // Fallback do prostego odejmowania const res = start - sub1; q.text = `Odejmowanie: ${start} - ${sub1} = ?`; q.correct = res.toString(); q.options = shuffle([res, res+2, res-2, res+10].map(String)); } else { const res = start - sub1 - sub2; q.text = `Odejmowanie: ${start} - ${sub1} - ${sub2} = ?`; q.correct = res.toString(); q.options = shuffle([res, res + 5, res - 5, res + 10].map(String)); } } } else if (type === 'multi_simple') { // Tabliczka mnożenia liczb jednocyfrowych (2-9) const a = rand(2, 9); const b = rand(2, 9); const res = a * b; q.text = `Ile to jest: ${a} · ${b} = ?`; q.correct = res.toString(); // Generowanie zmyłek typowych dla błędów w tabliczce q.options = shuffle([ res.toString(), (res + a).toString(), (res - b).toString(), (res > 10 ? res + 5 : res + 2).toString() ]); } else if (type === ‘measure_simple’) { // Litry, pół litra – proste const tasks = [ { t: “Ile półlitrowych słoików potrzeba, żeby zmieścić 2 litry kompotu?”, a: “4”, o: [“4”, “2”, “6”, “8”] }, { t: “Mikołaj wypił pół litra mleka, a Elf ćwierć litra. Kto wypił więcej?”, a: “Mikołaj”, o: [“Mikołaj”, “Elf”, “Wypili tyle samo”, “Nie wiadomo”] }, { t: “W dzbanku były 3 litry soku. Dzieci wypiły 1 litr. Ile zostało?”, a: “2 litry”, o: [“2 litry”, “1 litr”, “Półtora litra”, “2 i pół litra”] }, { t: “Jeden litr to ile ćwierćlitrowych kubków?”, a: “4 kubki”, o: [“4 kubki”, “2 kubki”, “3 kubki”, “5 kubków”] } ]; const p = tasks[rand(0, tasks.length-1)]; q.text = p.t; q.correct = p.a; q.options = shuffle(p.o); } else if (type === ‘time_simple’) { // Zegar – proste obliczenia const hour = rand(1, 10); if (Math.random() > 0.5) { q.text = `Teraz jest godzina ${hour}:00. Za godzinę przyjdzie Mikołaj. Która to będzie godzina?`; q.correct = `${hour + 1}:00`; q.options = shuffle([`${hour + 1}:00`, `${hour}:30`, `${hour + 2}:00`, `${hour}:15`]); } else { q.text = `Film o reniferach trwa 30 minut. Zaczął się o ${hour}:30. O której się skończy?`; q.correct = `${hour + 1}:00`; q.options = shuffle([`${hour + 1}:00`, `${hour}:50`, `${hour}:00`, `${hour + 1}:30`]); } } else if (type === ‘word_simple’) { // Proste zadania tekstowe w tematyce świątecznej (zakres 100) const problems = [ { t: “Na choince wisi 30 czerwonych bombek i 20 złotych. Ile bombek wisi razem?”, a: “50”, o: [“50”, “40”, “60”, “35”] }, { t: “Mikołaj miał 60 prezentów. Rozdał dzieciom 20. Ile mu zostało?”, a: “40”, o: [“40”, “30”, “50”, “80”] }, { t: “Jeden pierniczek kosztuje 2 złote. Ile zapłacisz za 8 pierniczków?”, a: “16 zł”, o: [“16 zł”, “10 zł”, “18 zł”, “14 zł”] }, { t: “W pudełku jest 10 czekoladek. Mama kupiła 3 takie pudełka. Ile jest razem czekoladek?”, a: “30”, o: [“30”, “13”, “20”, “40”] }, { t: “Sanie mają 2 płozy. Ile płóz ma 5 sań?”, a: “10”, o: [“10”, “5”, “12”, “8”] }, ]; const p = problems[rand(0, problems.length – 1)]; q.text = p.t; q.correct = p.a; q.options = shuffle(p.o); } return q; }; // — LOGIKA GRY — const startGame = (selectedTeamCount) => { const newTeams = AVAILABLE_TEAMS.slice(0, selectedTeamCount).map(t => ({ …t, pos: 0, score: 0 })); setTeams(newTeams); setGameState(‘playing’); setCurrentTeamIndex(0); }; const rollDice = () => { if (isRolling) return; setIsRolling(true); // Animacja kostki let rolls = 0; const interval = setInterval(() => { setDiceValue(Math.floor(Math.random() * 6) + 1); rolls++; if (rolls > 10) { clearInterval(interval); const finalVal = Math.floor(Math.random() * 6) + 1; setDiceValue(finalVal); setIsRolling(false); handleMoveAttempt(finalVal); } }, 100); }; const handleMoveAttempt = (rolled) => { const currentTeam = teams[currentTeamIndex]; const newPos = currentTeam.pos + rolled; // Sprawdzenie czy wygrał if (newPos >= BOARD_SIZE) { setTargetPosition(BOARD_SIZE); setCurrentQuestion(generateQuestion()); setGameState(‘question’); } else { setTargetPosition(newPos); setCurrentQuestion(generateQuestion()); setGameState(‘question’); } }; const handleAnswer = (answer) => { if (answer === currentQuestion.correct) { setFeedback(‘correct’); } else { setFeedback(‘wrong’); } }; const closeQuestion = () => { const isCorrect = feedback === ‘correct’; setFeedback(null); setCurrentQuestion(null); const newTeams = […teams]; if (isCorrect) { newTeams[currentTeamIndex].pos = targetPosition; // Sprawdź czy wygrana if (targetPosition >= BOARD_SIZE) { setTeams(newTeams); setWinner(newTeams[currentTeamIndex]); setGameState(‘win’); return; } } else { // Błędna odpowiedź – zostajemy na starym miejscu } setTeams(newTeams); setGameState(‘playing’); // Następna tura setCurrentTeamIndex((prev) => (prev + 1) % teams.length); }; // — KOMPONENTY WIDOKU — const SetupScreen = () => (

Wyścig do Choinki

Gra matematyczna dla klasy 3. Pomóż drużynie dotrzeć do mety rozwiązując świąteczne zadania!

{[2, 3, 4].map(num => ( ))}
Zadania: Dodawanie/Odejmowanie do 100, Mnożenie, Czas, Litry.
); const Board = () => { const tiles = Array.from({ length: BOARD_SIZE + 1 }, (_, i) => i); return (
{tiles.map((num) => { const isStart = num === 0; const isFinish = num === BOARD_SIZE; const teamsHere = teams.filter(t => t.pos === num); let tileColor = ‘bg-white border-red-200’; if (isStart || isFinish) tileColor = ‘bg-yellow-200 border-yellow-500’; else if (num % 2 === 0) tileColor = ‘bg-white border-green-200’; else tileColor = ‘bg-red-50 border-red-200’; const isSpecial = !isStart && !isFinish && num % 5 === 0; return (
{num === 0 ? ‘START’ : num === BOARD_SIZE ? ‘META’ : num} {isFinish && } {isStart &&
🏠
} {isSpecial && }
{teamsHere.map(team => (
{team.icon}
))}
); })}
); }; const GameControls = () => { const activeTeam = teams[currentTeamIndex]; return (
{activeTeam.icon}

Teraz gra

{activeTeam.name}

{diceValue}
); }; const QuestionModal = () => { if (!currentQuestion) return null; const activeTeam = teams[currentTeamIndex]; return (

Pytanie dla: {activeTeam.name}

{activeTeam.icon}
{!feedback ? ( <>

{currentQuestion.text}

{currentQuestion.options.map((opt, idx) => ( ))}
) : (
{feedback === ‘correct’ ? (

Brawo!

Zostajecie na nowym polu.

) : (

Niestety…

Prawidłowa odpowiedź to: {currentQuestion.correct}

Wracacie na poprzednie pole.

)}
)}
); }; const WinnerScreen = () => (

Wygrana!

Wygrywa drużyna:
{winner.icon} {winner.name}
); return (
{gameState !== ‘setup’ && Array.from({ length: 15 }).map((_, i) => (
))} {gameState === ‘setup’ && } {gameState === ‘playing’ || gameState === ‘question’ ? ( <>

Wyścig do Choinki

{gameState === ‘question’ && } ) : null} {gameState === ‘win’ && }
); }; export default ChristmasMathGame;