diff --git a/cryptide_project/package-lock.json b/cryptide_project/package-lock.json index 1b1b975..0108d1d 100644 --- a/cryptide_project/package-lock.json +++ b/cryptide_project/package-lock.json @@ -28,16 +28,21 @@ "mysql": "^2.18.1", "react": "^18.2.0", "react-bootstrap": "^2.9.1", + "react-country-flag": "^3.1.0", "react-dom": "^18.2.0", "react-icons": "^4.11.0", "react-intl": "^6.5.2", "react-router-dom": "^6.18.0", + "react-router-hash-link": "^2.4.3", "react-scripts": "5.0.1", "react-switch": "^7.0.0", - "sqlite3": "^5.1.6", "typescript": "^5.2.2", "vis-network": "^9.1.9", "web-vitals": "^2.1.4" + }, + "devDependencies": { + "@types/react-router-hash-link": "^2.4.9", + "@types/uuid": "^9.0.7" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -3854,6 +3859,11 @@ "@sinonjs/commons": "^1.7.0" } }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, "node_modules/@surma/rollup-plugin-off-main-thread": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", @@ -4274,6 +4284,19 @@ "@types/node": "*" } }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/cors": { + "version": "2.8.16", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.16.tgz", + "integrity": "sha512-Trx5or1Nyg1Fq138PCuWqoApzvoSLWzZ25ORBiHMbbUT42g578lH1GT4TwYDbiUOLFuDsCkfLneT2105fsFWGg==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/eslint": { "version": "8.44.7", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.7.tgz", @@ -4333,6 +4356,12 @@ "integrity": "sha512-pdGBkAh4ggfXAkiwgmTdROJe3mwvLWJYm6JiaAwCtskAU0Weh+JQyyMTbhvxjxD2n8sr8PrxVwyDzmpnK4pUrQ==", "peer": true }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "dev": true + }, "node_modules/@types/hoist-non-react-statics": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", @@ -4503,6 +4532,38 @@ "@types/react": "*" } }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "dev": true, + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dev": true, + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@types/react-router-hash-link": { + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/@types/react-router-hash-link/-/react-router-hash-link-2.4.9.tgz", + "integrity": "sha512-zl/VMj+lfJZhvjOAQXIlBVPNKSK+/fRG8AUHhlP9++LhlA2ziLeTmbRxIMJI3PCiCTS+W/FosEoDRoNOGH0OzA==", + "dev": true, + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-dom": "^5.3.0" + } + }, "node_modules/@types/react-transition-group": { "version": "4.4.8", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.8.tgz", @@ -4587,6 +4648,12 @@ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.5.tgz", "integrity": "sha512-I3pkr8j/6tmQtKV/ZzHtuaqYSQvyjGRKH4go60Rr0IDLlFxuRT5V32uvB1mecM5G1EVAUyF/4r4QZ1GHgz+mxA==" }, + "node_modules/@types/uuid": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.7.tgz", + "integrity": "sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g==", + "dev": true + }, "node_modules/@types/warning": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.2.tgz", @@ -5759,6 +5826,14 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -7559,15 +7634,6 @@ "node": ">= 0.8" } }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, "node_modules/enhanced-resolve": { "version": "5.15.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", @@ -15555,6 +15621,17 @@ } } }, + "node_modules/react-country-flag": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/react-country-flag/-/react-country-flag-3.1.0.tgz", + "integrity": "sha512-JWQFw1efdv9sTC+TGQvTKXQg1NKbDU2mBiAiRWcKM9F1sK+/zjhP2yGmm8YDddWyZdXVkR8Md47rPMJmo4YO5g==", + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "react": ">=16" + } + }, "node_modules/react-dev-utils": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", @@ -15696,6 +15773,18 @@ "react-dom": ">=16.8" } }, + "node_modules/react-router-hash-link": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/react-router-hash-link/-/react-router-hash-link-2.4.3.tgz", + "integrity": "sha512-NU7GWc265m92xh/aYD79Vr1W+zAIXDWp3L2YZOYP4rCqPnJ6LI6vh3+rKgkidtYijozHclaEQTAHaAaMWPVI4A==", + "dependencies": { + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": ">=15", + "react-router-dom": ">=4" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -16614,16 +16703,6 @@ "node": ">=8" } }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "optional": true, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -16634,34 +16713,6 @@ "websocket-driver": "^0.7.4" } }, - "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", - "optional": true, - "dependencies": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", - "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", - "optional": true, - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, "node_modules/source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", @@ -18118,9 +18169,14 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "peer": true, "bin": { "uuid": "dist/bin/uuid" } @@ -19097,6 +19153,14 @@ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/cryptide_project/package.json b/cryptide_project/package.json index 4dc122e..d1934ec 100644 --- a/cryptide_project/package.json +++ b/cryptide_project/package.json @@ -22,13 +22,17 @@ "mysql": "^2.18.1", "react": "^18.2.0", "react-bootstrap": "^2.9.1", + "react-country-flag": "^3.1.0", "react-dom": "^18.2.0", "react-icons": "^4.11.0", "react-intl": "^6.5.2", "react-router-dom": "^6.18.0", + "react-router-hash-link": "^2.4.3", "react-scripts": "5.0.1", "react-switch": "^7.0.0", "sqlite3": "^5.1.6", + "socket.io": "^4.7.2", + "socket.io-client": "^4.7.2", "typescript": "^5.2.2", "vis-network": "^9.1.9", "web-vitals": "^2.1.4" @@ -56,5 +60,9 @@ "last 1 firefox version", "last 1 safari version" ] + }, + "devDependencies": { + "@types/react-router-hash-link": "^2.4.9", + "@types/uuid": "^9.0.7" } } diff --git a/cryptide_project/server/server.js b/cryptide_project/server/server.js new file mode 100644 index 0000000..faee172 --- /dev/null +++ b/cryptide_project/server/server.js @@ -0,0 +1,87 @@ +const express = require('express'); +const http = require('http'); +const socketIO = require('socket.io'); +const cors = require('cors'); + +const app = express(); +const server = http.createServer(app); +const io = socketIO(server, { + cors: { + origin: ["http://localhost:3000", "http://localhost:3001"], // Remplacez par l'URL de votre application React + methods: ["GET", "POST"], + credentials: true + } +}); + + +const map = new Map() +// ... le reste de votre configuration du serveur + +server.listen(3002, () => { + console.log('Serveur Socket.IO écoutant sur le port 3001'); +}); + +io.on('connection', (socket) => { + console.log(socket.id); + + socket.on('network created', (network, person, indices, room) =>{ + io.to(room).emit("game created", network, person, indices, Math.floor(Math.random() * map.get(room).length)) + }); + + socket.on("lobby joined", (room, name) =>{ + socket.join(room) + if (map.get(room) == undefined){ + map.set(room, [{id: socket.id, name: name}]) + } + else{ + const tab = map.get(room) + for(let i = 0; i{ + io.to(socket.id).emit("lobby created", Math.floor(Math.random() * 10000)) + }) + + socket.on("already asked", (nodeId, askingPlayer, askedPlayer) =>{ + io.to(askingPlayer.id).emit("already asked", nodeId, askedPlayer) + }) + + socket.on("ask player", (nodeId, playerId, askingPlayer, askingPlayerIndex) =>{ + io.to(playerId).emit("asked", nodeId, askingPlayer, askingPlayerIndex) + }) + + socket.on("asked all 1by1", (id, playerId) =>{ + io.to(playerId).emit("asked all", id) + }) + + socket.on("asked wrong", (askingPlayer) =>{ + io.to(askingPlayer.id).emit("asked wrong") + }) + + socket.on("disconnect", () =>{ + for (const k of map.keys()){ + const tab = map.get(k) + for (let i = 0; i{ + console.log(playerIndex) + io.to(room).emit("node checked", id, works, color, playerIndex) + }) + +}); diff --git a/cryptide_project/src/App.tsx b/cryptide_project/src/App.tsx index 2765a15..dacb2c0 100644 --- a/cryptide_project/src/App.tsx +++ b/cryptide_project/src/App.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { useState } from 'react'; import { IntlProvider } from 'react-intl'; +import { GameProvider } from './Contexts/GameContext'; /* Page */ import Home from './Pages/Home'; @@ -32,6 +33,7 @@ import 'bootstrap/dist/css/bootstrap.min.css'; /* Internationnalisation */ import messagesFr from './Translations/fr.json'; import messagesEn from './Translations/en.json'; +import SoloGame from './Pages/SoloGame'; const messages = { fr: messagesFr, @@ -61,26 +63,29 @@ function App() { // logo // // - - //@ts-ignore - - - - {/* */} - {hasNavbarVisible && } - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - - - + + + {/*@ts-ignore*/} + + + + {hasNavbarVisible && } + + } /> + } /> + } /> + } /> + } /> + } /> + }/> + } /> + {/* }/> */} + + + + + + ); } diff --git a/cryptide_project/src/ColorHelper.ts b/cryptide_project/src/ColorHelper.ts new file mode 100644 index 0000000..6e10218 --- /dev/null +++ b/cryptide_project/src/ColorHelper.ts @@ -0,0 +1,56 @@ +import Player from "./model/Player"; +import { socket } from "./SocketConfig"; + +function positionToColor(pos: number): string{ + switch (pos) { + case 0: + return "blue"; + case 1: + return "green"; + case 2: + return "yellow"; + case 3: + return "purple"; + case 4: + return "red"; + default: + return "brown"; + } +} + +function colorToEmoji(color: string, works: boolean): string{ + if (works){ + switch (color) { + case "blue": + return "🔵"; + case "green": + return "🟢"; + case "yellow": + return "🟡"; + case "purple": + return "🟣"; + case "red": + return "🔴"; + default: + return "🟤"; + } + } + else{ + switch (color) { + case "blue": + return "🟦"; + case "green": + return "🟩"; + case "yellow": + return "🟨"; + case "purple": + return "🟪"; + case "red": + return "🟥"; + default: + return "🟫"; + } + } +} + +export {colorToEmoji, positionToColor} diff --git a/cryptide_project/src/Components/ChoiceBar.tsx b/cryptide_project/src/Components/ChoiceBar.tsx index 6769f62..96422d2 100644 --- a/cryptide_project/src/Components/ChoiceBar.tsx +++ b/cryptide_project/src/Components/ChoiceBar.tsx @@ -1,17 +1,67 @@ import React from 'react'; +import { useGame } from '../Contexts/GameContext'; +import { socket } from '../SocketConfig'; import './ChoiceBar.css'; import { useTheme } from '../Style/ThemeContext'; +import IndiceTesterFactory from '../model/Factory/IndiceTesterFactory'; +import { positionToColor } from '../ColorHelper'; const ChoiceBar = () => { - const players = ['Player1', 'Player2', 'Player3']; + const { players, nodeId, actualPlayerIndex, personNetwork, indices, room } = useGame(); const theme = useTheme(); + + + function askPlayer(playerId: string){ + if (nodeId !== null){ + socket.emit("ask player", nodeId, playerId, players.find((p) => p.id === socket.id, actualPlayerIndex)) + } + } + + async function askEveryone(){ + if (nodeId !== null){ + const person = personNetwork?.getPersons().find((p) => p.getId() == nodeId) + if (person != undefined){ + const indiceTester = IndiceTesterFactory.Create(indices[actualPlayerIndex]) + let nextPlayerIndex = actualPlayerIndex + 1 + if (nextPlayerIndex == players.length){ + nextPlayerIndex = 0 + } + + let playerIndex = actualPlayerIndex + 1 + if (indiceTester.Works(person)){ + socket.emit("node checked", nodeId, true, positionToColor(actualPlayerIndex), room, nextPlayerIndex) + while(playerIndex != actualPlayerIndex){ + if (playerIndex == players.length){ + playerIndex = 0 + } + const tester = IndiceTesterFactory.Create(indices[playerIndex]) + const works = tester.Works(person) + await delay(500); + socket.emit("asked all 1by1", person.getId(), players[playerIndex].id) + socket.emit("node checked", nodeId, works, positionToColor(playerIndex), room, nextPlayerIndex) + if(!works){ + return + } + playerIndex ++ + } + } + } + } + } + + function delay(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); + } + return (

Quel joueur voulez-vous interroger ?

+ {players.map((player, index) => ( - ))}
diff --git a/cryptide_project/src/Components/ColoredIndices.tsx b/cryptide_project/src/Components/ColoredIndices.tsx new file mode 100644 index 0000000..e8f8c4a --- /dev/null +++ b/cryptide_project/src/Components/ColoredIndices.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import '../Style/Global.css'; +import { FormattedMessage } from 'react-intl'; + +import { useTheme } from '../Style/ThemeContext'; + +//@ts-ignore +function ColoredIndices({ letter, color}) { + + const theme = useTheme(); + + // const mystyle = { + // backgroundColor: "#0064E0", + // }; + + return ( +
+ Indice Letter +
+ ); +} + +export default ColoredIndices; diff --git a/cryptide_project/src/Components/GraphContainer.tsx b/cryptide_project/src/Components/GraphContainer.tsx index bf8061a..dea0531 100644 --- a/cryptide_project/src/Components/GraphContainer.tsx +++ b/cryptide_project/src/Components/GraphContainer.tsx @@ -11,30 +11,73 @@ import "./GraphContainer.css"; import NodePerson from "../model/Graph/NodePerson"; import IndiceTesterFactory from "../model/Factory/IndiceTesterFactory"; import GameCreator from "../model/GameCreator"; +import io from 'socket.io-client'; +import JSONParser from "../JSONParser"; +import PersonNetwork from "../model/PersonsNetwork"; +import Person from "../model/Person"; +import Indice from "../model/Indices/Indice"; +import { useLocation } from "react-router-dom"; +import { useGame } from "../Contexts/GameContext"; +import { socket } from "../SocketConfig" +import { colorToEmoji, positionToColor } from "../ColorHelper"; -const [networkPerson, choosenPerson, choosenIndices, graph] = GameCreator.CreateGame(3, 30) - - -console.log(networkPerson) -console.log(graph) -choosenIndices.forEach((indice) =>{ - console.log(indice.ToString("fr")) -}); -console.log(choosenPerson) -const testIndice = choosenIndices[0] interface MyGraphComponentProps { onNodeClick: (shouldShowChoiceBar: boolean) => void; + handleShowTurnBar: (shouldShowTurnBar: boolean) => void + handleTurnBarTextChange: (newTurnBarText: string) => void + changecptTour: (newcptTour : number) => void + addToHistory: (message : string) => void + solo : boolean } -const MyGraphComponent: React.FC = ({onNodeClick}) => { +let lastAskingPlayer = 0 +let lastNodeId = -1 +let first = true +let askedWrong = false +let cptTour: number = 0 + +const MyGraphComponent: React.FC = ({onNodeClick, handleShowTurnBar, handleTurnBarTextChange, changecptTour, addToHistory, solo}) => { + + const { indices, indice, person, personNetwork, setNodeIdData, players, askedPersons, setActualPlayerIndexData, room, actualPlayerIndex, turnPlayerIndex, onlyFalse, setOnlyFalseData } = useGame(); + + const params = new URLSearchParams(window.location.search); + + + let firstlap = true; + let playerIndex: number = turnPlayerIndex + let index = 0 + for (let i=0; i { + if (personNetwork == null){ + return + } + const graph = GraphCreator.CreateGraph(personNetwork) + const container = document.getElementById('graph-container'); if (!container) { console.error("Container not found"); return; } - // Charger les données dans le graph const nodes = new DataSet(graph.nodesPerson); @@ -58,60 +101,178 @@ const MyGraphComponent: React.FC = ({onNodeClick}) => { } }; - + const networkData = { nodes: nodes, edges: graph.edges }; const network = new Network(container, networkData, initialOptions); - - //TEST POUR MONTRER QU'IL Y EN A QU'UN A CHAQUE FOIS - /* - networkPerson.getPersons().forEach(p => { - let a = 0 - for (let i of choosenIndices){ - let tester = IndiceTesterFactory.Create(i) - if (tester.Works(p)){ - a++ + if (!solo){ + socket.on("asked all", (id) =>{ + const pers = personNetwork.getPersons().find((p) => p.getId() == id) + if (pers!=undefined){ + askedPersons.push(pers) } - } - if (a==choosenIndices.length){ - networkData.nodes.update({id: p.getId(), label: p.getName() + "\n🔵"}) - } + }) - }); - */ - - // Gérer le changement entre la physique et le déplacement manuel - network.on("dragging", (params) => { - if (params.nodes.length > 0) { - // Un nœud a été cliqué - initialOptions.physics.enabled = false; - network.setOptions(initialOptions); + socket.on("node checked",(id, works, color, newPlayerIndex) => { + const node = nodes.get().find((n) => id == n.id) + if (node!=undefined){ + onNodeClick(false) + playerIndex = newPlayerIndex + if (!node.label.includes(colorToEmoji(color, works))){ + networkData.nodes.update({id: id, label: node.label + colorToEmoji(color, works)}) + addToHistory("qq1 à mis un " + colorToEmoji(color, works)) + } + if (playerIndex === thisPlayerIndex){ + handleTurnBarTextChange("À vous de jouer") + handleShowTurnBar(true) + } + else{ + handleShowTurnBar(false) + } } - }); - - network.on("click", (params) => { - if(params.nodes.length > 0){ - //TEST POUR VOIR SI ON PEUT RAJOUTER DES TRUCS AU LABEL - - const pers = networkPerson.getPersons().find((p) => p.getId() == params.nodes[0]) - if (pers!=undefined){ - //@ts-ignore - const node = nodes.get().find((n) => params.nodes[0] == n.id) - if (node != undefined){ - var tester = IndiceTesterFactory.Create(testIndice) - if (tester.Works(pers)){ - networkData.nodes.update({id: params.nodes[0], label: node.label + "🔵"}) + lastAskingPlayer = 0 + lastNodeId = -1 + }) + + socket.on("already asked", (nodeId, askedPlayer) =>{ + console.log("player: " + askedPlayer + " already asked on node " + nodeId) + }) + + socket.on("asked wrong", () =>{ + setOnlyFalseData(true) + askedWrong = true + handleShowTurnBar(true) + handleTurnBarTextChange("Mauvais choix, posez un carré !") + }) + + + socket.on("asked", (nodeId, askingPlayer, askingPlayerIndex) => { + console.log(askingPlayerIndex) + if (askingPlayer.id !== lastAskingPlayer || nodeId !== lastNodeId ){ + lastAskingPlayer = askingPlayer.id + lastNodeId = nodeId + const pers = personNetwork.getPersons().find((p) => p.getId() == nodeId) + if (pers!=undefined){ + if (askedPersons.includes(pers)){ + socket.emit("already asked", nodeId, askingPlayer, socket.id) + return } else{ - networkData.nodes.update({id: params.nodes[0], label: node.label + "🟦"}) - } + askedPersons.push(pers) + const node = nodes.get().find((n) => nodeId == n.id) + if (node != undefined && indice != null){ + var tester = IndiceTesterFactory.Create(indice) + let maybe = thisPlayerIndex + playerIndex = playerIndex + 1 + if(playerIndex == players.length){ + playerIndex = 0 + } + if (tester.Works(pers)){ + socket.emit("node checked", nodeId, true, positionToColor(thisPlayerIndex), room, playerIndex) + } + else{ + maybe = maybe - 1 + if(maybe == 0){ + maybe = players.length - 1 + } + socket.emit("node checked", nodeId, false, positionToColor(thisPlayerIndex), room, maybe) + socket.emit("asked wrong", askingPlayer, room) + } + } + } + } + } + + }) + } + else { + if (firstlap){ + addToHistory("<----- [Tour " + 1 +"/"+networkData.nodes.length + "] ----->"); + firstlap = false; + } + } + + + + + personNetwork.getPersons().forEach(p => { + let a = 0 + for (let i of indices){ + let tester = IndiceTesterFactory.Create(i) + if (tester.Works(p)){ + a++ } - + } + if (a==indices.length){ + //networkData.nodes.update({id: p.getId(), label: p.getName() + "\n🔵"}) + console.log(p) } + }); + - // Renvoyer un true pour afficher la choice bar - onNodeClick(true) + // Gérer le changement entre la physique et le déplacement manuel + network.on("dragging", (params) => { + if (params.nodes.length > 0) { + // Un nœud a été cliqué + initialOptions.physics.enabled = false; + network.setOptions(initialOptions); + } + }); + + network.on("click", async (params) => { + + if(params.nodes.length > 0){ + setNodeIdData(params.nodes[0]) + // addToHistory("Le joueur a cliqué") //! TEST DEBUG + if (!solo){ + if (askedWrong){ + const person = personNetwork?.getPersons().find((p) => p.getId() == params.nodes[0]) + if (person !== undefined && indice !== null){ + const tester = IndiceTesterFactory.Create(indice) + if (!tester.Works(person) && !askedPersons.includes(person)){ + playerIndex = thisPlayerIndex + 1 + if(playerIndex == players.length){ + playerIndex = 0 + } + socket.emit("node checked", params.nodes[0], false, positionToColor(thisPlayerIndex), room, playerIndex) + askedPersons.push(person) + askedWrong = false + } + } + } + else if (thisPlayerIndex == playerIndex){ + onNodeClick(true) + } + else{ + onNodeClick(false) + } + } + else{ // si solo -> Mastermind + const person = personNetwork?.getPersons().find((p) => p.getId() == params.nodes[0]) //person sélectionnée + if (person != undefined){ + let index = 0; + // indices.forEach(async (i, index) =>{ + for(const i of indices){ + const tester = IndiceTesterFactory.Create(i) + const test = tester.Works(person) + const node = nodes.get().find((n) => params.nodes[0] == n.id) + if (node!=undefined){ + networkData.nodes.update({id: params.nodes[0], label: node.label + colorToEmoji(positionToColor(index), test)}) + await delay(500); + } + index ++; + } + addToHistory(person.getName() + " n'est pas le tueur !"); //TODO préciser le nombre d'indice qu'il a de juste + + //TODO METTRE LA WIN CONDITION ICI AVEC LE MERGE + cptTour ++; // On Incrémente le nombre de tour du joueur + const tour = cptTour+1; + addToHistory("<----- [Tour " + tour +"/"+networkData.nodes.length + "] ----->"); + changecptTour(cptTour); // On le transmet a la page précédente avec la fonction + } + } } + // Renvoyer un true pour afficher la choice bar else{ // Renvoyer un false pour cacher la choice bar onNodeClick(false) @@ -124,6 +285,12 @@ const MyGraphComponent: React.FC = ({onNodeClick}) => {
); -}; + + function delay(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); + } +} + + export default MyGraphComponent; \ No newline at end of file diff --git a/cryptide_project/src/Components/IndiceList.tsx b/cryptide_project/src/Components/IndiceList.tsx new file mode 100644 index 0000000..5b77592 --- /dev/null +++ b/cryptide_project/src/Components/IndiceList.tsx @@ -0,0 +1,34 @@ +import React from 'react'; + +/* Style */ +import '../Style/Global.css'; +//import { useTheme } from '../Style/ThemeContext'; + +/* Model */ +import Stub from '../model/Stub'; +import Indice from '../model/Indices/Indice'; + +/* lang */ +import { FormattedMessage } from 'react-intl'; + +interface IndiceListComponentProps { + instance: (new (...args: any[]) => T) | (Function & { prototype: T }); + lang: string; +} + +const IndiceList: React.FC> = ({ instance, lang }) => { + const indices = Stub.GenerateIndice(); + return ( + <> +
    + {indices + .filter((i) => i instanceof instance) + .map((indice, index) => ( +

    {indice.ToString(lang)}

    + ))} +
+ + ); +} + +export default IndiceList; diff --git a/cryptide_project/src/Components/NavBar.tsx b/cryptide_project/src/Components/NavBar.tsx index d570467..f95c155 100644 --- a/cryptide_project/src/Components/NavBar.tsx +++ b/cryptide_project/src/Components/NavBar.tsx @@ -15,6 +15,10 @@ import { HiLanguage } from 'react-icons/hi2'; import logo from '../res/img/logo2_preview_rev_1.png'; /* Components */ +import ReactCountryFlag from "react-country-flag" + + +/* Style */ import './NavBar.css'; /* Style */ @@ -28,10 +32,6 @@ function AppNavbar({changeLocale}) { logo - {/*
-

Cryptide

-
by Crypteam
-
*/}
@@ -59,9 +59,23 @@ function AppNavbar({changeLocale}) { title={} className="navbar-title" id="basic-nav-dropdown"> changeLocale('fr')}> + changeLocale('en')}> + diff --git a/cryptide_project/src/Components/PersonStatus.tsx b/cryptide_project/src/Components/PersonStatus.tsx index 66abe64..7afcca2 100644 --- a/cryptide_project/src/Components/PersonStatus.tsx +++ b/cryptide_project/src/Components/PersonStatus.tsx @@ -9,7 +9,7 @@ import Person from '../res/img/Person.png' import leave from '../res/img/bot.png' //@ts-ignore -function PersonStatus({img = Person, state= leave, name = "Dummy"}) { +function PersonStatus({img = Person, state= Person, name = "Dummy"}) { const theme=useTheme(); return (
diff --git a/cryptide_project/src/Components/PlayerItemList.tsx b/cryptide_project/src/Components/PlayerItemList.tsx index 984455c..4b2d4e9 100644 --- a/cryptide_project/src/Components/PlayerItemList.tsx +++ b/cryptide_project/src/Components/PlayerItemList.tsx @@ -1,13 +1,35 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; import '../Style/Global.css'; +import Bot from '../res/img/bot.png'; + +/* Boostrap */ +import ToggleButton from 'react-bootstrap/ToggleButton'; +import ToggleButtonGroup from 'react-bootstrap/ToggleButtonGroup'; //@ts-ignore -function PlayerItemList({ pdp, name}) { +function PlayerItemList({ pdp, name, id}) { + const isBot = pdp === Bot; + return ( -
- player-image -

{name}

+
+
+ player-image +

{name}

+
+ {isBot && ( + + + Facile + + + Intermédiaire + + + Fort + + + )}
) } diff --git a/cryptide_project/src/Components/PlayerList.tsx b/cryptide_project/src/Components/PlayerList.tsx index 19d29c4..5dcfb25 100644 --- a/cryptide_project/src/Components/PlayerList.tsx +++ b/cryptide_project/src/Components/PlayerList.tsx @@ -1,5 +1,6 @@ import React from 'react'; +import { colorToEmoji, positionToColor } from '../ColorHelper'; import PersonStatus from './PersonStatus'; //@ts-ignore @@ -9,7 +10,7 @@ function PlayerList({ players }) { { //@ts-ignore players.map((player, index) => ( - + )) }
diff --git a/cryptide_project/src/Components/TurnBar.tsx b/cryptide_project/src/Components/TurnBar.tsx new file mode 100644 index 0000000..53df6d4 --- /dev/null +++ b/cryptide_project/src/Components/TurnBar.tsx @@ -0,0 +1,21 @@ +import React from "react"; +import { useTheme } from "../Style/ThemeContext"; + +interface TurnBarProps{ + text: string +} + +const TurnBar: React.FC = ({text})=> { + const theme = useTheme(); + return ( +
+ {/* texte changeable et a traduire */} +

{text}

+
+ ); +}; + +export default TurnBar; \ No newline at end of file diff --git a/cryptide_project/src/Contexts/GameContext.tsx b/cryptide_project/src/Contexts/GameContext.tsx new file mode 100644 index 0000000..380d7d3 --- /dev/null +++ b/cryptide_project/src/Contexts/GameContext.tsx @@ -0,0 +1,110 @@ +import React, { createContext, useContext, useState, ReactNode } from 'react'; +import Indice from '../model/Indices/Indice'; +import Person from '../model/Person'; +import PersonNetwork from '../model/PersonsNetwork'; +import Player from '../model/Player'; + +interface GameContextProps { + indices: Indice[]; + indice: Indice | null + person: Person | null; + personNetwork: PersonNetwork | null; + players: Player[] + nodeId: number | null + askedPersons: Person[]; + actualPlayerIndex: number; + turnPlayerIndex: number; + room: string; + onlyFalse: boolean + setIndicesData: (newIndices: Indice[]) => void; + setIndiceData: (newIndice: Indice) => void; + setPersonData: (newPerson: Person) => void; + setPersonNetworkData: (newPersonNetwork: PersonNetwork) => void; + setPlayersData: (newPlayer: Player[]) => void; + setNodeIdData: (newId: number) => void; + setAskedPersonsData: (newAskedPersons: Person[]) => void; + setActualPlayerIndexData: (newActualPlayerIndex: number) => void; + setTurnPlayerIndexData: (newTurnPlayerIndex: number) => void; + setRoomData: (newRoom: string) => void; + setOnlyFalseData: (newOnlyFalse: boolean) => void +} + +const GameContext = createContext(undefined); + +interface GameProviderProps { + children: ReactNode; +} + +export const GameProvider: React.FC = ({ children }) => { + const [indices, setIndices] = useState([]); + const [indice, setIndice] = useState(null); + const [person, setPerson] = useState(null); + const [personNetwork, setPersonNetwork] = useState(null); + const [players, setPlayers] = useState([]) + const [nodeId, setNodeId] = useState(null); + const [askedPersons, setAskedPersons] = useState([]) + const [actualPlayerIndex, setActualPlayerIndex] = useState(-1) + const [turnPlayerIndex, setTurnPlayerIndex] = useState(-1) + const [room, setRoom] = useState("") + const [onlyFalse, setOnlyFalse] = useState(false) + + + const setIndicesData = (newIndices: Indice[]) => { + setIndices(newIndices); + }; + + const setIndiceData = (newIndice: Indice) =>{ + setIndice(newIndice) + }; + + + const setPersonData = (newPerson: Person) => { + setPerson(newPerson); + }; + + const setPersonNetworkData = (newPersonNetwork: PersonNetwork) => { + setPersonNetwork(newPersonNetwork); + }; + + const setPlayersData = (newPlayers: Player[]) => { + setPlayers(newPlayers); + }; + + const setNodeIdData = (newId: number) => { + setNodeId(newId); + }; + + const setAskedPersonsData = (newAskedPerson: Person[]) => { + setAskedPersons(newAskedPerson); + }; + + const setActualPlayerIndexData = (newActualPlayerIndex: number) =>{ + setActualPlayerIndex(newActualPlayerIndex) + } + + const setTurnPlayerIndexData = (newTurnPlayerIndex: number) =>{ + setTurnPlayerIndex(newTurnPlayerIndex) + } + + const setRoomData = (newRoom: string) =>{ + setRoom(newRoom) + } + + const setOnlyFalseData = (newOnlyFalse: boolean) =>{ + setOnlyFalse(newOnlyFalse) + } + + return ( + + {children} + + ); +}; + +export const useGame = (): GameContextProps => { + const context = useContext(GameContext); + if (!context) { + throw new Error('useGame must be used within an GameProvider'); + } + return context; +}; diff --git a/cryptide_project/src/JSONParser.ts b/cryptide_project/src/JSONParser.ts new file mode 100644 index 0000000..037cf19 --- /dev/null +++ b/cryptide_project/src/JSONParser.ts @@ -0,0 +1,83 @@ +import AgeIndice from "./model/Indices/AgeIndice"; +import ColorEdgesIndice from "./model/Indices/ColorEdgesIndice"; +import ColorIndice from "./model/Indices/ColorIndice"; +import Indice from "./model/Indices/Indice"; +import NbEdgesIndice from "./model/Indices/NbEdgesIndice"; +import NbSportIndice from "./model/Indices/NbSportIndice"; +import SportIndice from "./model/Indices/SportIndice"; +import Person from "./model/Person"; +import PersonNetwork from "./model/PersonsNetwork"; + +class JSONParser{ + + static JSONToNetwork(jsonString: any): PersonNetwork{ + const json = JSON.parse(jsonString) + const persons: Person[] = [] + const personFriends = new Map() + json.persons.forEach((personJson: any) => { + persons.push(JSONParser.JSONToPerson(personJson)) + personJson.friends.forEach((f: any) => { + if (personFriends.get(personJson.id) == undefined){ + personFriends.set(personJson.id, [f.id]) + } + else{ + personFriends.get(personJson.id)?.push(f.id) + } + }); + }); + + for(const person of persons){ + const tab = personFriends.get(person.getId()) + if (tab != undefined){ + for(const i of tab){ + person.addFriend(persons.filter((p) => p.getId() == i)[0]) + } + } + } + + return new PersonNetwork(persons); + } + + static JSONToPerson(json: any): Person { + const person = new Person( + json.id, + json.name, + json.age, + json.color, + json.sports, + [] + ); + return person; + } + + + static JSONToIndice(json: any): Indice{ + switch (json.type){ + case "AgeIndice": + return new AgeIndice(json.id, json.minimum, json.maximum) + case "ColorEdgesIndice": + return new ColorEdgesIndice(json.id, json.neighborsColors) + case "ColorIndice": + return new ColorIndice(json.id, json.colors) + case "NbEdgesIndice": + return new NbEdgesIndice(json.id, json.nbNeighbors) + case "NbSportIndice": + return new NbSportIndice(json.id, json.nbSport) + case "SportIndice": + return new SportIndice(json.id, json.sports) + default: + throw new Error("PARSER unable to parse indice: " + json.type); + } + } + + static JSONToIndices(jsonString: any): Indice[]{ + const json = JSON.parse(jsonString) + const tabIndice: Indice[] = [] + json.forEach((i: any) => { + tabIndice.push(this.JSONToIndice(i)) + }); + return tabIndice + } +} + +export default JSONParser \ No newline at end of file diff --git a/cryptide_project/src/Pages/InGame.css b/cryptide_project/src/Pages/InGame.css index 9e12155..654e21f 100644 --- a/cryptide_project/src/Pages/InGame.css +++ b/cryptide_project/src/Pages/InGame.css @@ -60,6 +60,22 @@ top :50px; } +.nbLaps{ /*nombre de tour*/ + position: absolute; + z-index: 1; + left: 10px; + top :50px; + + margin: 10px 20px; + padding: 20px; + border-radius: 15px; + border: solid 2px; + + font-size: 30px; + color: #fff; +} + + #endgamebutton{ position: absolute; z-index: 1; @@ -91,7 +107,7 @@ .button{ /*background-color: #85C9C2;*/ - border: solid 2px #85C9C2; + border: solid 2px #7aa3f4; border-radius: 10px; width: 100px; @@ -101,4 +117,25 @@ /* #playerCanvasBody{ columns: 2 auto; grid-row: 2; -} */ \ No newline at end of file +} */ + +/** Historique*/ + +.historique{ + position: absolute; + z-index: 1; + bottom: 2%; + left: 2%; + + display: flex; + flex-direction: column; + /* justify-content: end; */ + + padding: 15px 25px; + background-color: #d9d9d9; + border-radius: 15px; + + height: 250px; + width: 20%; + overflow-y:auto; +} \ No newline at end of file diff --git a/cryptide_project/src/Pages/InGame.tsx b/cryptide_project/src/Pages/InGame.tsx index 38946bc..25bd894 100644 --- a/cryptide_project/src/Pages/InGame.tsx +++ b/cryptide_project/src/Pages/InGame.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import Switch from "react-switch"; /* Style */ @@ -10,6 +10,7 @@ import ChoiceBar from '../Components/ChoiceBar'; import ButtonImgNav from '../Components/ButtonImgNav'; import PersonStatus from '../Components/PersonStatus'; import PlayerList from '../Components/PlayerList'; +import TurnBar from '../Components/TurnBar'; /* Icon */ import Leave from "../res/icon/leave.png"; @@ -18,6 +19,7 @@ import Replay from "../res/icon/replay.png"; import Info from "../res/icon/infoGreen.png"; import Check from "../res/icon/checkboxGreen.png"; import Alpha from "../res/GreekLetters/alphaW.png"; +import MGlass from "../res/icon/magnifying-glass.png"; /* nav */ import { Link } from 'react-router-dom'; @@ -32,52 +34,81 @@ import { HiLanguage } from 'react-icons/hi2'; import { Nav, NavDropdown } from 'react-bootstrap'; import { FormattedMessage } from 'react-intl'; import Color from '../model/Color'; +import { useGame } from '../Contexts/GameContext'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { NavLink } from 'react-router-dom'; //@ts-ignore const InGame = ({locale, changeLocale}) => { + + const theme = useTheme(); + + + const params = new URLSearchParams(window.location.search); + + //* Gestion solo + let IsSolo: boolean = true + const solotmp = params.get('solo'); + if (solotmp == "false"){ + IsSolo=false + } - const players = [ - { state: Replay, name: 'Dummy' }, - { state: Replay, name: 'Boat' }, - { state: Replay, name: 'Bot-tom' }, - { state: Replay, name: 'Dummy' }, - { state: Replay, name: 'Boat' }, - { state: Replay, name: 'Bot-tom' }, - { state: Replay, name: 'Dummy' }, - { state: Replay, name: 'Boat' }, - { state: Replay, name: 'Bot-tom' }, - { state: Replay, name: 'Dummy' }, - { state: Replay, name: 'Boat' }, - { state: Replay, name: 'Bot-tom' }, - { state: Replay, name: 'Dummy' }, - { state: Replay, name: 'Boat' }, - { state: Replay, name: 'Bot-tom' } - // Ajouter d'autres joueurs au besoin - ]; + //* Historique + const [history, setHistory] = useState([]); + // Fonction pour ajouter un élément à l'historique + const addToHistory = (message: string) => { + setHistory(prevHistory => [...prevHistory, message]); + }; + + useEffect(() => { + const historyContainer = document.getElementById('history-container'); + if (historyContainer) { + historyContainer.scrollTop = historyContainer.scrollHeight; + } + }, [history]); - const theme = useTheme(); - const [showChoiceBar, setShowChoiceBar] = useState(false); - - const handleNodeClick = (shouldShowChoiceBar: boolean) => { - setShowChoiceBar(shouldShowChoiceBar); - }; - - /* offcanvas */ - //? faire une fonction pour close et show en fonction de l'etat du canva ? - //? comment faire pour eviter la recopie de tout le code a chaque canvas boostrap ? - const [show, setShow] = useState(false); - const handleClose = () => setShow(false); - const handleShow = () => setShow(true); - - const [showP, setShowP] = useState(false); - const handleCloseP = () => setShowP(false); - const handleShowP = () => setShowP(true); + + + const [showChoiceBar, setShowChoiceBar] = useState(false); + const [showTurnBar, setShowTurnBar] = useState(false); + const [turnBarText, setTurnBarText] = useState(""); + + const handleNodeClick = (shouldShowChoiceBar: boolean) => { + setShowChoiceBar(shouldShowChoiceBar); + }; + + + const handleShowTurnBar = (shouldShowTurnBar: boolean) => { + setShowTurnBar(shouldShowTurnBar); + }; - const [showS, setShowS] = useState(false); - const handleCloseS = () => setShowS(false); - const handleShowS = () => setShowS(true); + const handleTurnBarTextChange = (newTurnBarText: string) =>{ + setTurnBarText(newTurnBarText) + } + + /* offcanvas */ + //? faire une fonction pour close et show en fonction de l'etat du canva ? + //? comment faire pour eviter la recopie de tout le code a chaque canvas boostrap ? + const [show, setShow] = useState(false); + const handleClose = () => setShow(false); + const handleShow = () => setShow(true); + + const [showP, setShowP] = useState(false); + const handleCloseP = () => setShowP(false); + const handleShowP = () => setShowP(true); + + const [showS, setShowS] = useState(false); + const handleCloseS = () => setShowS(false); + const handleShowS = () => setShowS(true); + + const [cptTour, setcptTour] = useState(0); + + //@ts-ignore + const changecptTour = (newcptTour) => { + setcptTour(newcptTour); + }; const handleChange = () => { if (show){ @@ -114,35 +145,54 @@ const InGame = ({locale, changeLocale}) => { const [SwitchEnabled, setSwitchEnabled] = useState(false) const indices = Stub.GenerateIndice() + const { indice, players } = useGame(); + return (
-
- {/* texte changeable et a traduire */} -

Dummy, à vous de jouer !

-
+ {showTurnBar && }
- +
-
- + }}> + Coups : {cptTour} +
+ ) : ( +
+ +
+ ) + } + + +
+ {history.map((item, index) => ( +
{item}
+ ))}
+ {/* + //? redirection impossible apparament (securité des navigateur + */}
@@ -211,9 +264,7 @@ const InGame = ({locale, changeLocale}) => { {/* Possède les cheveux noir ou joue au basket */} - {indices[0].ToString(locale)}
- {indices[1].ToString(locale)}
- {indices[2].ToString(locale)} + {indice?.ToString(locale)}
@@ -248,13 +299,14 @@ const InGame = ({locale, changeLocale}) => { -
{showChoiceBar && }
-
{/* tmp */} + {/* +
{/* tmp
+ */}
); }; diff --git a/cryptide_project/src/Pages/InfoPage.css b/cryptide_project/src/Pages/InfoPage.css new file mode 100644 index 0000000..8c8786b --- /dev/null +++ b/cryptide_project/src/Pages/InfoPage.css @@ -0,0 +1,142 @@ +@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;600;700;800;900&display=swap"); /** import de la font */ + + +.infoPage{ + margin: 20px 100px; +} +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: "Poppins", sans-serif; +} + +/** Sommaire */ +.list { + max-width: 25%; + position: relative; +} +.list ul { + position: relative; +} +.list ul li { + position: relative; + left: 0; + color: #fce4ec; + list-style: none; + margin: 4px 0; + border-left: 2px solid #0052B8; + transition: 0.5s; + cursor: pointer; +} +.list ul li:hover { + left: 10px; +} +.list ul li span { + position: relative; + padding: 8px; + padding-left: 12px; + display: inline-block; + z-index: 1; + transition: 0.5s; + color: #000; +} +.list ul li:hover span { + color: #fff; +} +.list ul li:before { + content: ""; + position: absolute; + width: 100%; + height: 100%; + background: #0052B8; + transform: scaleX(0); + transform-origin: left; + transition: 0.5s; +} +.list ul li:hover:before { + transform: scaleX(1); +} +li *{ + font-size: larger; + font-weight: bold; + text-decoration: none; +} + +.LiInterfaceDisplay{ + display: flex; + justify-content: start; + margin-bottom: 20px; +} + +.LiInterfaceDisplay p{ + font-size: medium; +} + +h2 { + position: relative; + padding: 0; + margin: 0; + font-family: "Raleway", sans-serif; + font-weight: 300; + font-size: 40px; + color: #080808; + -webkit-transition: all 0.4s ease 0s; + -o-transition: all 0.4s ease 0s; + transition: all 0.4s ease 0s; +} + +h2 span { + display: block; + font-size: 0.5em; + line-height: 1.3; +} +h2 em { + font-style: normal; + font-weight: 600; +} +.infoPage h2 { + font-size: 28px; + font-weight: 500; + letter-spacing: 0; + line-height: 1.5em; + padding-bottom: 15px; + position: relative; +} +.infoPage h2:before { + content: ""; + position: absolute; + left: 0; + bottom: 0; + height: 5px; + width: 55px; + background-color: #111; +} +.infoPage h2:after { + content: ""; + position: absolute; + left: 0; + bottom: 2px; + height: 1px; + width: 95%; + max-width: 255px; + background-color: #333; +} + +h4{ + font-size: 25px; + position: relative; + padding: 0; + margin: 20px 0 0 0; + font-family: "Raleway", sans-serif; +} + +.h5title{ + margin: 50px 0 0 0; + font-family: "Raleway", sans-serif; +} + +/* .infoPage h2{ + text-decoration: underline; + font-family:'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif; +} */ \ No newline at end of file diff --git a/cryptide_project/src/Pages/InfoPage.tsx b/cryptide_project/src/Pages/InfoPage.tsx index 34c2f93..dadd9ac 100644 --- a/cryptide_project/src/Pages/InfoPage.tsx +++ b/cryptide_project/src/Pages/InfoPage.tsx @@ -2,63 +2,277 @@ import React from 'react'; /* Style */ import '../Style/Global.css'; - +import './InfoPage.css'; import { FormattedMessage } from 'react-intl'; +import { useGame } from '../Contexts/GameContext'; +import ColorIndice from '../model/Indices/ColorIndice'; +import Stub from '../model/Stub'; +import SportIndice from '../model/Indices/SportIndice'; +import EdgesIndice from '../model/Indices/EdgesIndice'; +import NbEdgesIndice from '../model/Indices/NbEdgesIndice'; +import NbSportIndice from '../model/Indices/NbSportIndice'; +import AgeIndice from '../model/Indices/AgeIndice'; +import ColorEdgesIndice from '../model/Indices/ColorEdgesIndice'; +import IndiceList from '../Components/IndiceList'; +import { HashLink as Link } from 'react-router-hash-link'; +import { ColorToHexa } from '../model/EnumExtender'; +import Color from '../model/Color'; +import "./InGame.css" +import {useTheme} from '../Style/ThemeContext' +import Check from "../res/icon/checkboxGreen.png"; +import Alert from 'react-bootstrap/Alert'; +import MGlass from "../res/icon/magnifying-glass.png"; +import Param from "../res/icon/param.png"; +import Info from "../res/icon/infoGreen.png"; //todo changer la couleur de l'icon -function InfoPage() { //! cette page n'affiche que des informations et est suceptible de changer selon le context. +//@ts-ignore +function InfoPage({locale, changeLocale}) { + + const theme = useTheme(); + const styles = { + roux: { backgroundColor: ColorToHexa(Color.REDHEAD), width: '15px', height: '15px', display: 'inline-block', marginRight: '5px' }, + blond: { backgroundColor: ColorToHexa(Color.BLOND), width: '15px', height: '15px', display: 'inline-block', marginRight: '5px' }, + noir: { backgroundColor: ColorToHexa(Color.BLACK), width: '15px', height: '15px', display: 'inline-block', marginRight: '5px' }, + blanc: { backgroundColor: ColorToHexa(Color.WHITE), border: '1px solid #ccc', width: '15px', height: '15px', display: 'inline-block', marginRight: '5px' }, + chatain: { backgroundColor: ColorToHexa(Color.BROWN), width: '15px', height: '15px', display: 'inline-block', marginRight: '5px' }, + }; return ( + //! Il faudra possiblement faire une gestion des mode de jeu, pour modifier les regles en fonction de ce dernier. +
+

-
-

Informations

- -

Indice possible :

-

- couleur de cheveux d'une personne -

-
    -
  • - Possède les cheveux noir -
  • -
  • - Possède les cheveux roux -
  • -
  • - Possède les cheveux blond -
  • -
  • - Possède les cheveux brun -
  • -
  • - Possède les cheveux blanc -
  • -
+
+

+

+ +

+
+ +
+

+
    +
  • +
  • +
  • +
  • +
+
+ +
+

:

+

+ +

+
+
    +

    +

  • : 🟪🟦🟩🟨🟥🟫
  • + + +
  • : 🟣🔵🟢🟡🔴🟤
  • + +

    +
+
+

+ +

+
+

+ {/* + //TODO mettre icon des ages apres le merge + */} +

:
+ . + +
:
+ +
    +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
+ +
: ⚾🏀🎳⚽🎾
+ +
    +
  • +
  • 🏀
  • +
  • 🎳
  • +
  • +
  • 🎾
  • +
+ +

+

-

- Sport d'une personne -

-
    -
  • - Effectue du Foot ou du tennis -
  • -
  • - Effectue du rugby ou du tennis -
  • -
-

- Caractèristique des voisins -

-
    -
  • - Possède deux voisins footballeur -
  • -
  • - Possède aucun voisin rugbyman -
  • -
+
+

:

+

+ +

+

+ : +

+

+ +

+

:

+

+ +

+

:

+

+ +

-

Topographie

-

Legende des différents objet disponible sur la carte.

+

+ Interface : +

+
Pour chacune des parties, vous aurez certains éléments d'interface à disposition :
+
    +
  • +
    + +

    + Le bouton "Paramètre" permet l'affichage et la gestion de différent paramètres de la partie, comme par exemple le language, l'aide ... . +

    +
    + + Attention, cette partie ne peut pas être complétée tant que tout les paramètres n'ont pas été choisis ! + +
  • +
  • +
    + +

    + Le bouton "Information" permet de rediriger vers la page de règle du jeu (celle ci). + {/* + //! mais est ce que nous devons rediriger sur les indices possibles ? + */} +

    +
    +
  • +
  • +
    + + +

    + Le bouton "Fiche de déduction d'indice" permet l'affichage de tableau dynamic permettant, avec le déroulé de la partie, de déduire quels indices sont les plus probables. +

    +
    + + Attention, cette partie ne peut pas être complétée tant que la page et l'algorithme dédié ne sont pas fait ! + +
  • +
  • +
    + + +

    + Le bouton "Indice personnel" est le plus important, en effet il permet d'afficher quel est votre indice secret. Vous seul le connaissais ! Il va falloir ruser pour tromper vos amis et le garder secret le plus longtemps possible ! +

    +
    +
  • +
+
+
+
+

:

+

+ 1 : +

+

+ +

+

+ 2 : +

+

+ +

+

+ 3 : +

+

+ +

+
+
+
+

:

+
+

+ +

+ + +

+ +

+ + +
+

+ +

+ + + + +

+ +

+ + +
+
); } diff --git a/cryptide_project/src/Pages/Lobby.css b/cryptide_project/src/Pages/Lobby.css index 5aed52c..5c4bfbd 100644 --- a/cryptide_project/src/Pages/Lobby.css +++ b/cryptide_project/src/Pages/Lobby.css @@ -1,5 +1,4 @@ - .lobby-container { display: flex; background-color: #fff; @@ -41,4 +40,17 @@ margin: 20px; } +.codeDiv{ + display: flex; + align-items: end; + justify-content: end; + margin: auto 20px; +} +.codeDiv p{ + font-style: italic; + font-weight: bold; + color: gray; + font-size: 20px; + cursor: pointer; +} \ No newline at end of file diff --git a/cryptide_project/src/Pages/Lobby.tsx b/cryptide_project/src/Pages/Lobby.tsx index cf30190..a6d6930 100644 --- a/cryptide_project/src/Pages/Lobby.tsx +++ b/cryptide_project/src/Pages/Lobby.tsx @@ -1,29 +1,116 @@ -import React from 'react'; - -/* Style */ +import React, { useEffect, useState } from 'react'; import './Lobby.css'; import { useTheme } from '../Style/ThemeContext'; /* res */ -import Person from '../res/img/Person.png'; +import PlayerItemList from '../Components/PlayerItemList' +import PersonImg from '../res/img/Person.png'; import Bot from '../res/img/bot.png'; import param from '../res/icon/param.png'; import cible from '../res/icon/cible.png'; /* Component */ import ButtonImgNav from '../Components/ButtonImgNav'; -import PlayerItemList from '../Components/PlayerItemList' +import { io } from 'socket.io-client'; +import { Link } from 'react-router-dom'; +import PersonNetwork from '../model/PersonsNetwork'; +import Person from '../model/Person'; +import GameCreator from '../model/GameCreator'; +import { useGame } from '../Contexts/GameContext'; +import JSONParser from '../JSONParser'; +import Indice from '../model/Indices/Indice'; +import { useNavigate } from 'react-router-dom'; +import { socket } from "../SocketConfig"; +import { random } from 'lodash'; +import Player from '../model/Player'; + + function Lobby() { const theme=useTheme(); + const navigate = useNavigate(); + + + const { indices, setIndicesData, indice, setIndiceData, person, setPersonData, personNetwork, setPersonNetworkData, players, setPlayersData, setActualPlayerIndexData, setTurnPlayerIndexData, setRoomData } = useGame(); + + let first = true + + const params = new URLSearchParams(window.location.search); + const room = params.get('room'); + + useEffect(() => { + if (first){ + first = false + socket.emit("lobby joined", room, "test name" + Math.floor(Math.random() * 10)) + + return () => { + socket.off('game created'); + }; + } + + }, []); + + socket.on("game created", (jsonNetwork, jsonPersonString, jsonIndicesString, playerIndex)=> { + const jsonPerson = JSON.parse(jsonPersonString) + const network: PersonNetwork = JSONParser.JSONToNetwork(jsonNetwork) + const choosenOne: Person = network.getPersons().filter((i) => i.getId() == jsonPerson.id)[0] + const choosenIndices : Indice[] = JSONParser.JSONToIndices(jsonIndicesString) + let index = 0 + for (let i=0; i{ + const tmpTab: Player[] = [] + for (const p of tab){ + tmpTab.push(new Player(p.id, p.name)) + } + setPlayersData(tab.map((p: any) => new Player(p.id, p.name))) + }) + + const [codeShowed, setCodeShowed] = useState(true); + + + function StartGame(){ + const [networkPerson, choosenPerson, choosenIndices] = GameCreator.CreateGame(players.length, 30) + setPersonData(choosenPerson) + setPersonNetworkData(networkPerson) + setIndicesData(choosenIndices) + socket.emit('network created', JSON.stringify(networkPerson, null, 2), JSON.stringify(choosenPerson), JSON.stringify(choosenIndices), room); + } + return (
+
setCodeShowed(!codeShowed)}> + { + codeShowed ? ( +

Room : {room}

+ ) : ( +

Room : ******

+ ) + } +
{/* //! voir pour la gestion avec un liste, utilisateur avec le "+ (vous)" et les pdp avec les lettres grecs (?)*/} - - - + {players.map((player, index) => ( + + ))}
@@ -46,12 +133,24 @@ function Lobby() { //? indice avancé ? ==> négation, voisin du 2e degré etc. } -
- {/* page de baptiste ici */} +
+
); + + function shuffleArray(array: Indice[]) { + for (var i = array.length - 1; i > 0; i--) { + var j = Math.floor(Math.random() * (i + 1)); + var temp = array[i]; + array[i] = array[j]; + array[j] = temp; + } + } } export default Lobby; diff --git a/cryptide_project/src/Pages/Play.tsx b/cryptide_project/src/Pages/Play.tsx index 68acff5..dab7184 100644 --- a/cryptide_project/src/Pages/Play.tsx +++ b/cryptide_project/src/Pages/Play.tsx @@ -1,5 +1,4 @@ -import React from 'react'; -import {useEffect, useState} from 'react'; +import React, { useEffect, useState } from 'react'; /* Style */ import './Play.css'; @@ -19,6 +18,10 @@ import Person from '../res/img/Person.png'; import trophy from '../res/icon/trophy.png'; import param from '../res/icon/param.png'; import share from '../res/icon/share.png'; +import { socket } from '../SocketConfig'; +import { useNavigate } from 'react-router-dom'; +import GameCreator from '../model/GameCreator'; +import { useGame } from '../Contexts/GameContext'; function Play() { @@ -47,6 +50,48 @@ function Play() { }, []); + const { setIndicesData, setPersonData, setPersonNetworkData } = useGame(); + + + const [room, setRoom] = useState(null); + const navigate = useNavigate(); + + function createLobby(){ + socket.emit("lobby created") + } + + function launchMastermind(){ + const [networkPerson, choosenPerson, choosenIndices] = GameCreator.CreateGame(5, 30) + setPersonData(choosenPerson) + setPersonNetworkData(networkPerson) + setIndicesData(choosenIndices) + setIndicesData(choosenIndices) + navigate('/game?solo=true'); + } + + + + useEffect(() => { + const handleLobbyCreated = (newRoom: any) => { + setRoom(newRoom); + }; + + // Ajouter l'event listener + socket.on('lobby created', handleLobbyCreated); + + // Nettoyer l'event listener lors du démontage du composant + return () => { + socket.off('lobby created', handleLobbyCreated); + }; + + }, []); // Aucune dépendance ici + + useEffect(() => { + if (room !== null) { + const nouvelleURL = `/lobby?room=${room}`; + navigate(nouvelleURL); + } + }, [room, navigate]); return ( @@ -69,15 +114,10 @@ function Play() { />
- - - - - - - - - + + + +
diff --git a/cryptide_project/src/Pages/SoloGame.css b/cryptide_project/src/Pages/SoloGame.css new file mode 100644 index 0000000..4f2769b --- /dev/null +++ b/cryptide_project/src/Pages/SoloGame.css @@ -0,0 +1,107 @@ +.upperInfo{ + display: flex; + justify-content: center; + flex-direction: column; + align-items: center; + + width: 30%; + + border-radius: 0px 0px 30px 30px; + border: solid; + border-width: 2px 5px; + + background-color: white; + + font-size: 30px; + + top: 20px;; +} + +#mainDiv{ + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; +} + + +.paramDiv{ + z-index: 1; + position: absolute; + top: 10px; + right: 10px; +} + +#graphDiv{ + + display: flex; + flex-direction: row; + + position: absolute; + + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +#bottom-container{ + bottom: 0; + + background-color: white; + padding:20px; + border-radius: 20px 20px 0px 0px; +} + +.nbLaps{ + position: absolute; + z-index: 1; + left: 10px; + top :50px; + + margin: 10px 20px; + padding: 20px; + border-radius: 15px; + border: solid 2px; + + font-size: 30px; + color: #fff; +} + +#endgamebutton{ + position: absolute; + z-index: 1; + bottom: 0; + right: 25%; +} + +.upperInfo, +#bottom-container, +.menuGame { + position: absolute; + z-index: 1; +} + +.menuGame{ + display: flex; + align-items: space-between; + justify-content: end; + flex-direction: column; + + top:30%; + right: 0; +} + +.menuGame Button { + margin: 10px; +} + +.button{ + /*background-color: #85C9C2;*/ + + border: solid 2px #85C9C2; + border-radius: 10px; + + width: 100px; + height: 60px; +} diff --git a/cryptide_project/src/Pages/SoloGame.tsx b/cryptide_project/src/Pages/SoloGame.tsx new file mode 100644 index 0000000..98e5825 --- /dev/null +++ b/cryptide_project/src/Pages/SoloGame.tsx @@ -0,0 +1,236 @@ +import React, { useState } from 'react'; +import Switch from "react-switch"; + +/* Style */ +import "./SoloGame.css" +import {useTheme} from '../Style/ThemeContext' +/* Component */ +import GraphContainer from '../Components/GraphContainer'; +import ChoiceBar from '../Components/ChoiceBar'; +import ButtonImgNav from '../Components/ButtonImgNav'; +import PersonStatus from '../Components/PersonStatus'; +import PlayerList from '../Components/PlayerList'; + +/* Icon */ +import Leave from "../res/icon/leave.png"; +import Param from "../res/icon/param.png"; +import Replay from "../res/icon/replay.png"; +import Info from "../res/icon/infoGreen.png"; +import Check from "../res/icon/checkboxGreen.png"; +import Alpha from "../res/GreekLetters/alphaW.png"; + +/* nav */ +import { Link } from 'react-router-dom'; + +/* Boostrap */ +import Button from 'react-bootstrap/Button'; +import Offcanvas from 'react-bootstrap/Offcanvas'; + +/* Model */ +import Stub from '../model/Stub'; +import { HiLanguage } from 'react-icons/hi2'; +import { Nav, NavDropdown } from 'react-bootstrap'; +import { FormattedMessage } from 'react-intl'; +import Color from '../model/Color'; +import TurnBar from '../Components/TurnBar'; +import { useGame } from '../Contexts/GameContext'; + +//@ts-ignore +const SoloGame = ({locale, changeLocale}) => { + + const theme = useTheme(); + + const [showChoiceBar, setShowChoiceBar] = useState(false); + const [showTurnBar, setShowTurnBar] = useState(false); + + + const handleNodeClick = (shouldShowChoiceBar: boolean) => { + setShowChoiceBar(shouldShowChoiceBar); + }; + + const handleShowTurnBar = (shouldShowTurnBar: boolean) => { + setShowTurnBar(shouldShowTurnBar); + }; + + /* offcanvas */ + //? faire une fonction pour close et show en fonction de l'etat du canva ? + //? comment faire pour eviter la recopie de tout le code a chaque canvas boostrap ? + const [show, setShow] = useState(false); + const handleClose = () => setShow(false); + const handleShow = () => setShow(true); + + // const [showP, setShowP] = useState(false); + // const handleCloseP = () => setShowP(false); + // const handleShowP = () => setShowP(true); + + const [showS, setShowS] = useState(false); + const handleCloseS = () => setShowS(false); + const handleShowS = () => setShowS(true); + + const handleChange = () => { + if (show){ + handleClose() + } + else { + handleShow() + } + }; + + // const handleChangeP = () => { + // if (showP){ + // handleCloseP() + // } + // else { + // handleShowP() + // } + // }; + + const handleChangeS = () => { + if (showS){ + handleCloseS() + } + else { + handleShowS() + } + }; + + /* Windows open */ + //@ts-ignore + const openInNewTab = (url) => { //! avec url ==> dangereux + window.open(url); + }; + + const [SwitchEnabled, setSwitchEnabled] = useState(false) + const indices = Stub.GenerateIndice() + const { indice, players } = useGame(); + + + return ( +
+ +
+ {/* */} +
+ +
+ Tour : 5 +
+ +
+ +
+ +
+ + + + {/* */} + + + + + + +
+ + {/* + + Joueurs +

Il y a {players.length} joueurs

+
+ + + +
*/} + + + + Indice + + + {/* Possède les cheveux noir ou joue au basket */} + {indice?.ToString(locale)} + + + + { + //* canva pour les paramètres + } + + + param Paramètres + + + + + + + + +
+ {showChoiceBar && } +
+ {/* +
{/* tmp + +
+ */} +
+ ); +}; + + +export default SoloGame; diff --git a/cryptide_project/src/SocketConfig.ts b/cryptide_project/src/SocketConfig.ts new file mode 100644 index 0000000..81422c9 --- /dev/null +++ b/cryptide_project/src/SocketConfig.ts @@ -0,0 +1,6 @@ +import { io } from "socket.io-client"; + + +const socket = io("http://127.20.10.4:3002"); + +export {socket} \ No newline at end of file diff --git a/cryptide_project/src/Style/Global.css b/cryptide_project/src/Style/Global.css index 1a0f41f..0e22e38 100644 --- a/cryptide_project/src/Style/Global.css +++ b/cryptide_project/src/Style/Global.css @@ -12,6 +12,12 @@ align-items: center; } +.item-horizontal-div-container{ + display: flex; + align-items: center; + margin-right: 20px; +} + .item-horizontal-div{ display: flex; flex-direction: row; @@ -43,3 +49,7 @@ form{ margin : auto 150px; } + +.listContainer{ + columns: 2 auto; +} \ No newline at end of file diff --git a/cryptide_project/src/Style/Theme.tsx b/cryptide_project/src/Style/Theme.tsx index 50df20a..199ff79 100644 --- a/cryptide_project/src/Style/Theme.tsx +++ b/cryptide_project/src/Style/Theme.tsx @@ -3,7 +3,7 @@ const theme = { colors: { primary: '#0064E0', secondary: '#0052B8', - + tertiary: '#7aa3f4', //* Pour les boutons de l'interface. text: '#fff' //faire une gestion dark/light diff --git a/cryptide_project/src/Translations/en.json b/cryptide_project/src/Translations/en.json index dd6bacd..684204e 100644 --- a/cryptide_project/src/Translations/en.json +++ b/cryptide_project/src/Translations/en.json @@ -42,7 +42,7 @@ "and": "and", "or": "or", - "or_sport": "or", + "or_sport": "and/or", "age_indice_start": "The suspect is between", @@ -62,5 +62,82 @@ "nb_sports_indice_end": "sport", "sport_start": "The suspect plays at least", - "sport_end": "" + "sport_end": "", + + + + + + + + + + + + "informations" : "Information", + "info.intro.title":"Introduction to the game :", + "info.intro.text":"Welcome to our exciting deduction game, where intrigue and mischief come together in a thrilling adventure! Immerse yourself in a world of mystery and intrigue, where every interaction counts, and every clue brings you closer to the truth.Imagine a complex graph where each vertex represents a person, each axis a relationship, and every detail counts. You are plunged into a challenging challenge to discover who among these individuals is the mysterious killer. Each player has a crucial clue, and only the strategic sharing of these clues will lead you to solving the mystery. Explore our rules page to understand the intricacies of the game, discover clues that can guide you, and develop smart strategies to identify the culprit. Manipulate your friends to be the first to find out who the murderer is! Are you ready to take up the challenge and unmask the killer hidden in the graph? Let the investigation begin!", + + "info.sommaire":"Contents", + + "info.title.composant":"Game Components", + "info.title.objectif":"Objective of the game", + "info.title.deroulement":"Game flow", + "info.title.indice_possible":"Possible game clue", + + "info.pions" : "Pawns", + "info.composant.text" : "Each player will be associated with a specific color that will distinguish the actions represented by the pawns as follows :", + + "info.composant.carre.title":"square tokens", + "info.composant.carre":"These chips indicate a negation. When a player places a square token, it means that his clue clears the designated person.", + + "info.composant.rond.title":"round tokens", + "info.composant.rond":"These chips represent a 'maybe'. The player depositing this token claims that the person is a suspect, but this does not guarantee his guilt.There is only one suspect carrying a round token for all players in the game, and this is the culprit!", + + "info.car_perso":"Characteristics", + "info.composant.textcar":"In addition to their names, the characters are represented with other characteristics :", + + "info.composant.age.title":"Ages", + "info.composant.age":"Each person has an age to authenticate them, varying between 0 and 60 years. Age is a characteristic that will be confirmed by clues in the form of ", + "info.composant.age.link":"age groups", + + "info.composant.hair_col.title":"Hair's colors", + "info.composant.hair_col":"The characters also have a hair colour, which can be found in the following colours :", + + "hair.blanc":"Blanc", + "hair.blond":"Blond", + "hair.roux":"Red head", + "hair.chatain":"Brown", + "hair.noir":"Black", + + "info.composant.sport.title":"Sports", + "info.composant.sport":"The characters' hobbies are represented by five sports respectively :", + "info.composant.baseball":"Baseball", + "info.composant.basketball":"Basketball", + "info.composant.bowling":"Bowling", + "info.composant.football":"Football", + "info.composant.tennis":"Tennis", + "info.composant.sport.bis":"Among these sports, each character can have between 0 and 3 sports, which facilitates their identification using the clues you have.", + + + "info.objectif.intro":"Welcome to the clever universe of our deduction game, where deception and cunning are the keys to success. Your mission is to unravel the mystery behind each interaction of the complex graph representing the relationships between individuals.", + "info.objectif.t1":"Subtle Manipulation", + "info.objectif.t1.text":"The ultimate goal is to find out who among the individuals is the killer, but not through open collaboration. On the contrary, you will use subtle manipulation to blur the lines and distract your opponents. Ask strategic questions, respond with malice, and plant misleading clues to get closer to the outcome.", + "info.objectif.t2":"Trickery", + "info.objectif.t2.text":"Each round offers the opportunity to sow doubt among your opponents. When a player questions you, respond by cleverly placing a square token to indicate that 'depending on your clue, that person cannot be the culprit' or a round token to suggest that they remain in the suspect list. Be careful, because every gesture can be interpreted, and the truth is often hidden behind a facade of misleading clues.", + "info.objectif.t3":"Counter-manipulation", + "info.objectif.t3.text":"If a player places a square token, the questioner must also play his game by placing a square token of his color on a node of the graph. Countermanipulation becomes a formidable weapon to divert the accusation and sow confusion.", + + "etape":"Step", + "info.deroulement.e1":"Ask Strategic Questions", + "info.deroulement.e1.text":"Each round begins with a player asking another player a question about a person on the graph. Answers are formulated by placing square or round tokens to indicate certainty or doubt as to the involvement of this person.", + "info.deroulement.e2":"Counterhandling and Counterquestioning", + "info.deroulement.e2.text":"If a player places a square token, the questioner must also place a square token on a node in the graph. Counter-questions are a way to confuse players and deflect the accusation.", + "info.deroulement.e3":"The Final Guess", + "info.deroulement.e3.text":"The game reaches its climax when a player attempts the final 'Guess', claiming that such a person is the killer. Other players can then contradict this statement by placing their own square chips. If no refutation is made, the player who made the 'Guess' wins the game, demonstrating his mastery in the art of manipulation.", + + "info.indice-possible.age":"Person's age", + "info.indice-possible.hair":"Hair color of a person", + "info.indice-possible.sport":"Sport(s) of a person", + "info.indice-possible.voisin":"Character of neighbours" } \ No newline at end of file diff --git a/cryptide_project/src/Translations/fr.json b/cryptide_project/src/Translations/fr.json index 6d3d1e3..b457739 100644 --- a/cryptide_project/src/Translations/fr.json +++ b/cryptide_project/src/Translations/fr.json @@ -42,7 +42,7 @@ "and": "et", "or": "ou", - "or_sport": "ou du", + "or_sport": "et/ou du", "age_indice_start": "Le suspect a entre", "age_indice_more_start": "Le suspect a ou a plus de", @@ -61,5 +61,83 @@ "nb_sports_indice_end": "sport(s)", "sport_start": "Le suspect pratique au moins du", - "sport_end": "" + "sport_end": "", + + + + + + + + + + + + "informations" : "Informations", + "info.intro.title":"Introduction au jeu :", + "info.intro.text":"Bienvenue dans notre jeu de déduction captivant, où l'intrigue et la malice se rejoignent dans une aventure palpitante ! Plongez-vous dans un monde de mystère et d'intrigue, où chaque interaction compte, et chaque indice vous rapproche de la vérité.Imaginez un graphique complexe où chaque sommet représente une personne, chaque axe une relation, et chaque détail compte. Vous êtes plongé dans un défi stimulant pour découvrir qui parmi ces individus est le mystérieux tueur. Chaque joueur détient un indice crucial, et seul le partage stratégique de ces indices vous mènera à la résolution du mystère. Explorez notre page de règles pour comprendre les subtilités du jeu, découvrez les indices qui peuvent vous guider, et élaborez des stratégies intelligentes pour identifier le coupable. Manipuler vos amis, afin d'être le premier à découvrir qui est le meurtrier ! Êtes-vous prêt à relever le défi et à démasquer le tueur caché dans le graphe ? Que l'enquête commence !", + + "info.sommaire":"Sommaire", + + "info.title.composant":"Composants du jeu", + "info.title.objectif":"Objectif du jeu", + "info.title.deroulement":"Déroulement du jeu", + "info.title.indice_possible":"Indice possible du jeu", + + "info.pions" : "Pions", + "info.composant.text" : "Chaque joueur sera associé à une couleur spécifique qui distinguera les actions représentées par les pions comme suit :", + + "info.composant.carre.title":"Les jetons carrés", + "info.composant.carre":"Ces jetons indiquent une négation. Lorsqu'un joueur place un jeton carré, il signifie que son indice innocente la personne désignée.", + + "info.composant.rond.title":"Les jetons ronds", + "info.composant.rond":"Ces jetons représentent un 'peut-être'. Le joueur déposant ce jeton affirme que la personne est un suspect, mais cela ne garantit pas sa culpabilité.Il y a un seul suspect portant un jeton rond pour tous les joueurs de la partie, et il s'agit du coupable ! ", + + "info.car_perso":"Caractèristiques des personnages", + "info.composant.textcar":"En plus de leur nom, les personnages sont représentés avec d'autres caractéristiques :", + + "info.composant.age.title":"Les Âges", + "info.composant.age":"Chaque personne possède un âge pour les authentifier, variant entre 0 et 60 ans. L'âge est une caractéristique qui sera confirmée par des indices sous forme de ", + "info.composant.age.link":"tranches d'âge", + + "info.composant.hair_col.title":"Les Couleurs de cheveux", + "info.composant.hair_col":"Les personnages possèdent également une couleur de cheveux, que l'on retrouve parmi les couleurs suivantes :", + + "hair.blanc":"Blanc", + "hair.blond":"Blond", + "hair.roux":"Roux", + "hair.chatain":"Châtain", + "hair.noir":"Noir", + + "info.composant.sport.title":"Les Sports", + "info.composant.sport":"Les loisirs des personnages sont représentés par cinq sports respectivement :", + + "info.composant.baseball":"Baseball", + "info.composant.basketball":"Basketball", + "info.composant.bowling":"Bowling", + "info.composant.football":"Football", + "info.composant.tennis":"Tennis", + "info.composant.sport.bis":"Parmi ces sports, chaque personnage peut avoir entre 0 et 3 sports, ce qui facilite leur identification à l'aide des indices que vous possédez.", + + "info.objectif.intro":"Bienvenue dans l'univers astucieux de notre jeu de déduction, où la tromperie et la ruse sont les clés du succès. Votre mission est de démêler le mystère qui se cache derrière chaque interaction du graphique complexe représentant les relations entre les individus.", + "info.objectif.t1":"Manipulation Subtile", + "info.objectif.t1.text":"Le but ultime est de découvrir qui parmi les individus est le tueur, mais pas par une collaboration ouverte. Au contraire, vous utiliserez la manipulation subtile pour brouiller les pistes et détourner l'attention de vos adversaires. Posez des questions stratégiques, répondez avec malice, et plantez des indices trompeurs pour vous rapprocher du dénouement.", + "info.objectif.t2":"Jeu de Duperie", + "info.objectif.t2.text":"Chaque tour offre l'opportunité de semer le doute parmi vos adversaires. Lorsqu'un joueur vous interroge, répondez en plaçant habilement un jeton carré pour indiquer que 'selon votre indice, cette personne ne peut être le coupable' ou un jeton rond pour suggérer qu'elle reste dans la liste des suspects. Soyez prudent, car chaque geste peut être interprété, et la vérité est souvent cachée derrière une façade d'indices trompeurs.", + "info.objectif.t3":"Contre-manipulation", + "info.objectif.t3.text":"Si un joueur place un jeton carré, le questionneur doit également jouer son jeu en posant un jeton carré de sa couleur sur un nœud du graphique. La contre-manipulation devient une arme redoutable pour détourner l'accusation et semer la confusion.", + + "etape":"Étape", + + "info.deroulement.e1":"Poser des Questions Stratégiques", + "info.deroulement.e1.text":"Chaque tour commence par un joueur posant une question à un autre joueur concernant une personne sur le graphe. Les réponses sont formulées en plaçant des jetons carrés ou ronds pour indiquer la certitude ou le doute quant à l'implication de cette personne.", + "info.deroulement.e2":"Contre-manipulation et Contre-questions", + "info.deroulement.e2.text":"Si un joueur place un jeton carré, le questionneur doit également poser un jeton carré sur un nœud du graphique. Les contre-questions sont un moyen de semer la confusion parmi les joueurs et de détourner l'accusation.", + "info.deroulement.e3":"Le 'Guess' Final", + "info.deroulement.e3.text":"La partie atteint son apogée lorsqu'un joueur tente le 'Guess' final, affirmant que telle personne est le tueur. Les autres joueurs peuvent alors contredire cette affirmation en plaçant leurs propres jetons carrés. Si aucune réfutation n'est faite, le joueur ayant fait le 'Guess' remporte la partie, démontrant ainsi sa maîtrise dans l'art de la manipulation.", + + "info.indice-possible.age":"Âge d'une personne", + "info.indice-possible.hair":"Couleur de cheveux d'une personne", + "info.indice-possible.sport":"Sport(s) d'une personne", + "info.indice-possible.voisin":"Caractèristique des voisins" } diff --git a/cryptide_project/src/model/GameCreator.ts b/cryptide_project/src/model/GameCreator.ts index 1d9d8ca..026969c 100644 --- a/cryptide_project/src/model/GameCreator.ts +++ b/cryptide_project/src/model/GameCreator.ts @@ -10,7 +10,7 @@ import PersonNetwork from "./PersonsNetwork"; import Stub from "./Stub"; class GameCreator{ - static CreateGame(nbPlayers: number, nbNodes: number): [PersonNetwork, Person, Indice[], GraphPerson]{ + static CreateGame(nbPlayers: number, nbNodes: number): [PersonNetwork, Person, Indice[]]{ const edgesCreator = new EdgesCreator() const chooser = new IndiceChooser() @@ -26,9 +26,7 @@ class GameCreator{ edgesCreator.CreateAllEdges(networkPerson, person, choosenIndices) - const graph = GraphCreator.CreateGraph(networkPerson) - - return [networkPerson, person, choosenIndices, graph] + return [networkPerson, person, choosenIndices] } } diff --git a/cryptide_project/src/model/Indices/AgeIndice.ts b/cryptide_project/src/model/Indices/AgeIndice.ts index ba7eb7d..9edb813 100644 --- a/cryptide_project/src/model/Indices/AgeIndice.ts +++ b/cryptide_project/src/model/Indices/AgeIndice.ts @@ -28,6 +28,15 @@ class AgeIndice extends Indice { getMaximum(): number{ return this.maximum } + + toJSON() { + return { + type: "AgeIndice", + id: this.id, + minimum: this.minimum, + maximum: this.maximum + }; + } } export default AgeIndice \ No newline at end of file diff --git a/cryptide_project/src/model/Indices/ColorEdgesIndice.ts b/cryptide_project/src/model/Indices/ColorEdgesIndice.ts index e922ed2..d4c368a 100644 --- a/cryptide_project/src/model/Indices/ColorEdgesIndice.ts +++ b/cryptide_project/src/model/Indices/ColorEdgesIndice.ts @@ -29,6 +29,14 @@ class ColorEdgesIndice extends EdgesIndice { } return `${string} ${json.color_edges_end}` } + + toJSON() { + return { + type: "ColorEdgesIndice", + id: this.id, + neighborsColors: this.neighborsColors, + }; + } } export default ColorEdgesIndice \ No newline at end of file diff --git a/cryptide_project/src/model/Indices/ColorIndice.ts b/cryptide_project/src/model/Indices/ColorIndice.ts index 3ec00ac..6bf22a4 100644 --- a/cryptide_project/src/model/Indices/ColorIndice.ts +++ b/cryptide_project/src/model/Indices/ColorIndice.ts @@ -28,6 +28,15 @@ class ColorIndice extends Indice { getColors(): Color[]{ return this.colors } + + toJSON() { + return { + type: "ColorIndice", + id: this.id, + colors: this.colors, + }; + } } + export default ColorIndice \ No newline at end of file diff --git a/cryptide_project/src/model/Indices/Indice.ts b/cryptide_project/src/model/Indices/Indice.ts index 8a5ffec..b2cc5bf 100644 --- a/cryptide_project/src/model/Indices/Indice.ts +++ b/cryptide_project/src/model/Indices/Indice.ts @@ -17,7 +17,10 @@ abstract class Indice { // Méthode abstraite pour être implémentée par les classes dérivées abstract ToString(lang: string): string; - + abstract toJSON(): any + } + + //todo to string ? export default Indice diff --git a/cryptide_project/src/model/Indices/NbEdgesIndice.ts b/cryptide_project/src/model/Indices/NbEdgesIndice.ts index b0e4e7f..2736e3e 100644 --- a/cryptide_project/src/model/Indices/NbEdgesIndice.ts +++ b/cryptide_project/src/model/Indices/NbEdgesIndice.ts @@ -18,6 +18,15 @@ class NbEdgesIndice extends EdgesIndice { let json = GetJsonFile(lang) return `${json.nb_friends_indice_start} ${this.nbNeighbors} ${json.nb_friends_indice_end}`; } + + toJSON() { + return { + type: "NbEdgesIndice", + id: this.id, + nbNeighbors: this.nbNeighbors, + }; + } + } export default NbEdgesIndice \ No newline at end of file diff --git a/cryptide_project/src/model/Indices/NbSportIndice.ts b/cryptide_project/src/model/Indices/NbSportIndice.ts index fe660e7..a34bcbb 100644 --- a/cryptide_project/src/model/Indices/NbSportIndice.ts +++ b/cryptide_project/src/model/Indices/NbSportIndice.ts @@ -18,6 +18,14 @@ class NbSportIndice extends Indice { let json = GetJsonFile(lang) return `${json.nb_sports_indice_start} ${this.nbSport} ${json.nb_sports_indice_end}`; } + + toJSON() { + return { + type: "NbSportIndice", + id: this.id, + nbSport: this.nbSport, + }; + } } export default NbSportIndice \ No newline at end of file diff --git a/cryptide_project/src/model/Indices/SportIndice.ts b/cryptide_project/src/model/Indices/SportIndice.ts index c4038fb..2dbae4b 100644 --- a/cryptide_project/src/model/Indices/SportIndice.ts +++ b/cryptide_project/src/model/Indices/SportIndice.ts @@ -29,6 +29,14 @@ class SportIndice extends Indice { getSports(): Sport[]{ return this.sports } + + toJSON() { + return { + type: "SportIndice", + id: this.id, + sports: this.sports, + }; + } } export default SportIndice \ No newline at end of file diff --git a/cryptide_project/src/model/Person.ts b/cryptide_project/src/model/Person.ts index 782d7d4..caf4b49 100644 --- a/cryptide_project/src/model/Person.ts +++ b/cryptide_project/src/model/Person.ts @@ -78,6 +78,24 @@ class Person { setFriends(friends: Person[]): void { this.friends = friends; } + + toJSON() { + return { + id: this.id, + name: this.name, + age: this.age, + color: this.color, + sports: this.sports, + friends: this.friends.map(friend => ({ + id: friend.id, + name: friend.name, + age: friend.age, + color: friend.color, + sports: friend.sports, + // Ne pas inclure friends ici pour éviter la boucle infinie + })) + }; + } } export default Person diff --git a/cryptide_project/src/model/Player.ts b/cryptide_project/src/model/Player.ts new file mode 100644 index 0000000..4af4485 --- /dev/null +++ b/cryptide_project/src/model/Player.ts @@ -0,0 +1,12 @@ +class Player{ + + public id: string + public name: string; + + constructor(id: string, name: string){ + this.id=id + this.name=name + } +} + +export default Player \ No newline at end of file diff --git a/cryptide_project/src/model/Stub.ts b/cryptide_project/src/model/Stub.ts index eb32c76..a258644 100644 --- a/cryptide_project/src/model/Stub.ts +++ b/cryptide_project/src/model/Stub.ts @@ -11,8 +11,8 @@ import Sport from "./Sport" class Stub{ static GenerateIndice(): Indice[]{ - let indice = new NbEdgesIndice(1, 3) - let indice1 = new NbEdgesIndice(2, 4) + let indice = new NbEdgesIndice(1, 2) + let indice1 = new NbEdgesIndice(2, 3) let ageIndice = new AgeIndice(3, 0, 14) let ageIndice1 = new AgeIndice(4, 15, 19) let ageIndice2 = new AgeIndice(5, 20, 29) @@ -40,12 +40,14 @@ class Stub{ test++ } } - + + //* Voisin couleur for (let i: Color=0; i<5; i++){ indices.push(new ColorEdgesIndice(test, [i])) test++ } + //* Nombre de sport for (let i=1; i<3; i++){ indices.push(new NbSportIndice(test, i)) test++ diff --git a/cryptide_project/src/res/icon/magnifying-glass.png b/cryptide_project/src/res/icon/magnifying-glass.png new file mode 100644 index 0000000..7d29f82 Binary files /dev/null and b/cryptide_project/src/res/icon/magnifying-glass.png differ diff --git a/cryptide_project/yarn.lock b/cryptide_project/yarn.lock index 4402b25..b27a467 100644 --- a/cryptide_project/yarn.lock +++ b/cryptide_project/yarn.lock @@ -1905,6 +1905,11 @@ dependencies: "@sinonjs/commons" "^1.7.0" +"@socket.io/component-emitter@~3.1.0": + version "3.1.0" + resolved "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz" + integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg== + "@surma/rollup-plugin-off-main-thread@^2.2.3": version "2.2.3" resolved "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz" @@ -2162,6 +2167,18 @@ dependencies: "@types/node" "*" +"@types/cookie@^0.4.1": + version "0.4.1" + resolved "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz" + integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== + +"@types/cors@^2.8.12": + version "2.8.16" + resolved "https://registry.npmjs.org/@types/cors/-/cors-2.8.16.tgz" + integrity sha512-Trx5or1Nyg1Fq138PCuWqoApzvoSLWzZ25ORBiHMbbUT42g578lH1GT4TwYDbiUOLFuDsCkfLneT2105fsFWGg== + dependencies: + "@types/node" "*" + "@types/eslint-scope@^3.7.3": version "3.7.7" resolved "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz" @@ -2220,6 +2237,11 @@ resolved "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.44.tgz" integrity sha512-pdGBkAh4ggfXAkiwgmTdROJe3mwvLWJYm6JiaAwCtskAU0Weh+JQyyMTbhvxjxD2n8sr8PrxVwyDzmpnK4pUrQ== +"@types/history@^4.7.11": + version "4.7.11" + resolved "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz" + integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA== + "@types/hoist-non-react-statics@^3.3.1": version "3.3.5" resolved "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz" @@ -2299,7 +2321,7 @@ dependencies: "@types/node" "*" -"@types/node@*": +"@types/node@*", "@types/node@>=10.0.0": version "20.8.10" resolved "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz" integrity sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w== @@ -2343,6 +2365,32 @@ dependencies: "@types/react" "*" +"@types/react-router-dom@^5.3.0": + version "5.3.3" + resolved "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz" + integrity sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw== + dependencies: + "@types/history" "^4.7.11" + "@types/react" "*" + "@types/react-router" "*" + +"@types/react-router-hash-link@^2.4.9": + version "2.4.9" + resolved "https://registry.npmjs.org/@types/react-router-hash-link/-/react-router-hash-link-2.4.9.tgz" + integrity sha512-zl/VMj+lfJZhvjOAQXIlBVPNKSK+/fRG8AUHhlP9++LhlA2ziLeTmbRxIMJI3PCiCTS+W/FosEoDRoNOGH0OzA== + dependencies: + "@types/history" "^4.7.11" + "@types/react" "*" + "@types/react-router-dom" "^5.3.0" + +"@types/react-router@*": + version "5.1.20" + resolved "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz" + integrity sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q== + dependencies: + "@types/history" "^4.7.11" + "@types/react" "*" + "@types/react-transition-group@^4.4.6": version "4.4.8" resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.8.tgz" @@ -2429,6 +2477,11 @@ resolved "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.5.tgz" integrity sha512-I3pkr8j/6tmQtKV/ZzHtuaqYSQvyjGRKH4go60Rr0IDLlFxuRT5V32uvB1mecM5G1EVAUyF/4r4QZ1GHgz+mxA== +"@types/uuid@^9.0.7": + version "9.0.7" + resolved "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.7.tgz" + integrity sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g== + "@types/warning@^3.0.0": version "3.0.2" resolved "https://registry.npmjs.org/@types/warning/-/warning-3.0.2.tgz" @@ -3240,6 +3293,11 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base64id@~2.0.0, base64id@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz" + integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== + batch@0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz" @@ -3795,12 +3853,16 @@ cookie-signature@1.0.6: resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== +<<<<<<< HEAD cookie@0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz" integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== cookie@0.4.2: +======= +cookie@~0.4.1: +>>>>>>> a8c529123b11a032c4ba44a1587af10373815560 version "0.4.2" resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz" integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== @@ -3840,7 +3902,11 @@ core-util-is@~1.0.0: resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== +<<<<<<< HEAD cors@^2.8.5: +======= +cors@^2.8.5, cors@~2.8.5: +>>>>>>> a8c529123b11a032c4ba44a1587af10373815560 version "2.8.5" resolved "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz" integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== @@ -4115,7 +4181,11 @@ debug@^3.2.7: dependencies: ms "^2.1.1" +<<<<<<< HEAD debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@4: +======= +debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2, debug@4: +>>>>>>> a8c529123b11a032c4ba44a1587af10373815560 version "4.3.4" resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -4464,12 +4534,46 @@ encodeurl@~1.0.2: resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== +<<<<<<< HEAD encoding@^0.1.0, encoding@^0.1.12: version "0.1.13" resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz" integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== dependencies: iconv-lite "^0.6.2" +======= +engine.io-client@~6.5.2: + version "6.5.3" + resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz" + integrity sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + engine.io-parser "~5.2.1" + ws "~8.11.0" + xmlhttprequest-ssl "~2.0.0" + +engine.io-parser@~5.2.1: + version "5.2.1" + resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz" + integrity sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ== + +engine.io@~6.5.2: + version "6.5.4" + resolved "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz" + integrity sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg== + dependencies: + "@types/cookie" "^0.4.1" + "@types/cors" "^2.8.12" + "@types/node" ">=10.0.0" + accepts "~1.3.4" + base64id "2.0.0" + cookie "~0.4.1" + cors "~2.8.5" + debug "~4.3.1" + engine.io-parser "~5.2.1" + ws "~8.11.0" +>>>>>>> a8c529123b11a032c4ba44a1587af10373815560 enhanced-resolve@^5.15.0: version "5.15.0" @@ -5004,6 +5108,7 @@ expect@^29.0.0: jest-message-util "^29.7.0" jest-util "^29.7.0" +<<<<<<< HEAD express-session@^1.17.3: version "1.17.3" resolved "https://registry.npmjs.org/express-session/-/express-session-1.17.3.tgz" @@ -5018,6 +5123,8 @@ express-session@^1.17.3: safe-buffer "5.2.1" uid-safe "~2.1.5" +======= +>>>>>>> a8c529123b11a032c4ba44a1587af10373815560 express@^4.17.3, express@^4.18.2: version "4.18.2" resolved "https://registry.npmjs.org/express/-/express-4.18.2.tgz" @@ -8636,6 +8743,11 @@ react-bootstrap@^2.9.1: uncontrollable "^7.2.1" warning "^4.0.3" +react-country-flag@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/react-country-flag/-/react-country-flag-3.1.0.tgz" + integrity sha512-JWQFw1efdv9sTC+TGQvTKXQg1NKbDU2mBiAiRWcKM9F1sK+/zjhP2yGmm8YDddWyZdXVkR8Md47rPMJmo4YO5g== + react-dev-utils@^12.0.1: version "12.0.1" resolved "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz" @@ -8735,7 +8847,7 @@ react-refresh@^0.11.0, "react-refresh@>=0.10.0 <1.0.0": resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz" integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A== -react-router-dom@^6.18.0: +react-router-dom@^6.18.0, react-router-dom@>=4: version "6.18.0" resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.18.0.tgz" integrity sha512-Ubrue4+Ercc/BoDkFQfc6og5zRQ4A8YxSO3Knsne+eRbZ+IepAsK249XBH/XaFuOYOYr3L3r13CXTLvYt5JDjw== @@ -8743,6 +8855,13 @@ react-router-dom@^6.18.0: "@remix-run/router" "1.11.0" react-router "6.18.0" +react-router-hash-link@^2.4.3: + version "2.4.3" + resolved "https://registry.npmjs.org/react-router-hash-link/-/react-router-hash-link-2.4.3.tgz" + integrity sha512-NU7GWc265m92xh/aYD79Vr1W+zAIXDWp3L2YZOYP4rCqPnJ6LI6vh3+rKgkidtYijozHclaEQTAHaAaMWPVI4A== + dependencies: + prop-types "^15.7.2" + react-router@6.18.0: version "6.18.0" resolved "https://registry.npmjs.org/react-router/-/react-router-6.18.0.tgz" @@ -8822,7 +8941,7 @@ react-transition-group@^4.4.5: loose-envify "^1.4.0" prop-types "^15.6.2" -react@*, "react@^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.6.0 || 17 || 18", "react@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", react@^18.0.0, react@^18.2.0, "react@>= 16", react@>=0.14.0, react@>=15.0.0, react@>=16.14.0, react@>=16.3, react@>=16.6.0, react@>=16.8, react@>=16.8.0: +react@*, "react@^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.6.0 || 17 || 18", "react@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", react@^18.0.0, react@^18.2.0, "react@>= 16", react@>=0.14.0, react@>=15, react@>=15.0.0, react@>=16, react@>=16.14.0, react@>=16.3, react@>=16.6.0, react@>=16.8, react@>=16.8.0: version "18.2.0" resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz" integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== @@ -9369,10 +9488,50 @@ slash@^4.0.0: resolved "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz" integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== +<<<<<<< HEAD smart-buffer@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== +======= +socket.io-adapter@~2.5.2: + version "2.5.2" + resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz" + integrity sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA== + dependencies: + ws "~8.11.0" + +socket.io-client@^4.7.2: + version "4.7.2" + resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz" + integrity sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.2" + engine.io-client "~6.5.2" + socket.io-parser "~4.2.4" + +socket.io-parser@~4.2.4: + version "4.2.4" + resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz" + integrity sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + +socket.io@^4.7.2: + version "4.7.2" + resolved "https://registry.npmjs.org/socket.io/-/socket.io-4.7.2.tgz" + integrity sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw== + dependencies: + accepts "~1.3.4" + base64id "~2.0.0" + cors "~2.8.5" + debug "~4.3.2" + engine.io "~6.5.2" + socket.io-adapter "~2.5.2" + socket.io-parser "~4.2.4" +>>>>>>> a8c529123b11a032c4ba44a1587af10373815560 sockjs@^0.3.24: version "0.3.24" @@ -10276,7 +10435,12 @@ utils-merge@1.0.1: resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -"uuid@^3.4.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", uuid@^8.3.2: +"uuid@^3.4.0 || ^7.0.0 || ^8.0.0 || ^9.0.0": + version "9.0.1" + resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + +uuid@^8.3.2: version "8.3.2" resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== @@ -10820,6 +10984,11 @@ ws@^8.13.0: resolved "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz" integrity sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g== +ws@~8.11.0: + version "8.11.0" + resolved "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz" + integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg== + xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz" @@ -10830,6 +10999,11 @@ xmlchars@^2.2.0: resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== +xmlhttprequest-ssl@~2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz" + integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A== + y18n@^5.0.5: version "5.0.8" resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..41b488d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "Cryptid", + "lockfileVersion": 3, + "requires": true, + "packages": {} +}