diff --git a/multiplayerservice/server.js b/multiplayerservice/server.js index d2b8c858..59cdecea 100644 --- a/multiplayerservice/server.js +++ b/multiplayerservice/server.js @@ -10,6 +10,7 @@ const io = socketIo(server, { cors: { //origin: 'http://conoceryvencer.xyz', origin: process.env.WEBAPP_ENPOINT || 'http://localhost', + //origin: 'http://localhost:3000', methods: ['GET', 'POST'], credentials: true } diff --git a/webapp/src/components/game/singleplayer/PlayingGameSinglePlayer.tsx b/webapp/src/components/game/PlayingGame.tsx similarity index 63% rename from webapp/src/components/game/singleplayer/PlayingGameSinglePlayer.tsx rename to webapp/src/components/game/PlayingGame.tsx index 4576863a..28b6fcc7 100644 --- a/webapp/src/components/game/singleplayer/PlayingGameSinglePlayer.tsx +++ b/webapp/src/components/game/PlayingGame.tsx @@ -1,18 +1,24 @@ -import { FC, useEffect, useMemo, useState } from 'react' -import { Player, Question4Answers } from './GameSinglePlayer' +import { FC, useCallback, useEffect, useMemo, useState } from 'react' +import { Player, Question4Answers } from './singleplayer/GameSinglePlayer' import axios from 'axios'; +import shuffleAnswers from './util/SuffleAnswers'; +import calculatePoints from './util/CalculatePoints'; +import { SocketProps } from './multiplayer/GameMultiPlayer'; +import "./QuestionsGame.scss" interface PlayingGameProps { questions: Question4Answers[] setCurrentStage: (n: number) => void; - setPlayers: (players:Player[]) => void; - players: Player[]; + + setPlayers?: (players:Player[]) => void; + players?: Player[]; + socket?: SocketProps; + partyCode?: string; } -const PlayingGame: FC = ({questions, setCurrentStage, setPlayers, players}) => { +const PlayingGame: FC = ({questions, setCurrentStage, setPlayers, players, socket, partyCode}) => { const uuid = localStorage.getItem("userUUID"); - //const apiEndpoint = 'http://conoceryvencer.xyz:8000' const apiEndpoint = process.env.REACT_APP_API_ENDPOINT || 'http://localhost:8000'; const [currentQuestion, setCurrentQuestion] = useState(0); @@ -22,19 +28,44 @@ const PlayingGame: FC = ({questions, setCurrentStage, setPlaye const [isWaiting, setIsWaiting] = useState(false); - const answersShuffled = useMemo(() => { - return questions.map((question) => { - const answers = [question.correctAnswer, question.incorrectAnswer1, question.incorrectAnswer2, question.incorrectAnswer3]; - for (let i = answers.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - [answers[i], answers[j]] = [answers[j], answers[i]]; - } - return answers; - }); - }, [questions]); + const answersShuffled = useMemo(() => shuffleAnswers(questions), [questions]); + + const endGame = useCallback(async () => { + const totalPoints = calculatePoints(correctAnswers, questions.length); + const requestData = { + "players": [{ + "uuid": uuid, + "nCorrectAnswers": correctAnswers, + "nWrongAnswers": questions.length - correctAnswers, + "totalScore": totalPoints, + "isWinner": false + }] + }; + + const previousScore = parseInt(localStorage.getItem("score")); + localStorage.setItem("score", (previousScore + totalPoints).toString()); + + await axios.post(`${apiEndpoint}/updateStats`, requestData); + if(players){ + players.map(player => { + const randomPoints = Math.floor(Math.random() * (1000 - 100 + 1) / 50) * 50 + 100; + if(player.isBot){ + player.points += randomPoints; + }else { + player.points += calculatePoints(correctAnswers, questions.length); + } + return player; + }) + setPlayers(players); + setCurrentStage(3); + } + if(socket) + socket.emit('playerFinished', partyCode, totalPoints); + + }, [correctAnswers, questions.length, uuid, apiEndpoint, socket, partyCode, players, setPlayers, setCurrentStage]); useEffect(() => { - const intervalId = setInterval(() => { + const intervalId = setInterval(async () => { if((currentQuestion+1) < questions.length){ if (seconds > 0) { setSeconds(prevSeconds => prevSeconds - 1); @@ -43,12 +74,15 @@ const PlayingGame: FC = ({questions, setCurrentStage, setPlaye setSelectedAnswer(null); clearInterval(intervalId); setSeconds(10); + if(currentQuestion+2 === questions.length && partyCode){ // is multiplayer + await endGame() + } } } }, 1000); return () => clearInterval(intervalId); - }, [seconds, currentQuestion, questions]); + }, [seconds, currentQuestion, questions, partyCode, endGame]); const handleAnswerClick = async (answer: string, isCorrect:boolean) => { setSeconds(10); @@ -65,45 +99,12 @@ const PlayingGame: FC = ({questions, setCurrentStage, setPlaye }, 1000); setIsWaiting(false); } + if(currentQuestion+2 === questions.length && partyCode){ + await endGame(); + } }; - const finishGame = async() => { - const totalPoints = calculatePoints(correctAnswers, questions.length); - // the player has finished the game - // update stats for each player - players.map(player => { - const randomPoints = Math.floor(Math.random() * (1000 - 100 + 1) / 50) * 50 + 100; - if(player.isBot){ - player.points += randomPoints; - }else { - player.points += calculatePoints(correctAnswers, questions.length); - } - return player; - }) - setPlayers(players); - - const requestData ={ "players": [{ - "uuid": uuid, - "nCorrectAnswers": correctAnswers, - "nWrongAnswers": questions.length - correctAnswers, - "totalScore": totalPoints, - "isWinner": false - }]} - - // update score in localstorage - const previousScore = parseInt(localStorage.getItem("score")) - localStorage.setItem("score", (previousScore + totalPoints).toString()) - setCurrentStage(3); - await axios.post(`${apiEndpoint}/updateStats`, requestData); - } - - const calculatePoints = (correctAnswers: number, totalQuestions: number) => { - const incorrectQuestions = totalQuestions - correctAnswers; - const points = correctAnswers * 100 - incorrectQuestions * 25; - return points; - } - const getAnswers = () => { const answers = answersShuffled[currentQuestion]; if (answers.length > 4) { @@ -144,7 +145,8 @@ const PlayingGame: FC = ({questions, setCurrentStage, setPlaye <>

You answered {correctAnswers} out of {questions.length} questions correctly.

You earned {calculatePoints(correctAnswers, questions.length)} points.

- + {partyCode &&

Waiting for the rest of the players to finish...

} + {players &&} )} diff --git a/webapp/src/components/game/multiplayer/GameMultiPlayer.tsx b/webapp/src/components/game/multiplayer/GameMultiPlayer.tsx index fb5c9cd2..26e8b640 100644 --- a/webapp/src/components/game/multiplayer/GameMultiPlayer.tsx +++ b/webapp/src/components/game/multiplayer/GameMultiPlayer.tsx @@ -4,8 +4,8 @@ import MenuMultiplayer from './MenuMultiplayer'; import { Container } from '@mui/material'; import LobbyMultiPlayer from './LobbyMultiPlayer'; import { Question4Answers } from '../singleplayer/GameSinglePlayer'; -import QuestionsMultiPlayer from './QuestionsMultiPlayer'; import ScoreboardGame from '../ScoreboardGame'; +import PlayingGame from '../PlayingGame'; interface GameMultiPlayerProps { @@ -114,7 +114,7 @@ const GameMultiPlayer: FC = () => { {stage === 1 && } {stage === 2 && } - {stage === 3 && } + {stage === 3 && } {stage === 4 && } ) diff --git a/webapp/src/components/game/multiplayer/QuestionsMultiPlayer.tsx b/webapp/src/components/game/multiplayer/QuestionsMultiPlayer.tsx deleted file mode 100644 index 2c8fa191..00000000 --- a/webapp/src/components/game/multiplayer/QuestionsMultiPlayer.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import { FC, useCallback, useEffect, useMemo, useState } from 'react' -import { SocketProps } from './GameMultiPlayer'; -import { Question4Answers } from '../singleplayer/GameSinglePlayer'; -import axios from 'axios'; -import '../QuestionsGame.scss'; - -interface QuestionsMultiPlayerProps { - socket: SocketProps; - handleCurrentStage: (n: number) => void - questions: Question4Answers[] - partyCode: string -} - - -const QuestionsMultiPlayer: FC = ({socket, questions, partyCode}) => { - - const answersShuffled = useMemo(() => { - return questions.map((question) => { - const answers = [question.correctAnswer, question.incorrectAnswer1, question.incorrectAnswer2, question.incorrectAnswer3]; - for (let i = answers.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - [answers[i], answers[j]] = [answers[j], answers[i]]; - } - return answers; - }); - }, [questions]); - - const uuid = localStorage.getItem("userUUID"); - //const apiEndpoint = 'http://conoceryvencer.xyz:8000' - const apiEndpoint = process.env.REACT_APP_API_ENDPOINT || 'http://localhost:8000'; - - const [currentQuestion, setCurrentQuestion] = useState(0); - const [correctAnswers, setCorrectAnswers] = useState(0); - const [selectedAnswer, setSelectedAnswer] = useState(null); - const [seconds, setSeconds] = useState(10); - - const [isWaiting, setIsWaiting] = useState(false); - - const endGame = useCallback(async () => { - const totalPoints = calculatePoints(correctAnswers, questions.length); - const requestData = { - "players": [{ - "uuid": uuid, - "nCorrectAnswers": correctAnswers, - "nWrongAnswers": questions.length - correctAnswers, - "totalScore": totalPoints, - "isWinner": false - }] - }; - - const previousScore = parseInt(localStorage.getItem("score")); - localStorage.setItem("score", (previousScore + totalPoints).toString()); - - await axios.post(`${apiEndpoint}/updateStats`, requestData); - socket.emit('playerFinished', partyCode, totalPoints); - - }, [correctAnswers, questions.length, uuid, apiEndpoint, socket, partyCode]); - - useEffect(() => { - const intervalId = setInterval(async () => { - if((currentQuestion+1) < questions.length){ - if (seconds > 0) { - setSeconds(prevSeconds => prevSeconds - 1); - } else { - setCurrentQuestion(currentQuestion + 1); - setSelectedAnswer(null); - clearInterval(intervalId); - setSeconds(10); - if(currentQuestion+2 === questions.length){ - await endGame() - } - } - } - }, 1000); - - return () => clearInterval(intervalId); - }, [seconds, currentQuestion, questions, endGame]); - - - const handleAnswerClick = async (answer: string, isCorrect:boolean) => { - setSeconds(10); - if(!isWaiting){ - setIsWaiting(true); - setSelectedAnswer(answer); - - setTimeout(() => { - if (isCorrect) { - setCorrectAnswers(correctAnswers + 1); - } - setCurrentQuestion(currentQuestion + 1); - setSelectedAnswer(null); - }, 1000); - setIsWaiting(false); - } - - if(currentQuestion+2 === questions.length){ - await endGame(); - } - }; - - const calculatePoints = (correctAnswers: number, totalQuestions: number) => { - const incorrectQuestions = totalQuestions - correctAnswers; - const points = correctAnswers * 100 - incorrectQuestions * 25; - return points; - } - - const getAnswers = () => { - const answers = answersShuffled[currentQuestion]; - if (answers.length > 4) { - console.log(answers) - const removeCount = answers.length - 4; - answers.splice(0, removeCount); - } - return answersShuffled[currentQuestion]; - }; - - return ( -
- {(currentQuestion+1) < questions.length && ( - <> -
-

Question {currentQuestion + 1} / {questions.length}

-

{questions[currentQuestion].question}

-

{seconds}

-
-
- {getAnswers().map((answer) => { - const isCorrect = questions[currentQuestion].correctAnswer === answer; - const buttonColor = (selectedAnswer === answer && !isWaiting) ? (isCorrect ? '#66ff66' : '#ff6666') : '#89c3ff'; - return ( - - )} - )} -
- - )} - {currentQuestion+1 === questions.length && ( - <> -

You answered {correctAnswers} out of {questions.length} questions correctly.

-

You earned {calculatePoints(correctAnswers, questions.length)} points.

-

Waiting for the rest of the players to finish...

- - )} -
- ) -} - -export default QuestionsMultiPlayer \ No newline at end of file diff --git a/webapp/src/components/game/singleplayer/GameSinglePlayer.tsx b/webapp/src/components/game/singleplayer/GameSinglePlayer.tsx index c16ca75c..de381b89 100644 --- a/webapp/src/components/game/singleplayer/GameSinglePlayer.tsx +++ b/webapp/src/components/game/singleplayer/GameSinglePlayer.tsx @@ -1,7 +1,7 @@ import axios from 'axios'; import { useState, useEffect } from 'react'; import LobbyGame from './LobbyGameSinglePlayer'; -import PlayingGame from './PlayingGameSinglePlayer'; +import PlayingGame from '../PlayingGame'; import ScoreboardGame from '../ScoreboardGame'; import { Container } from '@mui/material'; diff --git a/webapp/src/components/game/singleplayer/singlePlayerPlay.test.js b/webapp/src/components/game/singleplayer/singlePlayerPlay.test.js index c09407dd..5eba8e7d 100644 --- a/webapp/src/components/game/singleplayer/singlePlayerPlay.test.js +++ b/webapp/src/components/game/singleplayer/singlePlayerPlay.test.js @@ -1,5 +1,5 @@ import { render, fireEvent, waitFor,screen } from '@testing-library/react'; -import PlayingGame from './PlayingGameSinglePlayer'; +import PlayingGame from '../PlayingGame'; // Mock de las props necesarias para el componente const mockProps = { diff --git a/webapp/src/components/game/util/CalculatePoints.ts b/webapp/src/components/game/util/CalculatePoints.ts new file mode 100644 index 00000000..012777a8 --- /dev/null +++ b/webapp/src/components/game/util/CalculatePoints.ts @@ -0,0 +1,7 @@ +const calculatePoints = (correctAnswers: number, totalQuestions: number) => { + const incorrectQuestions = totalQuestions - correctAnswers; + const points = correctAnswers * 100 - incorrectQuestions * 25; + return points; + } + +export default calculatePoints; \ No newline at end of file diff --git a/webapp/src/components/game/util/SuffleAnswers.ts b/webapp/src/components/game/util/SuffleAnswers.ts new file mode 100644 index 00000000..5b3e3f13 --- /dev/null +++ b/webapp/src/components/game/util/SuffleAnswers.ts @@ -0,0 +1,10 @@ +export default function shuffleAnswers(questions){ + return questions.map((question) => { + const answers = [question.correctAnswer, question.incorrectAnswer1, question.incorrectAnswer2, question.incorrectAnswer3]; + for (let i = answers.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [answers[i], answers[j]] = [answers[j], answers[i]]; + } + return answers; + }); + } \ No newline at end of file