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}
);
};
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;