diff --git a/webapp/src/App.js b/webapp/src/App.js index d6b5967e..6c9a3d1f 100644 --- a/webapp/src/App.js +++ b/webapp/src/App.js @@ -13,6 +13,7 @@ import Config from "./pages/Config/Config.js"; import Login from "./components/Login/Login.js"; import Register from "./components/Register/Register.js"; import Perfil from "./pages/Perfil/Perfil.js"; +import CalculadoraHumana from "./pages/Calculadora/Calculadora.js"; function App() { @@ -32,6 +33,7 @@ function App() { } /> } /> } /> + } /> } /> } /> } /> diff --git a/webapp/src/pages/Calculadora/Calculadora.js b/webapp/src/pages/Calculadora/Calculadora.js new file mode 100644 index 00000000..5572f7b3 --- /dev/null +++ b/webapp/src/pages/Calculadora/Calculadora.js @@ -0,0 +1,169 @@ +import React, { useState, useEffect } from "react"; +import Nav from "../../components/Nav/Nav.js"; +import Footer from "../../components/Footer/Footer.js"; +import { Link } from "react-router-dom"; +import { Box, Flex, Heading, Button, Input } from "@chakra-ui/react"; + +const generateRandomOperation = () => { + let operators = ["+", "-", "*", "/"]; + let operator = operators[Math.floor(Math.random() * operators.length)]; + let num1 = Math.floor(Math.random() * 10 + 1); + let num2 = Math.floor(Math.random() * 10 + 1); + if (operator === "/") { + let numCandidates = findDivisors(num1); + let num2 = numCandidates[Math.floor(Math.random() * numCandidates.length)]; + return `${num1} ${operator} ${num2}`; + } + + return `${num1} ${operator} ${num2}`; +}; + +function findDivisors(num) { + const divisors = []; + const sqrtNum = Math.sqrt(Math.abs(num)); + + for (let i = 1; i <= sqrtNum; i++) { + if (num % i === 0) { + divisors.push(i); + if (i !== sqrtNum) { + divisors.push(num / i); + } + } + } + + return divisors; +} + +const CalculadoraHumana = () => { + const TIME = 60; + + const [valSubmit, setValSubmit] = useState(""); + const [puntuacion, setPuntuacion] = useState(0); + const [operation, setOperation] = useState(generateRandomOperation()); + const [tiempoRestante, setTiempoRestante] = useState(TIME); + const [juegoTerminado, setJuegoTerminado] = useState(false); + const [progressPercent, setProgressPercent] = useState(100); + + useEffect(() => { + if (tiempoRestante === 0) { + setJuegoTerminado(true); + } + const timer = setInterval(() => { + setTiempoRestante((prevTiempo) => (prevTiempo <= 0 ? 0 : prevTiempo - 1)); + }, 1000); + return () => clearInterval(timer); + // eslint-disable-next-line + }, [tiempoRestante]); + + useEffect(() => { + setProgressPercent((tiempoRestante / TIME) * 100); + + const timer = setInterval(() => { + setTiempoRestante((prevTiempo) => + prevTiempo <= 0 ? 0 : prevTiempo - 0.01 + ); + }, 10); + + return () => clearInterval(timer); + // eslint-disable-next-line + }, [tiempoRestante]); + + const handleAnswer = (valSubmit) => { + setValSubmit(""); + valSubmit = Number(valSubmit); + + let evalued = eval(operation); + if (valSubmit === evalued) { + setPuntuacion(puntuacion + 1); + let newOperation = generateOperation(valSubmit); + setOperation(newOperation); + } else { + setJuegoTerminado(true); + } + }; + + const generateOperation = (valSubmit) => { + valSubmit = Number(valSubmit); + + let operators = ["+", "-", "*", "/"]; + let operator = operators[Math.floor(Math.random() * operators.length)]; + let num1 = Math.floor(Math.random() * 10 + 1); + let operation = `${valSubmit} ${operator} ${num1}`; + if (operator === "/") { + if(valSubmit === 0){ + return `${valSubmit} ${operator} ${1}`; + } + let numCandidates = findDivisors(valSubmit); + let num2 = + numCandidates[Math.floor(Math.random() * numCandidates.length)]; + return `${valSubmit} ${operator} ${num2}`; + } + return operation; + }; + + const handleRepetirJuego = () => { + setPuntuacion(0); + setTiempoRestante(60); + setJuegoTerminado(false); + setOperation(generateRandomOperation()); + }; + + const handleKeyDown = (event) => { + if (event.key === "Enter") { + handleAnswer(Number(event.target.value)); + } + }; + + return ( + <> + + + + {juegoTerminado ? ( + + ¡Juego terminado! + Tu puntuación: {puntuacion} + + Repetir Juego + + + Volver al Menú Principal + + + ) : ( + + + ¿{operation}? + + setValSubmit(e.target.value)} + onKeyDown={handleKeyDown} + /> + handleAnswer(Number(valSubmit))}> + {" "} + Enviar{" "} + + + Tiempo restante: {Math.floor(tiempoRestante)} + Puntuación: {puntuacion} + + + + + + )} + + + + > + ); +}; + +export default CalculadoraHumana; diff --git a/webapp/src/pages/Calculadora/Calculadora.test.js b/webapp/src/pages/Calculadora/Calculadora.test.js new file mode 100644 index 00000000..48042745 --- /dev/null +++ b/webapp/src/pages/Calculadora/Calculadora.test.js @@ -0,0 +1,151 @@ +import React from "react"; +import { render, screen, fireEvent, waitFor } from "@testing-library/react"; +import CalculadoraHumana from "./Calculadora"; +import { MemoryRouter } from "react-router-dom"; + +test("renders the game screen", () => { + render( + + + + ); + + // Check if the game screen is rendered + expect(screen.getByText(/¿/i)).toBeInTheDocument(); + expect(screen.getByTitle(/number/i)).toBeInTheDocument(); + expect(screen.getByRole("button", { name: /enviar/i })).toBeInTheDocument(); + expect(screen.getByText(/tiempo restante/i)).toBeInTheDocument(); + expect(screen.getByText(/puntuación/i)).toBeInTheDocument(); +}); + +test("handles correct answer", () => { + render( + + + + ); + + // Get the initial score + const initialScore = parseInt( + screen + .getByText(/puntuación: (\d+)/i) + .textContent.split(":")[1] + .trim() + ); + + // Get the initial operation + var initialOperation = screen.getByText(/(\d+)\s*([-+*/])\s*(\d+)/).textContent; + initialOperation = initialOperation.substring(1, initialOperation.length - 1); + + // Get the input field and submit button + const inputField = screen.getByTitle(/number/i); + const submitButton = screen.getByRole("button", { name: /enviar/i }); + + // Enter the correct answer and submit + fireEvent.change(inputField, { target: { value: eval(initialOperation) } }); + fireEvent.click(submitButton); + + // Check if the score has increased + var updatedScore = parseInt( + screen + .getByText(/puntuación: (\d+)/i) + .textContent.split(":")[1] + .trim() + ); + expect(updatedScore).toBe(initialScore + 1); + + // Get next operation + var nextOperation = screen.getByText(/(\d+)\s*([-+*/])\s*(\d+)/).textContent; + nextOperation = nextOperation.substring(1, nextOperation.length - 1); + + // Enter the correct answer and submit + fireEvent.change(inputField, { target: { value: eval(nextOperation) } }); + fireEvent.keyDown(inputField, { key: 'Enter', code: 'Enter' }); + + // Check if the score has increased + updatedScore = parseInt( + screen + .getByText(/puntuación: (\d+)/i) + .textContent.split(":")[1] + .trim() + ); + expect(updatedScore).toBe(initialScore + 2); +}); + +test("handles incorrect answer", () => { + render( + + + + ); + + // Get the initial score + const initialScore = parseInt( + screen + .getByText(/puntuación: (\d+)/i) + .textContent.split(":")[1] + .trim() + ); + + // Get the input field and submit button + const inputField = screen.getByTitle(/number/i); + const submitButton = screen.getByRole("button", { name: /enviar/i }); + + // Enter an incorrect answer and submit + fireEvent.change(inputField, { target: { value: 0 } }); + fireEvent.click(submitButton); + + // Check if the score remains the same + const updatedScore = parseInt( + screen + .getByText(/puntuación: (\d+)/i) + .textContent.split(":")[1] + .trim() + ); + expect(updatedScore).toBe(initialScore); +}); + +test("handles game over", () => { + render( + + + + ); + + // Get the initial score + const initialScore = parseInt( + screen + .getByText(/puntuación: (\d+)/i) + .textContent.split(":")[1] + .trim() + ); + + // Get the input field and submit button + const inputField = screen.getByTitle(/number/i); + const submitButton = screen.getByRole("button", { name: /enviar/i }); + + // Enter an incorrect answer and submit until game over + while (!screen.queryByText(/juego terminado/i)) { + fireEvent.change(inputField, { target: { value: 0 } }); + fireEvent.click(submitButton); + } + + // Check if the game over screen is rendered + expect(screen.getByText(/juego terminado/i)).toBeInTheDocument(); + expect(screen.getByText(/tu puntuación: (\d+)/i)).toBeInTheDocument(); + + // Check if the score remains the same + const updatedScore = parseInt( + screen + .getByText(/puntuación: (\d+)/i) + .textContent.split(":")[1] + .trim() + ); + expect(updatedScore).toBe(initialScore); + + screen.getByText(/repetir juego/i).click(); + + waitFor(() => { + expect(screen.getByText(/¿/i)).toBeInTheDocument(); + }); +}); diff --git a/webapp/src/pages/Home/Home.js b/webapp/src/pages/Home/Home.js index 68ef25fb..d32d4749 100644 --- a/webapp/src/pages/Home/Home.js +++ b/webapp/src/pages/Home/Home.js @@ -40,6 +40,16 @@ const Home = () => { route="/home/bateria" /> + + + {error && ( Hubo un error al cargar las preguntas. Por favor, inténtalo más tarde.
Tu puntuación: {puntuacion}
Tiempo restante: {Math.floor(tiempoRestante)}
Puntuación: {puntuacion}