Skip to content

Commit

Permalink
Merge pull request #84 from Arquisoft/83-modo-de-juego-calculadora-hu…
Browse files Browse the repository at this point in the history
…mana

83 modo de juego calculadora humana
  • Loading branch information
iyanfdezz authored Apr 5, 2024
2 parents e062746 + 40e4e1a commit b5188a6
Show file tree
Hide file tree
Showing 4 changed files with 332 additions and 0 deletions.
2 changes: 2 additions & 0 deletions webapp/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -32,6 +33,7 @@ function App() {
<Route path="/sobre" element={<Sobre />} />
<Route path="/home/clasico" element={<Clasico />} />
<Route path="/home/bateria" element={<Bateria />} />
<Route path="/home/calculadora" element={<CalculadoraHumana />} />
<Route path="/stats" element={<Stats />} />
<Route path="/ranking" element={<Ranking />} />
<Route path="/perfil" element={<Perfil />} />
Expand Down
169 changes: 169 additions & 0 deletions webapp/src/pages/Calculadora/Calculadora.js
Original file line number Diff line number Diff line change
@@ -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 (
<>
<Nav />
<Flex justify="center" align="center" h="70vh">
<Box p={6} borderWidth="1px" borderRadius="lg" boxShadow="lg">
{juegoTerminado ? (
<Box textAlign="center">
<Heading as="h2">¡Juego terminado!</Heading>
<p p={2}>Tu puntuación: {puntuacion}</p>
<Button onClick={handleRepetirJuego} colorScheme="teal" m={2}>
Repetir Juego
</Button>
<Link to="/home" style={{ marginLeft: "10px" }}>
Volver al Menú Principal
</Link>
</Box>
) : (
<Box>
<Heading as="h2" mb={4}>
¿{operation}?
</Heading>
<Input
type="number"
title="number"
value={valSubmit}
onChange={(e) => setValSubmit(e.target.value)}
onKeyDown={handleKeyDown}
/>
<Button mt={3} onClick={() => handleAnswer(Number(valSubmit))}>
{" "}
Enviar{" "}
</Button>
<Box textAlign="center" mt={4}>
<p>Tiempo restante: {Math.floor(tiempoRestante)}</p>
<p>Puntuación: {puntuacion}</p>
<Box w="100%" bg="gray.100" borderRadius="lg" mt={4}>
<Box
bg="teal.500"
h="4px"
width={`${progressPercent}%`}
></Box>
</Box>
</Box>
</Box>
)}
</Box>
</Flex>
<Footer />
</>
);
};

export default CalculadoraHumana;
151 changes: 151 additions & 0 deletions webapp/src/pages/Calculadora/Calculadora.test.js
Original file line number Diff line number Diff line change
@@ -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(
<MemoryRouter>
<CalculadoraHumana />
</MemoryRouter>
);

// 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(
<MemoryRouter>
<CalculadoraHumana />
</MemoryRouter>
);

// 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(
<MemoryRouter>
<CalculadoraHumana />
</MemoryRouter>
);

// 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(
<MemoryRouter>
<CalculadoraHumana />
</MemoryRouter>
);

// 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();
});
});
10 changes: 10 additions & 0 deletions webapp/src/pages/Home/Home.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ const Home = () => {
route="/home/bateria"
/>
</Box>
<Box p={2}>
<CustomModal
title="Calculadora Humana"
text="
En el modo Calculadora Humana, tendrás que resolver operaciones matemáticas en un tiempo limitado.
¡Demuestra tus habilidades matemáticas y rapidez para superar este desafío!
"
route="/home/calculadora"
/>
</Box>
{error && (
<Box mb={4} color="red">
Hubo un error al cargar las preguntas. Por favor, inténtalo más tarde.
Expand Down

0 comments on commit b5188a6

Please sign in to comment.