pull/81/head
Baptiste MARCEL 1 year ago
commit 8bb0d37d35

@ -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",

@ -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"
}
}

@ -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<tab.length; i++){
if (tab[i].id === socket.id){
tab.splice(i, 1)
}
}
map.get(room).push({id: socket.id, name: name})
}
io.to(room).emit("new player", map.get(room))
})
socket.on("lobby created", () =>{
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<tab.length; i++){
if (tab[i].id === socket.id){
tab.splice(i, 1)
}
}
}
})
socket.on("node checked", (id, works, color, room, playerIndex) =>{
console.log(playerIndex)
io.to(room).emit("node checked", id, works, color, playerIndex)
})
});

@ -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() {
// <img src={logo} className="App-logo" alt="logo" />
// </header>
// </div>
//@ts-ignore
<IntlProvider locale={locale} messages={messages[locale]}>
<ThemeProvider>
<BrowserRouter>
{/* <AppNavbar changeLocale={changeLocale} /> */}
{hasNavbarVisible && <AppNavbar changeLocale={changeLocale} />}
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/signup" element={<SignUp />} />
<Route path="/play" element={<Play/>} />
<Route path="/lobby" element={<Lobby/>} />
<Route path="/endgame" element={<EndGame/>} />
<Route path="/game" element={<InGame locale={locale} changeLocale={changeLocale} />} />
<Route path="/info" element={<InfoPage/>} />
</Routes>
</BrowserRouter>
</ThemeProvider>
</IntlProvider>
<GameProvider>
{/*@ts-ignore*/}
<IntlProvider locale={locale} messages={messages[locale]}>
<ThemeProvider>
<BrowserRouter>
{hasNavbarVisible && <AppNavbar changeLocale={changeLocale} />}
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/signup" element={<SignUp />} />
<Route path="/play" element={<Play/>} />
<Route path="/lobby" element={<Lobby/>} />
<Route path="/endgame" element={<EndGame/>} />
<Route path="/game" element={<InGame locale={locale} changeLocale={changeLocale}/>}/>
<Route path="/info" element={<InfoPage locale={locale} changeLocale={changeLocale}/>} />
{/* <Route path="/solo" element={<SoloGame locale={locale} changeLocale={changeLocale} />}/> */}
</Routes>
</BrowserRouter>
</ThemeProvider>
</IntlProvider>
</GameProvider>
);
}

@ -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}

@ -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 (
<div className="choice-bar-container">
<h3 className="choice-bar-heading">Quel joueur voulez-vous interroger ?</h3>
<div>
<button className="choice-bar-button" onClick={async () => await askEveryone()} style={{ backgroundColor: theme.colors.primary }}>Tout le monde</button>
{players.map((player, index) => (
<button key={index} className="choice-bar-button" style={{ backgroundColor: theme.colors.primary }}>
{player}
player.id !== socket.id &&
<button key={index} className="choice-bar-button" onClick={() => askPlayer(player.id)} style={{ backgroundColor: theme.colors.primary }}>
{player.name}
</button>
))}
</div>

@ -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 (
<div className='centerDivH' style={{ backgroundColor: theme.colors.primary }}>
<img src={letter} alt="Indice Letter"/>
</div>
);
}
export default ColoredIndices;

@ -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<MyGraphComponentProps> = ({onNodeClick}) => {
let lastAskingPlayer = 0
let lastNodeId = -1
let first = true
let askedWrong = false
let cptTour: number = 0
const MyGraphComponent: React.FC<MyGraphComponentProps> = ({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<players.length; i++){
if(players[i].id == socket.id){
index=i
break
}
}
let thisPlayerIndex = index
if (first){
first = false
if (!solo){
setActualPlayerIndexData(index)
if (playerIndex == thisPlayerIndex){
handleTurnBarTextChange("À vous de jouer")
handleShowTurnBar(true)
}
}
}
useEffect(() => {
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<MyGraphComponentProps> = ({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<MyGraphComponentProps> = ({onNodeClick}) => {
<div id="graph-container"/>
</>
);
};
function delay(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
export default MyGraphComponent;

@ -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<T extends Indice> {
instance: (new (...args: any[]) => T) | (Function & { prototype: T });
lang: string;
}
const IndiceList: React.FC<IndiceListComponentProps<any>> = ({ instance, lang }) => {
const indices = Stub.GenerateIndice();
return (
<>
<ul className='listContainer'>
{indices
.filter((i) => i instanceof instance)
.map((indice, index) => (
<p key={index}>{indice.ToString(lang)}</p>
))}
</ul>
</>
);
}
export default IndiceList;

@ -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}) {
<Container>
<Navbar.Brand href="/">
<img src={logo} alt="logo" className="logo"/>
{/* <div>
<h2 style={{color:theme.colors.text}}>Cryptide</h2>
<h6 style={{color:theme.colors.text}}>by Crypteam</h6>
</div> */}
</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
@ -59,9 +59,23 @@ function AppNavbar({changeLocale}) {
title={<span><HiLanguage /></span>}
className="navbar-title" id="basic-nav-dropdown">
<NavDropdown.Item onClick={() => changeLocale('fr')}>
<ReactCountryFlag countryCode="FR"
svg
style={{
width: '30px',
height: '20px',
margin: 'auto 10px 3px auto',
}}/>
<FormattedMessage id="languageSelector.french"/>
</NavDropdown.Item>
<NavDropdown.Item onClick={() => changeLocale('en')}>
<ReactCountryFlag countryCode="GB"
svg
style={{
width: '30px',
height: '20px',
margin: 'auto 10px 3px auto',
}}/>
<FormattedMessage id="languageSelector.english"/>
</NavDropdown.Item>
</NavDropdown>

@ -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 (
<div className='centerDivV'>

@ -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 (
<div className='item-horizontal-div'>
<img src={pdp} alt='player-image' height="100" width="100"/>
<h4>{name}</h4>
<div className='item-horizontal-div-container'>
<div className='item-horizontal-div'>
<img src={pdp} alt='player-image' height='100' width='100' />
<h4>{name}</h4>
</div>
{isBot && (
<ToggleButtonGroup type='radio' name={`options-${id}`} defaultValue={1}>
<ToggleButton id={`tbg-radio-1-${id}`} value={1}>
Facile
</ToggleButton>
<ToggleButton id={`tbg-radio-2-${id}`} value={2}>
Intermédiaire
</ToggleButton>
<ToggleButton id={`tbg-radio-3-${id}`} value={3}>
Fort
</ToggleButton>
</ToggleButtonGroup>
)}
</div>
)
}

@ -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) => (
<PersonStatus key={index} state={player.state} name={player.name} />
<PersonStatus key={index} state={player.state} name={player.name + " " + colorToEmoji(positionToColor(index), true)} />
))
}
</div>

@ -0,0 +1,21 @@
import React from "react";
import { useTheme } from "../Style/ThemeContext";
interface TurnBarProps{
text: string
}
const TurnBar: React.FC<TurnBarProps> = ({text})=> {
const theme = useTheme();
return (
<div className='upperInfo'
style={{
borderColor: theme.colors.secondary
}}>
{/* texte changeable et a traduire */}
<p>{text}</p>
</div>
);
};
export default TurnBar;

@ -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<GameContextProps | undefined>(undefined);
interface GameProviderProps {
children: ReactNode;
}
export const GameProvider: React.FC<GameProviderProps> = ({ children }) => {
const [indices, setIndices] = useState<Indice[]>([]);
const [indice, setIndice] = useState<Indice | null>(null);
const [person, setPerson] = useState<Person | null>(null);
const [personNetwork, setPersonNetwork] = useState<PersonNetwork | null>(null);
const [players, setPlayers] = useState<Player[]>([])
const [nodeId, setNodeId] = useState<number | null>(null);
const [askedPersons, setAskedPersons] = useState<Person[]>([])
const [actualPlayerIndex, setActualPlayerIndex] = useState<number>(-1)
const [turnPlayerIndex, setTurnPlayerIndex] = useState<number>(-1)
const [room, setRoom] = useState<string>("")
const [onlyFalse, setOnlyFalse] = useState<boolean>(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 (
<GameContext.Provider value={{ indices, setIndicesData, indice, setIndiceData, person, setPersonData, personNetwork, setPersonNetworkData, players, setPlayersData, nodeId, setNodeIdData, askedPersons, setAskedPersonsData, actualPlayerIndex, setActualPlayerIndexData, turnPlayerIndex, setTurnPlayerIndexData, room, setRoomData, onlyFalse, setOnlyFalseData }}>
{children}
</GameContext.Provider>
);
};
export const useGame = (): GameContextProps => {
const context = useContext(GameContext);
if (!context) {
throw new Error('useGame must be used within an GameProvider');
}
return context;
};

@ -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<number, number[]>()
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

@ -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;
} */
} */
/** 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;
}

@ -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<string[]>([]);
// 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 (
<div id="mainDiv">
<div className='upperInfo'
style={{
borderColor: theme.colors.secondary
}}>
{/* texte changeable et a traduire */}
<p>Dummy, à vous de jouer !</p>
</div>
{showTurnBar && <TurnBar text={turnBarText}/>}
<div id='graphDiv'>
<GraphContainer onNodeClick={handleNodeClick} />
<GraphContainer onNodeClick={handleNodeClick}
handleShowTurnBar={handleShowTurnBar}
handleTurnBarTextChange={handleTurnBarTextChange}
changecptTour={changecptTour}
addToHistory={addToHistory}
solo={IsSolo} />
</div>
<div className='playerlistDiv'>
<button className='button'
style={{
backgroundColor: theme.colors.primary,
{IsSolo ? (
<div className='nbLaps' style={{
backgroundColor: theme.colors.tertiary,
borderColor: theme.colors.secondary
}}
onClick={handleChangeP}>
Players
</button>
}}>
Coups : {cptTour}
</div>
) : (
<div className='playerlistDiv'>
<button className='button'
style={{
backgroundColor: theme.colors.tertiary,
borderColor: theme.colors.secondary
}}
onClick={handleChangeP}>
Players
</button>
</div>
)
}
<div className='historique' id="history-container">
{history.map((item, index) => (
<div key={index}>{item}</div>
))}
</div>
<div className='paramDiv'>
<button className='button'
style={{
backgroundColor: theme.colors.primary,
backgroundColor: theme.colors.tertiary,
borderColor: theme.colors.secondary
}}
onClick={handleChangeS}>
@ -151,10 +201,13 @@ const InGame = ({locale, changeLocale}) => {
</div>
<div className='menuGame'>
{/* <Link to='/info#indice-possible' target='_blank'>
//? redirection impossible apparament (securité des navigateur
*/}
<Link to='/info' target='_blank'>
<button className='button'
style={{
backgroundColor: theme.colors.primary,
backgroundColor: theme.colors.tertiary,
borderColor: theme.colors.secondary
}}>
<img src={Info} alt="info" height="40"/>
@ -167,7 +220,7 @@ const InGame = ({locale, changeLocale}) => {
<Link to='/info' target='_blank'>
<button className='button'
style={{
backgroundColor: theme.colors.primary,
backgroundColor: theme.colors.tertiary,
borderColor: theme.colors.secondary
}}>
<img src={Check} alt="check" height="40"/>
@ -176,10 +229,10 @@ const InGame = ({locale, changeLocale}) => {
<button className='button' onClick={handleChange}
style={{
backgroundColor: theme.colors.primary,
backgroundColor: theme.colors.tertiary,
borderColor: theme.colors.secondary
}}>
<img src={Alpha} alt="indice" height="40"/>
<img src={MGlass} alt="indice" height="40"/>
</button>
</div>
@ -211,9 +264,7 @@ const InGame = ({locale, changeLocale}) => {
</Offcanvas.Header>
<Offcanvas.Body>
{/* Possède les cheveux noir <u>ou</u> joue au basket */}
{indices[0].ToString(locale)}<br/>
{indices[1].ToString(locale)}<br/>
{indices[2].ToString(locale)}
{indice?.ToString(locale)}
</Offcanvas.Body>
</Offcanvas>
@ -248,13 +299,14 @@ const InGame = ({locale, changeLocale}) => {
</Offcanvas.Body>
</Offcanvas>
<div id="bottom-container">
{showChoiceBar && <ChoiceBar />}
</div>
<div id="endgamebutton" > {/* tmp */}
{/*
<div id="endgamebutton" > {/* tmp
<ButtonImgNav dest="/endgame" img={Leave} text='endgame'/>
</div>
*/}
</div>
);
};

@ -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;
} */

@ -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.
<div className='infoPage'>
<h1><FormattedMessage id="informations"/></h1>
<div>
<h1>Informations</h1>
<h2>Indice possible :</h2>
<h3>
couleur de cheveux d'une personne
</h3>
<ul>
<li>
Possède les cheveux noir
</li>
<li>
Possède les cheveux roux
</li>
<li>
Possède les cheveux blond
</li>
<li>
Possède les cheveux brun
</li>
<li>
Possède les cheveux blanc
</li>
</ul>
<div>
<h2><FormattedMessage id="info.intro.title"/></h2>
<p>
<FormattedMessage id="info.intro.text"/>
</p>
</div>
<div className="list">
<h2> <FormattedMessage id="info.sommaire"/> </h2>
<ul>
<li><Link to="#composants-du-jeu"><span><FormattedMessage id="info.title.composant"/></span></Link></li>
<li><Link to="#objectif-du-jeu"><span><FormattedMessage id="info.title.objectif"/></span></Link></li>
<li><Link to="#deroulement-du-jeu"><span><FormattedMessage id="info.title.deroulement"/></span></Link></li>
<li><Link to="#indice-possible"><span><FormattedMessage id="info.title.indice_possible"/></span></Link></li>
</ul>
</div>
<section id="composants-du-jeu">
<h2><FormattedMessage id="info.pions"/> :</h2>
<h4>
<FormattedMessage id="info.sommaire"/>
</h4>
<h6><FormattedMessage id="info.composant.text"/></h6>
<ul>
<p>
<li><h5 className='h5title'><FormattedMessage id="info.composant.carre.title"/> : 🟪🟦🟩🟨🟥🟫</h5></li>
<FormattedMessage id="info.composant.carre"/>
<li><h5 className='h5title'><FormattedMessage id="info.composant.rond.title"/> : 🟣🔵🟢🟡🔴🟤</h5></li>
<FormattedMessage id="info.composant.rond"/>
</p>
</ul>
<hr/>
<h4>
<FormattedMessage id="info.car_perso"/>
</h4>
<h6><FormattedMessage id="info.composant.textcar"/></h6>
<p>
{/*
//TODO mettre icon des ages apres le merge
*/}
<h5 className='h5title'><FormattedMessage id="info.composant.age.title"/> :</h5>
<FormattedMessage id="info.composant.age"/><Link to="#indice-possible"><FormattedMessage id="info.composant.age.link"/></Link>.
<h5 className='h5title'><FormattedMessage id="info.composant.hair_col.title"/> :</h5>
<FormattedMessage id="info.composant.hair_col"/>
<ul>
<li>
<span style={styles.blanc}></span>
<FormattedMessage id="hair.blanc"/>
</li>
<li>
<span style={styles.blond}></span>
<FormattedMessage id="hair.blond"/>
</li>
<li>
<span style={styles.roux}></span>
<FormattedMessage id="hair.roux"/>
</li>
<li>
<span style={styles.chatain}></span>
<FormattedMessage id="hair.chatain"/>
</li>
<li>
<span style={styles.noir}></span>
<FormattedMessage id="hair.noir"/>
</li>
</ul>
<h5 className='h5title'><FormattedMessage id="info.composant.sport.title"/> : 🏀🎳🎾</h5>
<FormattedMessage id="info.composant.sport"/>
<ul>
<li> <FormattedMessage id="info.composant.baseball"/></li>
<li>🏀 <FormattedMessage id="info.composant.basketball"/></li>
<li>🎳 <FormattedMessage id="info.composant.bowling"/></li>
<li> <FormattedMessage id="info.composant.football"/></li>
<li>🎾 <FormattedMessage id="info.composant.tennis"/></li>
</ul>
<FormattedMessage id="info.composant.sport.bis"/>
</p>
</section>
<hr/>
<h3>
Sport d'une personne
</h3>
<ul>
<li>
Effectue du Foot <u>ou</u> du tennis
</li>
<li>
Effectue du rugby <u>ou</u> du tennis
</li>
</ul>
<h3>
Caractèristique des voisins
</h3>
<ul>
<li>
Possède deux voisins footballeur
</li>
<li>
Possède aucun voisin rugbyman
</li>
</ul>
<section id="objectif-du-jeu">
<h2><FormattedMessage id="info.title.objectif"/> :</h2>
<p>
<FormattedMessage id="info.objectif.intro"/>
</p>
<h4>
<FormattedMessage id="info.objectif.t1"/> :
</h4>
<p>
<FormattedMessage id="info.objectif.t1.text"/>
</p>
<h4><FormattedMessage id="info.objectif.t2"/> :</h4>
<p>
<FormattedMessage id="info.objectif.t2.text"/>
</p>
<h4><FormattedMessage id="info.objectif.t3"/> :</h4>
<p>
<FormattedMessage id="info.objectif.t3.text"/>
</p>
<h2>Topographie</h2>
<p>Legende des différents objet disponible sur la carte.</p>
<h4>
Interface :
</h4>
<h6> Pour chacune des parties, vous aurez certains éléments d'interface à disposition :</h6>
<ul>
<li>
<div className='LiInterfaceDisplay'>
<button className='button'
style={{
backgroundColor: theme.colors.tertiary,
borderColor: theme.colors.secondary,
margin:"0 20px"
}}>
<img src={Param} alt="paramètres" height='40'/>
</button>
<p>
Le bouton "<b>Paramètre</b>" permet l'affichage et la gestion de différent paramètres de la partie, comme par exemple le language, l'aide ... .
</p>
</div>
<Alert variant='danger'>
Attention, cette partie ne peut pas être complétée tant que tout les paramètres n'ont pas été choisis !
</Alert>
</li>
<li>
<div className='LiInterfaceDisplay'>
<button className='button'
style={{
backgroundColor: theme.colors.tertiary,
borderColor: theme.colors.secondary,
margin:"0 20px"
}}>
<img src={Info} alt="info" height="40"/>
</button>
<p>
Le bouton "<b>Information</b>" permet de rediriger vers la page de règle du jeu (celle ci).
{/*
//! mais est ce que nous devons rediriger sur les indices possibles ?
*/}
</p>
</div>
</li>
<li>
<div className='LiInterfaceDisplay'>
<button className='button'
style={{
backgroundColor: theme.colors.tertiary,
borderColor: theme.colors.secondary,
margin:"0 20px"
}}>
<img src={Check} alt="check" height="40"/>
</button>
<p>
Le bouton "<b>Fiche de déduction d'indice</b>" permet l'affichage de tableau dynamic permettant, avec le déroulé de la partie, de déduire quels indices sont les plus probables.
</p>
</div>
<Alert variant='danger'>
Attention, cette partie ne peut pas être complétée tant que la page et l'algorithme dédié ne sont pas fait !
</Alert>
</li>
<li>
<div className='LiInterfaceDisplay'>
<button className='button'
style={{
backgroundColor: theme.colors.tertiary,
borderColor: theme.colors.secondary,
margin:"0 20px"
}}>
<img src={MGlass} alt="indice" height="40"/>
</button>
<p>
Le bouton "<b>Indice personnel</b>" 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 !
</p>
</div>
</li>
</ul>
</section>
<hr/>
<section id="deroulement-du-jeu">
<h2><FormattedMessage id="info.title.deroulement"/> :</h2>
<h4>
<u><FormattedMessage id="etape"/> 1</u> : <FormattedMessage id="info.deroulement.e1"/>
</h4>
<p>
<FormattedMessage id="info.deroulement.e1.text"/>
</p>
<h4>
<u><FormattedMessage id="etape"/> 2</u> : <FormattedMessage id="info.deroulement.e2"/>
</h4>
<p>
<FormattedMessage id="info.deroulement.e2.text"/>
</p>
<h4>
<u><FormattedMessage id="etape"/> 3</u> : <FormattedMessage id="info.deroulement.e3"/>
</h4>
<p>
<FormattedMessage id="info.deroulement.e3.text"/>
</p>
</section>
<hr/>
<section id="indice-possible">
<h2><FormattedMessage id="info.title.indice_possible"/> :</h2>
<br/>
<h4>
<FormattedMessage id="info.indice-possible.age"/>
</h4>
<IndiceList instance={AgeIndice} lang={locale}/>
<h4>
<FormattedMessage id="info.indice-possible.hair"/>
</h4>
<IndiceList instance={ColorIndice} lang={locale}/>
<IndiceList instance={ColorEdgesIndice} lang={locale}/>
<hr/>
<h4>
<FormattedMessage id="info.indice-possible.sport"/>
</h4>
<IndiceList instance={SportIndice} lang={locale}/>
<IndiceList instance={NbSportIndice} lang={locale}/>
<h4>
<FormattedMessage id="info.indice-possible.voisin"/>
</h4>
<IndiceList instance={EdgesIndice} lang={locale}/>
<IndiceList instance={NbEdgesIndice} lang={locale}/>
<hr/>
</section>
</div>
);
}

@ -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;
}

@ -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<players.length; i++){
if(players[i].id == socket.id){
index=i
break
}
}
if (room != null){
setRoomData(room)
}
setTurnPlayerIndexData(playerIndex)
setActualPlayerIndexData(index)
setIndiceData(choosenIndices[index])
setPersonData(choosenOne)
setPersonNetworkData(network)
setIndicesData(choosenIndices)
first = true
navigate('/game?solo=false');
});
socket.on("new player", (tab) =>{
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 (
<div className='lobby-container'>
<div className='left-part'>
<div className='player-board'>
<div className='codeDiv' onClick={() => setCodeShowed(!codeShowed)}>
{
codeShowed ? (
<p>Room : {room}</p>
) : (
<p>Room : ******</p>
)
}
</div>
{/* //! voir pour la gestion avec un liste, utilisateur avec le "+ (vous)" et les pdp avec les lettres grecs (?)*/}
<PlayerItemList pdp={Person} name="Dummy (vous)"/>
<PlayerItemList pdp={Bot} name="Boat"/>
<PlayerItemList pdp={Bot} name="Bot-tom"/>
{players.map((player, index) => (
<PlayerItemList key={player.id} pdp={PersonImg} name={player.name} id={player.id}/>
))}
</div>
</div>
@ -46,12 +133,24 @@ function Lobby() {
//? indice avancé ? ==> négation, voisin du 2e degré etc.
}
</ul>
<center>
<ButtonImgNav dest='/game' img={cible} text=' À la chasse !'/> {/* page de baptiste ici */}
<center >
<button className='buttonNabImg' onClick={StartGame}>
<img src={cible} alt="Button Image" height="50" width="50"/>
<p>{"la chasse !"}</p>
</button>
</center>
</div>
</div>
);
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;

@ -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() {
/>
</div>
<div className='buttonGroupVertical'>
<Link to="/lobby">
<button className="ButtonNav" style={{backgroundColor: theme.colors.primary, borderColor: theme.colors.secondary}}> Jouer seul </button>
</Link>
<Link to="/">
<button className="ButtonNav" style={{backgroundColor: theme.colors.primary, borderColor: theme.colors.secondary}}> Créer une partie </button>
</Link>
<Link to="/">
<button className="ButtonNav" style={{backgroundColor: theme.colors.primary, borderColor: theme.colors.secondary}}> Rejoindre </button>
</Link>
<button onClick={launchMastermind} className="ButtonNav" style={{backgroundColor: theme.colors.primary, borderColor: theme.colors.secondary}}> Jouer seul </button>
<button onClick={createLobby} className="ButtonNav" style={{backgroundColor: theme.colors.primary, borderColor: theme.colors.secondary}}> Créer une partie </button>
<button className="ButtonNav" style={{backgroundColor: theme.colors.primary, borderColor: theme.colors.secondary}}> Rejoindre </button>
</div>
</div>
<div className='rightContainer'>

@ -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;
}

@ -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 (
<div id="mainDiv">
<TurnBar text="je suis dans la page solo"/>
<div id='graphDiv'>
{/* <GraphContainer onNodeClick={handleNodeClick} handleShowTurnBar={handleShowTurnBar} FromSolo={true}/> */}
</div>
<div className='nbLaps' style={{
backgroundColor: theme.colors.primary,
borderColor: theme.colors.secondary
}}>
Tour : 5
</div>
<div className='paramDiv'>
<button className='button'
style={{
backgroundColor: theme.colors.primary,
borderColor: theme.colors.secondary
}}
onClick={handleChangeS}>
<img src={Param} alt="paramètres" height='40'/>
</button>
</div>
<div className='menuGame'>
<Link to='/info' target='_blank'>
<button className='button'
style={{
backgroundColor: theme.colors.primary,
borderColor: theme.colors.secondary
}}>
<img src={Info} alt="info" height="40"/>
</button>
</Link>
{/* <button className='button' onClick={() => openInNewTab('http://localhost:3000/play')}> //! avec url =={'>'} dangereux
<img src={Check} alt="check" height="40"/>
</button> */}
<Link to='/info' target='_blank'>
<button className='button'
style={{
backgroundColor: theme.colors.primary,
borderColor: theme.colors.secondary
}}>
<img src={Check} alt="check" height="40"/>
</button>
</Link>
<button className='button' onClick={handleChange}
style={{
backgroundColor: theme.colors.primary,
borderColor: theme.colors.secondary
}}>
<img src={Alpha} alt="indice" height="40"/>
</button>
</div>
{/* <Offcanvas show={showP}
onHide={handleCloseP}>
<Offcanvas.Header closeButton>
<Offcanvas.Title>Joueurs</Offcanvas.Title>
<h3>Il y a {players.length} joueurs</h3>
</Offcanvas.Header>
<Offcanvas.Body>
<PlayerList players={players} />
</Offcanvas.Body>
</Offcanvas> */}
<Offcanvas show={show}
onHide={handleClose}
placement='end'
scroll={true}
backdrop={false}
style={{ height: '20%', width: '25%', top: '60vh' }}>
<Offcanvas.Header closeButton>
<Offcanvas.Title>Indice</Offcanvas.Title>
</Offcanvas.Header>
<Offcanvas.Body>
{/* Possède les cheveux noir <u>ou</u> joue au basket */}
{indice?.ToString(locale)}
</Offcanvas.Body>
</Offcanvas>
{
//* canva pour les paramètres
}
<Offcanvas show={showS}
onHide={handleCloseS}
placement='top'
style={{height: '30%', width: '30%', left: '70%' }}>
<Offcanvas.Header closeButton>
<Offcanvas.Title><img src={Param} alt='param'/> Paramètres</Offcanvas.Title>
</Offcanvas.Header>
<Offcanvas.Body>
<Nav className="me-auto">
<NavDropdown
title={<span><HiLanguage/> Language </span>}
className="navbar-title" id="basic-nav-dropdown">
<NavDropdown.Item onClick={() => changeLocale('fr')}>
<FormattedMessage id="languageSelector.french"/>
</NavDropdown.Item>
<NavDropdown.Item onClick={() => changeLocale('en')}>
<FormattedMessage id="languageSelector.english"/>
</NavDropdown.Item>
</NavDropdown>
</Nav>
<label>
<Switch checked={SwitchEnabled} onChange={setSwitchEnabled}/>
<p>Afficher les noeuds possibles</p>
</label>
</Offcanvas.Body>
</Offcanvas>
<div id="bottom-container">
{showChoiceBar && <ChoiceBar />}
</div>
{/*
<div id="endgamebutton" > {/* tmp
<ButtonImgNav dest="/endgame" img={Leave} text='endgame'/>
</div>
*/}
</div>
);
};
export default SoloGame;

@ -0,0 +1,6 @@
import { io } from "socket.io-client";
const socket = io("http://127.20.10.4:3002");
export {socket}

@ -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;
}

@ -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

@ -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"
}

@ -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"
}

@ -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]
}
}

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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++

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

@ -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"

6
package-lock.json generated

@ -0,0 +1,6 @@
{
"name": "Cryptid",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}
Loading…
Cancel
Save