| 'use client'; |
|
|
| import { useState } from 'react'; |
| import { Check, X, Calculator } from 'lucide-react'; |
|
|
| const operations = ['+', '-', '*', '/'] as const; |
| type Operation = typeof operations[number]; |
|
|
| const difficulties = ['easy', 'medium', 'hard'] as const; |
| type Difficulty = typeof difficulties[number]; |
|
|
| interface Question { |
| num1: number; |
| num2: number; |
| operation: Operation; |
| answer: number; |
| } |
|
|
| const generateQuestion = (difficulty: Difficulty): Question => { |
| const operation = operations[Math.floor(Math.random() * operations.length)]; |
| let num1 = 0; |
| let num2 = 0; |
|
|
| switch (difficulty) { |
| case 'easy': |
| num1 = Math.floor(Math.random() * 10) + 1; |
| num2 = Math.floor(Math.random() * 10) + 1; |
| break; |
| case 'medium': |
| num1 = Math.floor(Math.random() * 50) + 1; |
| num2 = Math.floor(Math.random() * 50) + 1; |
| break; |
| case 'hard': |
| num1 = Math.floor(Math.random() * 100) + 1; |
| num2 = Math.floor(Math.random() * 100) + 1; |
| break; |
| } |
|
|
| |
| if (operation === '/') { |
| |
| num2 = num2 === 0 ? 1 : num2; |
| |
| if (difficulty === 'easy' || difficulty === 'medium') { |
| num1 = num2 * Math.floor(Math.random() * 10) + 1; |
| } |
| } |
|
|
| const answer = eval(`${num1} ${operation} ${num2}`); |
| |
| const roundedAnswer = Number.isInteger(answer) ? answer : parseFloat(answer.toFixed(2)); |
|
|
| return { |
| num1, |
| num2, |
| operation, |
| answer: roundedAnswer, |
| }; |
| }; |
|
|
| interface CalculatorComponentProps { |
| onClose: () => void; |
| } |
|
|
| const CalculatorComponent: React.FC<CalculatorComponentProps> = ({ onClose }) => { |
| const [display, setDisplay] = useState('0'); |
| const [firstOperand, setFirstOperand] = useState<number | null>(null); |
| const [operator, setOperator] = useState<string | null>(null); |
| const [waitingForSecondOperand, setWaitingForSecondOperand] = useState(false); |
|
|
| const inputDigit = (digit: string) => { |
| if (waitingForSecondOperand) { |
| setDisplay(digit); |
| setWaitingForSecondOperand(false); |
| } else { |
| setDisplay(display === '0' ? digit : display + digit); |
| } |
| }; |
|
|
| const inputDecimal = () => { |
| if (waitingForSecondOperand) { |
| setDisplay('0.'); |
| setWaitingForSecondOperand(false); |
| return; |
| } |
| if (!display.includes('.')) { |
| setDisplay(display + '.'); |
| } |
| }; |
|
|
| const clear = () => { |
| setDisplay('0'); |
| setFirstOperand(null); |
| setOperator(null); |
| setWaitingForSecondOperand(false); |
| }; |
|
|
| const calculate = (firstOp: number, secondOp: number, op: string): number | string => { |
| switch (op) { |
| case '+': return firstOp + secondOp; |
| case '-': return firstOp - secondOp; |
| case '*': return firstOp * secondOp; |
| case '/': return secondOp === 0 ? 'Error' : firstOp / secondOp; |
| default: return secondOp; |
| } |
| }; |
|
|
| const performOperation = (nextOperator: string) => { |
| const inputValue = parseFloat(display); |
| |
| if (nextOperator === '=') { |
| if (operator && firstOperand !== null) { |
| const result = calculate(firstOperand, inputValue, operator); |
| setDisplay(String(result)); |
| setFirstOperand(null); |
| setOperator(null); |
| setWaitingForSecondOperand(false); |
| } |
| } else { |
| if (firstOperand === null) { |
| setFirstOperand(inputValue); |
| } else if (operator) { |
| const result = calculate(firstOperand, inputValue, operator); |
| setDisplay(String(result)); |
| setFirstOperand(typeof result === 'number' ? result : null); |
| } |
| |
| setWaitingForSecondOperand(true); |
| setOperator(nextOperator); |
| } |
| }; |
|
|
| return ( |
| <div className="bg-gray-100 p-4 rounded-lg shadow-lg w-full max-w-md"> |
| <div className="flex justify-between items-center mb-4"> |
| <h2 className="text-xl font-bold">Calculator</h2> |
| <button onClick={onClose} className="text-gray-600 hover:text-gray-800"> |
| <X className="w-6 h-6" /> |
| </button> |
| </div> |
| <div className="bg-gray-200 p-4 rounded mb-4 text-right text-2xl font-bold"> |
| {display} |
| </div> |
| <div className="grid grid-cols-4 gap-2"> |
| <button onClick={clear} className="p-3 bg-gray-300 hover:bg-gray-400 rounded">C</button> |
| <button onClick={() => performOperation('/')} className="p-3 bg-gray-300 hover:bg-gray-400 rounded">/</button> |
| <button onClick={() => performOperation('*')} className="p-3 bg-gray-300 hover:bg-gray-400 rounded">*</button> |
| <button onClick={() => performOperation('-')} className="p-3 bg-gray-300 hover:bg-gray-400 rounded">-</button> |
| |
| <button onClick={() => inputDigit('7')} className="p-3 bg-white hover:bg-gray-100 rounded">7</button> |
| <button onClick={() => inputDigit('8')} className="p-3 bg-white hover:bg-gray-100 rounded">8</button> |
| <button onClick={() => inputDigit('9')} className="p-3 bg-white hover:bg-gray-100 rounded">9</button> |
| <button onClick={() => performOperation('+')} className="p-3 bg-gray-300 hover:bg-gray-400 rounded">+</button> |
| |
| <button onClick={() => inputDigit('4')} className="p-3 bg-white hover:bg-gray-100 rounded">4</button> |
| <button onClick={() => inputDigit('5')} className="p-3 bg-white hover:bg-gray-100 rounded">5</button> |
| <button onClick={() => inputDigit('6')} className="p-3 bg-white hover:bg-gray-100 rounded">6</button> |
| <button onClick={() => performOperation('=')} className="p-3 bg-blue-500 hover:bg-blue-600 text-white rounded row-span-2">=</button> |
| |
| <button onClick={() => inputDigit('1')} className="p-3 bg-white hover:bg-gray-100 rounded">1</button> |
| <button onClick={() => inputDigit('2')} className="p-3 bg-white hover:bg-gray-100 rounded">2</button> |
| <button onClick={() => inputDigit('3')} className="p-3 bg-white hover:bg-gray-100 rounded">3</button> |
| |
| <button onClick={() => inputDigit('0')} className="p-3 bg-white hover:bg-gray-100 rounded col-span-2">0</button> |
| <button onClick={inputDecimal} className="p-3 bg-white hover:bg-gray-100 rounded">.</button> |
| </div> |
| </div> |
| ); |
| }; |
|
|
| const MathQuizApp: React.FC = () => { |
| const [question, setQuestion] = useState<Question>(generateQuestion('easy')); |
| const [userAnswer, setUserAnswer] = useState(''); |
| const [result, setResult] = useState(''); |
| const [score, setScore] = useState(0); |
| const [wrongAnswers, setWrongAnswers] = useState(0); |
| const [difficulty, setDifficulty] = useState<Difficulty>('easy'); |
| const [showCalculator, setShowCalculator] = useState(false); |
|
|
| const handleSubmit = (e: React.FormEvent) => { |
| e.preventDefault(); |
| |
| |
| const parsedAnswer = parseFloat(userAnswer); |
| |
| |
| const isCorrect = Math.abs(parsedAnswer - question.answer) < 0.001; |
| |
| if (isCorrect) { |
| setResult('Correct!'); |
| setScore(score + 1); |
| } else { |
| setResult(`Incorrect. The correct answer is ${question.answer}.`); |
| setWrongAnswers(wrongAnswers + 1); |
| } |
| |
| setUserAnswer(''); |
| setQuestion(generateQuestion(difficulty)); |
| }; |
|
|
| const handleDifficultyChange = (e: React.ChangeEvent<HTMLSelectElement>) => { |
| const newDifficulty = e.target.value as Difficulty; |
| setDifficulty(newDifficulty); |
| setQuestion(generateQuestion(newDifficulty)); |
| setScore(0); |
| setWrongAnswers(0); |
| setResult(''); |
| }; |
|
|
| return ( |
| <div className="bg-gray-50 min-h-screen flex items-center justify-center p-4"> |
| <div className="max-w-4xl w-full mx-auto bg-white rounded-lg shadow-md p-8"> |
| <div className="flex justify-between items-center mb-6"> |
| <h1 className="text-4xl font-bold">Math Quiz App</h1> |
| <button |
| onClick={() => setShowCalculator(!showCalculator)} |
| className="flex items-center gap-2 bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg" |
| > |
| <Calculator className="w-5 h-5" /> |
| {showCalculator ? 'Hide Calculator' : 'Show Calculator'} |
| </button> |
| </div> |
| <div className="grid grid-cols-1 md:grid-cols-2 gap-8"> |
| <div className="space-y-6"> |
| <form onSubmit={handleSubmit} className="space-y-6"> |
| <div className="flex flex-col items-center gap-6"> |
| <div className="flex gap-8 items-center justify-center"> |
| <div className="text-xl font-bold">Correct: {score}</div> |
| <div className="text-xl font-bold text-red-500">Wrong: {wrongAnswers}</div> |
| </div> |
| <select |
| value={difficulty} |
| onChange={handleDifficultyChange} |
| className="bg-gray-50 border border-gray-300 text-gray-900 text-lg rounded-lg focus:ring-blue-500 focus:border-blue-500 p-2.5 w-48 text-center" |
| > |
| {difficulties.map((diff) => ( |
| <option key={diff} value={diff}> |
| {diff.charAt(0).toUpperCase() + diff.slice(1)} |
| </option> |
| ))} |
| </select> |
| </div> |
| <div className="text-center"> |
| <p className="text-3xl font-bold mb-6"> |
| What is {question.num1} {question.operation} {question.num2}? |
| </p> |
| <input |
| type="number" |
| value={userAnswer} |
| onChange={(e) => setUserAnswer(e.target.value)} |
| className="bg-gray-50 border border-gray-300 text-gray-900 text-xl rounded-lg focus:ring-blue-500 focus:border-blue-500 p-4 w-full text-center" |
| step="any" |
| /> |
| </div> |
| <div className="text-center"> |
| <button |
| type="submit" |
| className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-lg px-8 py-3 text-center" |
| > |
| Submit |
| </button> |
| </div> |
| {result && ( |
| <p |
| className={`text-xl font-bold text-center ${ |
| result === 'Correct!' ? 'text-green-500' : 'text-red-500' |
| }`} |
| > |
| {result}{' '} |
| {result === 'Correct!' ? ( |
| <Check className="inline-block w-6 h-6" /> |
| ) : ( |
| <X className="inline-block w-6 h-6" /> |
| )} |
| </p> |
| )} |
| </form> |
| </div> |
| |
| {showCalculator && ( |
| <div className="flex justify-center"> |
| <CalculatorComponent onClose={() => setShowCalculator(false)} /> |
| </div> |
| )} |
| </div> |
| </div> |
| </div> |
| ); |
| }; |
|
|
| export default MathQuizApp; |