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

@ -28,16 +28,21 @@
"mysql": "^2.18.1", "mysql": "^2.18.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-bootstrap": "^2.9.1", "react-bootstrap": "^2.9.1",
"react-country-flag": "^3.1.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-icons": "^4.11.0", "react-icons": "^4.11.0",
"react-intl": "^6.5.2", "react-intl": "^6.5.2",
"react-router-dom": "^6.18.0", "react-router-dom": "^6.18.0",
"react-router-hash-link": "^2.4.3",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"react-switch": "^7.0.0", "react-switch": "^7.0.0",
"sqlite3": "^5.1.6",
"typescript": "^5.2.2", "typescript": "^5.2.2",
"vis-network": "^9.1.9", "vis-network": "^9.1.9",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
},
"devDependencies": {
"@types/react-router-hash-link": "^2.4.9",
"@types/uuid": "^9.0.7"
} }
}, },
"node_modules/@aashutoshrathi/word-wrap": { "node_modules/@aashutoshrathi/word-wrap": {
@ -3854,6 +3859,11 @@
"@sinonjs/commons": "^1.7.0" "@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": { "node_modules/@surma/rollup-plugin-off-main-thread": {
"version": "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", "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": "*" "@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": { "node_modules/@types/eslint": {
"version": "8.44.7", "version": "8.44.7",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.7.tgz", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.7.tgz",
@ -4333,6 +4356,12 @@
"integrity": "sha512-pdGBkAh4ggfXAkiwgmTdROJe3mwvLWJYm6JiaAwCtskAU0Weh+JQyyMTbhvxjxD2n8sr8PrxVwyDzmpnK4pUrQ==", "integrity": "sha512-pdGBkAh4ggfXAkiwgmTdROJe3mwvLWJYm6JiaAwCtskAU0Weh+JQyyMTbhvxjxD2n8sr8PrxVwyDzmpnK4pUrQ==",
"peer": true "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": { "node_modules/@types/hoist-non-react-statics": {
"version": "3.3.5", "version": "3.3.5",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz",
@ -4503,6 +4532,38 @@
"@types/react": "*" "@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": { "node_modules/@types/react-transition-group": {
"version": "4.4.8", "version": "4.4.8",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.8.tgz", "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", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.5.tgz",
"integrity": "sha512-I3pkr8j/6tmQtKV/ZzHtuaqYSQvyjGRKH4go60Rr0IDLlFxuRT5V32uvB1mecM5G1EVAUyF/4r4QZ1GHgz+mxA==" "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": { "node_modules/@types/warning": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.2.tgz", "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", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" "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": { "node_modules/batch": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
@ -7559,15 +7634,6 @@
"node": ">= 0.8" "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": { "node_modules/enhanced-resolve": {
"version": "5.15.0", "version": "5.15.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", "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": { "node_modules/react-dev-utils": {
"version": "12.0.1", "version": "12.0.1",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",
@ -15696,6 +15773,18 @@
"react-dom": ">=16.8" "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": { "node_modules/react-scripts": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
@ -16614,16 +16703,6 @@
"node": ">=8" "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": { "node_modules/sockjs": {
"version": "0.3.24", "version": "0.3.24",
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
@ -16634,34 +16713,6 @@
"websocket-driver": "^0.7.4" "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": { "node_modules/source-list-map": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
@ -18118,9 +18169,14 @@
} }
}, },
"node_modules/uuid": { "node_modules/uuid": {
"version": "8.3.2", "version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"peer": true,
"bin": { "bin": {
"uuid": "dist/bin/uuid" "uuid": "dist/bin/uuid"
} }
@ -19097,6 +19153,14 @@
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" "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": { "node_modules/y18n": {
"version": "5.0.8", "version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",

@ -22,13 +22,17 @@
"mysql": "^2.18.1", "mysql": "^2.18.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-bootstrap": "^2.9.1", "react-bootstrap": "^2.9.1",
"react-country-flag": "^3.1.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-icons": "^4.11.0", "react-icons": "^4.11.0",
"react-intl": "^6.5.2", "react-intl": "^6.5.2",
"react-router-dom": "^6.18.0", "react-router-dom": "^6.18.0",
"react-router-hash-link": "^2.4.3",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"react-switch": "^7.0.0", "react-switch": "^7.0.0",
"sqlite3": "^5.1.6", "sqlite3": "^5.1.6",
"socket.io": "^4.7.2",
"socket.io-client": "^4.7.2",
"typescript": "^5.2.2", "typescript": "^5.2.2",
"vis-network": "^9.1.9", "vis-network": "^9.1.9",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
@ -56,5 +60,9 @@
"last 1 firefox version", "last 1 firefox version",
"last 1 safari 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 React from 'react';
import { useState } from 'react'; import { useState } from 'react';
import { IntlProvider } from 'react-intl'; import { IntlProvider } from 'react-intl';
import { GameProvider } from './Contexts/GameContext';
/* Page */ /* Page */
import Home from './Pages/Home'; import Home from './Pages/Home';
@ -32,6 +33,7 @@ import 'bootstrap/dist/css/bootstrap.min.css';
/* Internationnalisation */ /* Internationnalisation */
import messagesFr from './Translations/fr.json'; import messagesFr from './Translations/fr.json';
import messagesEn from './Translations/en.json'; import messagesEn from './Translations/en.json';
import SoloGame from './Pages/SoloGame';
const messages = { const messages = {
fr: messagesFr, fr: messagesFr,
@ -61,12 +63,12 @@ function App() {
// <img src={logo} className="App-logo" alt="logo" /> // <img src={logo} className="App-logo" alt="logo" />
// </header> // </header>
// </div> // </div>
<GameProvider>
//@ts-ignore {/*@ts-ignore*/}
<IntlProvider locale={locale} messages={messages[locale]}> <IntlProvider locale={locale} messages={messages[locale]}>
<ThemeProvider> <ThemeProvider>
<BrowserRouter> <BrowserRouter>
{/* <AppNavbar changeLocale={changeLocale} /> */}
{hasNavbarVisible && <AppNavbar changeLocale={changeLocale} />} {hasNavbarVisible && <AppNavbar changeLocale={changeLocale} />}
<Routes> <Routes>
<Route path="/" element={<Home />} /> <Route path="/" element={<Home />} />
@ -76,11 +78,14 @@ function App() {
<Route path="/lobby" element={<Lobby/>} /> <Route path="/lobby" element={<Lobby/>} />
<Route path="/endgame" element={<EndGame/>} /> <Route path="/endgame" element={<EndGame/>} />
<Route path="/game" element={<InGame locale={locale} changeLocale={changeLocale}/>}/> <Route path="/game" element={<InGame locale={locale} changeLocale={changeLocale}/>}/>
<Route path="/info" element={<InfoPage/>} /> <Route path="/info" element={<InfoPage locale={locale} changeLocale={changeLocale}/>} />
{/* <Route path="/solo" element={<SoloGame locale={locale} changeLocale={changeLocale} />}/> */}
</Routes> </Routes>
</BrowserRouter> </BrowserRouter>
</ThemeProvider> </ThemeProvider>
</IntlProvider> </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 React from 'react';
import { useGame } from '../Contexts/GameContext';
import { socket } from '../SocketConfig';
import './ChoiceBar.css'; import './ChoiceBar.css';
import { useTheme } from '../Style/ThemeContext'; import { useTheme } from '../Style/ThemeContext';
import IndiceTesterFactory from '../model/Factory/IndiceTesterFactory';
import { positionToColor } from '../ColorHelper';
const ChoiceBar = () => { const ChoiceBar = () => {
const players = ['Player1', 'Player2', 'Player3']; const { players, nodeId, actualPlayerIndex, personNetwork, indices, room } = useGame();
const theme = useTheme(); 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 ( return (
<div className="choice-bar-container"> <div className="choice-bar-container">
<h3 className="choice-bar-heading">Quel joueur voulez-vous interroger ?</h3> <h3 className="choice-bar-heading">Quel joueur voulez-vous interroger ?</h3>
<div> <div>
<button className="choice-bar-button" onClick={async () => await askEveryone()} style={{ backgroundColor: theme.colors.primary }}>Tout le monde</button>
{players.map((player, index) => ( {players.map((player, index) => (
<button key={index} className="choice-bar-button" style={{ backgroundColor: theme.colors.primary }}> player.id !== socket.id &&
{player} <button key={index} className="choice-bar-button" onClick={() => askPlayer(player.id)} style={{ backgroundColor: theme.colors.primary }}>
{player.name}
</button> </button>
))} ))}
</div> </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 NodePerson from "../model/Graph/NodePerson";
import IndiceTesterFactory from "../model/Factory/IndiceTesterFactory"; import IndiceTesterFactory from "../model/Factory/IndiceTesterFactory";
import GameCreator from "../model/GameCreator"; 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 { interface MyGraphComponentProps {
onNodeClick: (shouldShowChoiceBar: boolean) => void; onNodeClick: (shouldShowChoiceBar: boolean) => void;
handleShowTurnBar: (shouldShowTurnBar: boolean) => void
handleTurnBarTextChange: (newTurnBarText: string) => void
changecptTour: (newcptTour : number) => void
addToHistory: (message : string) => void
solo : boolean
}
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)
}
}
} }
const MyGraphComponent: React.FC<MyGraphComponentProps> = ({onNodeClick}) => {
useEffect(() => { useEffect(() => {
if (personNetwork == null){
return
}
const graph = GraphCreator.CreateGraph(personNetwork)
const container = document.getElementById('graph-container'); const container = document.getElementById('graph-container');
if (!container) { if (!container) {
console.error("Container not found"); console.error("Container not found");
return; return;
} }
// Charger les données dans le graph // Charger les données dans le graph
const nodes = new DataSet(graph.nodesPerson); const nodes = new DataSet(graph.nodesPerson);
@ -61,23 +104,111 @@ const MyGraphComponent: React.FC<MyGraphComponentProps> = ({onNodeClick}) => {
const networkData = { nodes: nodes, edges: graph.edges }; const networkData = { nodes: nodes, edges: graph.edges };
const network = new Network(container, networkData, initialOptions); const network = new Network(container, networkData, initialOptions);
if (!solo){
socket.on("asked all", (id) =>{
const pers = personNetwork.getPersons().find((p) => p.getId() == id)
if (pers!=undefined){
askedPersons.push(pers)
}
})
//TEST POUR MONTRER QU'IL Y EN A QU'UN A CHAQUE FOIS socket.on("node checked",(id, works, color, newPlayerIndex) => {
/* const node = nodes.get().find((n) => id == n.id)
networkPerson.getPersons().forEach(p => { 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)
}
}
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{
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 let a = 0
for (let i of choosenIndices){ for (let i of indices){
let tester = IndiceTesterFactory.Create(i) let tester = IndiceTesterFactory.Create(i)
if (tester.Works(p)){ if (tester.Works(p)){
a++ a++
} }
} }
if (a==choosenIndices.length){ if (a==indices.length){
networkData.nodes.update({id: p.getId(), label: p.getName() + "\n🔵"}) //networkData.nodes.update({id: p.getId(), label: p.getName() + "\n🔵"})
console.log(p)
} }
}); });
*/
// Gérer le changement entre la physique et le déplacement manuel // Gérer le changement entre la physique et le déplacement manuel
network.on("dragging", (params) => { network.on("dragging", (params) => {
@ -88,30 +219,60 @@ const MyGraphComponent: React.FC<MyGraphComponentProps> = ({onNodeClick}) => {
} }
}); });
network.on("click", (params) => { network.on("click", async (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(params.nodes.length > 0){
if (pers!=undefined){ setNodeIdData(params.nodes[0])
//@ts-ignore // addToHistory("Le joueur a cliqué") //! TEST DEBUG
const node = nodes.get().find((n) => params.nodes[0] == n.id) if (!solo){
if (node != undefined){ if (askedWrong){
var tester = IndiceTesterFactory.Create(testIndice) const person = personNetwork?.getPersons().find((p) => p.getId() == params.nodes[0])
if (tester.Works(pers)){ if (person !== undefined && indice !== null){
networkData.nodes.update({id: params.nodes[0], label: node.label + "🔵"}) 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{ else{
networkData.nodes.update({id: params.nodes[0], label: node.label + "🟦"}) 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
// Renvoyer un true pour afficher la choice bar cptTour ++; // On Incrémente le nombre de tour du joueur
onNodeClick(true) 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{ else{
// Renvoyer un false pour cacher la choice bar // Renvoyer un false pour cacher la choice bar
onNodeClick(false) onNodeClick(false)
@ -124,6 +285,12 @@ const MyGraphComponent: React.FC<MyGraphComponentProps> = ({onNodeClick}) => {
<div id="graph-container"/> <div id="graph-container"/>
</> </>
); );
};
function delay(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
export default MyGraphComponent; 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'; import logo from '../res/img/logo2_preview_rev_1.png';
/* Components */ /* Components */
import ReactCountryFlag from "react-country-flag"
/* Style */
import './NavBar.css'; import './NavBar.css';
/* Style */ /* Style */
@ -28,10 +32,6 @@ function AppNavbar({changeLocale}) {
<Container> <Container>
<Navbar.Brand href="/"> <Navbar.Brand href="/">
<img src={logo} alt="logo" className="logo"/> <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.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" /> <Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav"> <Navbar.Collapse id="basic-navbar-nav">
@ -59,9 +59,23 @@ function AppNavbar({changeLocale}) {
title={<span><HiLanguage /></span>} title={<span><HiLanguage /></span>}
className="navbar-title" id="basic-nav-dropdown"> className="navbar-title" id="basic-nav-dropdown">
<NavDropdown.Item onClick={() => changeLocale('fr')}> <NavDropdown.Item onClick={() => changeLocale('fr')}>
<ReactCountryFlag countryCode="FR"
svg
style={{
width: '30px',
height: '20px',
margin: 'auto 10px 3px auto',
}}/>
<FormattedMessage id="languageSelector.french"/> <FormattedMessage id="languageSelector.french"/>
</NavDropdown.Item> </NavDropdown.Item>
<NavDropdown.Item onClick={() => changeLocale('en')}> <NavDropdown.Item onClick={() => changeLocale('en')}>
<ReactCountryFlag countryCode="GB"
svg
style={{
width: '30px',
height: '20px',
margin: 'auto 10px 3px auto',
}}/>
<FormattedMessage id="languageSelector.english"/> <FormattedMessage id="languageSelector.english"/>
</NavDropdown.Item> </NavDropdown.Item>
</NavDropdown> </NavDropdown>

@ -9,7 +9,7 @@ import Person from '../res/img/Person.png'
import leave from '../res/img/bot.png' import leave from '../res/img/bot.png'
//@ts-ignore //@ts-ignore
function PersonStatus({img = Person, state= leave, name = "Dummy"}) { function PersonStatus({img = Person, state= Person, name = "Dummy"}) {
const theme=useTheme(); const theme=useTheme();
return ( return (
<div className='centerDivV'> <div className='centerDivV'>

@ -1,14 +1,36 @@
import React from 'react'; import React from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import '../Style/Global.css'; 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 //@ts-ignore
function PlayerItemList({ pdp, name}) { function PlayerItemList({ pdp, name, id}) {
const isBot = pdp === Bot;
return ( return (
<div className='item-horizontal-div-container'>
<div className='item-horizontal-div'> <div className='item-horizontal-div'>
<img src={pdp} alt='player-image' height="100" width="100"/> <img src={pdp} alt='player-image' height='100' width='100' />
<h4>{name}</h4> <h4>{name}</h4>
</div> </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 React from 'react';
import { colorToEmoji, positionToColor } from '../ColorHelper';
import PersonStatus from './PersonStatus'; import PersonStatus from './PersonStatus';
//@ts-ignore //@ts-ignore
@ -9,7 +10,7 @@ function PlayerList({ players }) {
{ {
//@ts-ignore //@ts-ignore
players.map((player, index) => ( 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> </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; 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{ #endgamebutton{
position: absolute; position: absolute;
z-index: 1; z-index: 1;
@ -91,7 +107,7 @@
.button{ .button{
/*background-color: #85C9C2;*/ /*background-color: #85C9C2;*/
border: solid 2px #85C9C2; border: solid 2px #7aa3f4;
border-radius: 10px; border-radius: 10px;
width: 100px; width: 100px;
@ -102,3 +118,24 @@
columns: 2 auto; columns: 2 auto;
grid-row: 2; 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"; import Switch from "react-switch";
/* Style */ /* Style */
@ -10,6 +10,7 @@ import ChoiceBar from '../Components/ChoiceBar';
import ButtonImgNav from '../Components/ButtonImgNav'; import ButtonImgNav from '../Components/ButtonImgNav';
import PersonStatus from '../Components/PersonStatus'; import PersonStatus from '../Components/PersonStatus';
import PlayerList from '../Components/PlayerList'; import PlayerList from '../Components/PlayerList';
import TurnBar from '../Components/TurnBar';
/* Icon */ /* Icon */
import Leave from "../res/icon/leave.png"; 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 Info from "../res/icon/infoGreen.png";
import Check from "../res/icon/checkboxGreen.png"; import Check from "../res/icon/checkboxGreen.png";
import Alpha from "../res/GreekLetters/alphaW.png"; import Alpha from "../res/GreekLetters/alphaW.png";
import MGlass from "../res/icon/magnifying-glass.png";
/* nav */ /* nav */
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
@ -32,38 +34,60 @@ import { HiLanguage } from 'react-icons/hi2';
import { Nav, NavDropdown } from 'react-bootstrap'; import { Nav, NavDropdown } from 'react-bootstrap';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import Color from '../model/Color'; import Color from '../model/Color';
import { useGame } from '../Contexts/GameContext';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { NavLink } from 'react-router-dom';
//@ts-ignore //@ts-ignore
const InGame = ({locale, changeLocale}) => { const InGame = ({locale, changeLocale}) => {
const players = [ const theme = useTheme();
{ state: Replay, name: 'Dummy' },
{ state: Replay, name: 'Boat' },
{ state: Replay, name: 'Bot-tom' }, const params = new URLSearchParams(window.location.search);
{ state: Replay, name: 'Dummy' },
{ state: Replay, name: 'Boat' }, //* Gestion solo
{ state: Replay, name: 'Bot-tom' }, let IsSolo: boolean = true
{ state: Replay, name: 'Dummy' }, const solotmp = params.get('solo');
{ state: Replay, name: 'Boat' }, if (solotmp == "false"){
{ state: Replay, name: 'Bot-tom' }, IsSolo=false
{ state: Replay, name: 'Dummy' }, }
{ state: Replay, name: 'Boat' },
{ state: Replay, name: 'Bot-tom' }, //* Historique
{ state: Replay, name: 'Dummy' }, const [history, setHistory] = useState<string[]>([]);
{ state: Replay, name: 'Boat' },
{ state: Replay, name: 'Bot-tom' } // Fonction pour ajouter un élément à l'historique
// Ajouter d'autres joueurs au besoin 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 [showChoiceBar, setShowChoiceBar] = useState(false);
const [showTurnBar, setShowTurnBar] = useState(false);
const [turnBarText, setTurnBarText] = useState("");
const handleNodeClick = (shouldShowChoiceBar: boolean) => { const handleNodeClick = (shouldShowChoiceBar: boolean) => {
setShowChoiceBar(shouldShowChoiceBar); setShowChoiceBar(shouldShowChoiceBar);
}; };
const handleShowTurnBar = (shouldShowTurnBar: boolean) => {
setShowTurnBar(shouldShowTurnBar);
};
const handleTurnBarTextChange = (newTurnBarText: string) =>{
setTurnBarText(newTurnBarText)
}
/* offcanvas */ /* offcanvas */
//? faire une fonction pour close et show en fonction de l'etat du canva ? //? 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 ? //? comment faire pour eviter la recopie de tout le code a chaque canvas boostrap ?
@ -79,6 +103,13 @@ const InGame = ({locale, changeLocale}) => {
const handleCloseS = () => setShowS(false); const handleCloseS = () => setShowS(false);
const handleShowS = () => setShowS(true); const handleShowS = () => setShowS(true);
const [cptTour, setcptTour] = useState(0);
//@ts-ignore
const changecptTour = (newcptTour) => {
setcptTour(newcptTour);
};
const handleChange = () => { const handleChange = () => {
if (show){ if (show){
handleClose() handleClose()
@ -114,35 +145,54 @@ const InGame = ({locale, changeLocale}) => {
const [SwitchEnabled, setSwitchEnabled] = useState(false) const [SwitchEnabled, setSwitchEnabled] = useState(false)
const indices = Stub.GenerateIndice() const indices = Stub.GenerateIndice()
const { indice, players } = useGame();
return ( return (
<div id="mainDiv"> <div id="mainDiv">
<div className='upperInfo' {showTurnBar && <TurnBar text={turnBarText}/>}
style={{
borderColor: theme.colors.secondary
}}>
{/* texte changeable et a traduire */}
<p>Dummy, à vous de jouer !</p>
</div>
<div id='graphDiv'> <div id='graphDiv'>
<GraphContainer onNodeClick={handleNodeClick} /> <GraphContainer onNodeClick={handleNodeClick}
handleShowTurnBar={handleShowTurnBar}
handleTurnBarTextChange={handleTurnBarTextChange}
changecptTour={changecptTour}
addToHistory={addToHistory}
solo={IsSolo} />
</div> </div>
{IsSolo ? (
<div className='nbLaps' style={{
backgroundColor: theme.colors.tertiary,
borderColor: theme.colors.secondary
}}>
Coups : {cptTour}
</div>
) : (
<div className='playerlistDiv'> <div className='playerlistDiv'>
<button className='button' <button className='button'
style={{ style={{
backgroundColor: theme.colors.primary, backgroundColor: theme.colors.tertiary,
borderColor: theme.colors.secondary borderColor: theme.colors.secondary
}} }}
onClick={handleChangeP}> onClick={handleChangeP}>
Players Players
</button> </button>
</div> </div>
)
}
<div className='historique' id="history-container">
{history.map((item, index) => (
<div key={index}>{item}</div>
))}
</div>
<div className='paramDiv'> <div className='paramDiv'>
<button className='button' <button className='button'
style={{ style={{
backgroundColor: theme.colors.primary, backgroundColor: theme.colors.tertiary,
borderColor: theme.colors.secondary borderColor: theme.colors.secondary
}} }}
onClick={handleChangeS}> onClick={handleChangeS}>
@ -151,10 +201,13 @@ const InGame = ({locale, changeLocale}) => {
</div> </div>
<div className='menuGame'> <div className='menuGame'>
{/* <Link to='/info#indice-possible' target='_blank'>
//? redirection impossible apparament (securité des navigateur
*/}
<Link to='/info' target='_blank'> <Link to='/info' target='_blank'>
<button className='button' <button className='button'
style={{ style={{
backgroundColor: theme.colors.primary, backgroundColor: theme.colors.tertiary,
borderColor: theme.colors.secondary borderColor: theme.colors.secondary
}}> }}>
<img src={Info} alt="info" height="40"/> <img src={Info} alt="info" height="40"/>
@ -167,7 +220,7 @@ const InGame = ({locale, changeLocale}) => {
<Link to='/info' target='_blank'> <Link to='/info' target='_blank'>
<button className='button' <button className='button'
style={{ style={{
backgroundColor: theme.colors.primary, backgroundColor: theme.colors.tertiary,
borderColor: theme.colors.secondary borderColor: theme.colors.secondary
}}> }}>
<img src={Check} alt="check" height="40"/> <img src={Check} alt="check" height="40"/>
@ -176,10 +229,10 @@ const InGame = ({locale, changeLocale}) => {
<button className='button' onClick={handleChange} <button className='button' onClick={handleChange}
style={{ style={{
backgroundColor: theme.colors.primary, backgroundColor: theme.colors.tertiary,
borderColor: theme.colors.secondary borderColor: theme.colors.secondary
}}> }}>
<img src={Alpha} alt="indice" height="40"/> <img src={MGlass} alt="indice" height="40"/>
</button> </button>
</div> </div>
@ -211,9 +264,7 @@ const InGame = ({locale, changeLocale}) => {
</Offcanvas.Header> </Offcanvas.Header>
<Offcanvas.Body> <Offcanvas.Body>
{/* Possède les cheveux noir <u>ou</u> joue au basket */} {/* Possède les cheveux noir <u>ou</u> joue au basket */}
{indices[0].ToString(locale)}<br/> {indice?.ToString(locale)}
{indices[1].ToString(locale)}<br/>
{indices[2].ToString(locale)}
</Offcanvas.Body> </Offcanvas.Body>
</Offcanvas> </Offcanvas>
@ -248,13 +299,14 @@ const InGame = ({locale, changeLocale}) => {
</Offcanvas.Body> </Offcanvas.Body>
</Offcanvas> </Offcanvas>
<div id="bottom-container"> <div id="bottom-container">
{showChoiceBar && <ChoiceBar />} {showChoiceBar && <ChoiceBar />}
</div> </div>
<div id="endgamebutton" > {/* tmp */} {/*
<div id="endgamebutton" > {/* tmp
<ButtonImgNav dest="/endgame" img={Leave} text='endgame'/> <ButtonImgNav dest="/endgame" img={Leave} text='endgame'/>
</div> </div>
*/}
</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 */ /* Style */
import '../Style/Global.css'; import '../Style/Global.css';
import './InfoPage.css';
import { FormattedMessage } from 'react-intl'; 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
//@ts-ignore
function InfoPage({locale, changeLocale}) {
function InfoPage() { //! cette page n'affiche que des informations et est suceptible de changer selon le context. 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 ( 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> <div>
<h1>Informations</h1> <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>
<h2>Indice possible :</h2> <section id="composants-du-jeu">
<h3> <h2><FormattedMessage id="info.pions"/> :</h2>
couleur de cheveux d'une personne <h4>
</h3> <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> <ul>
<li> <li>
Possède les cheveux noir <span style={styles.blanc}></span>
<FormattedMessage id="hair.blanc"/>
</li> </li>
<li> <li>
Possède les cheveux roux <span style={styles.blond}></span>
<FormattedMessage id="hair.blond"/>
</li> </li>
<li> <li>
Possède les cheveux blond <span style={styles.roux}></span>
<FormattedMessage id="hair.roux"/>
</li> </li>
<li> <li>
Possède les cheveux brun <span style={styles.chatain}></span>
<FormattedMessage id="hair.chatain"/>
</li> </li>
<li> <li>
Possède les cheveux blanc <span style={styles.noir}></span>
<FormattedMessage id="hair.noir"/>
</li> </li>
</ul> </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/> <hr/>
<h3> <section id="objectif-du-jeu">
Sport d'une personne <h2><FormattedMessage id="info.title.objectif"/> :</h2>
</h3> <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>
<h4>
Interface :
</h4>
<h6> Pour chacune des parties, vous aurez certains éléments d'interface à disposition :</h6>
<ul> <ul>
<li> <li>
Effectue du Foot <u>ou</u> du tennis <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>
<li> <li>
Effectue du rugby <u>ou</u> du tennis <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>
</ul>
<h3>
Caractèristique des voisins
</h3>
<ul>
<li> <li>
Possède deux voisins footballeur <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>
<li> <li>
Possède aucun voisin rugbyman <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> </li>
</ul> </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}/>
<h2>Topographie</h2> <h4>
<p>Legende des différents objet disponible sur la carte.</p> <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> </div>
); );
} }

@ -1,5 +1,4 @@
.lobby-container { .lobby-container {
display: flex; display: flex;
background-color: #fff; background-color: #fff;
@ -41,4 +40,17 @@
margin: 20px; 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'; import React, { useEffect, useState } from 'react';
/* Style */
import './Lobby.css'; import './Lobby.css';
import { useTheme } from '../Style/ThemeContext'; import { useTheme } from '../Style/ThemeContext';
/* res */ /* 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 Bot from '../res/img/bot.png';
import param from '../res/icon/param.png'; import param from '../res/icon/param.png';
import cible from '../res/icon/cible.png'; import cible from '../res/icon/cible.png';
/* Component */ /* Component */
import ButtonImgNav from '../Components/ButtonImgNav'; 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() { function Lobby() {
const theme=useTheme(); 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 ( return (
<div className='lobby-container'> <div className='lobby-container'>
<div className='left-part'> <div className='left-part'>
<div className='player-board'> <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 (?)*/} {/* //! voir pour la gestion avec un liste, utilisateur avec le "+ (vous)" et les pdp avec les lettres grecs (?)*/}
<PlayerItemList pdp={Person} name="Dummy (vous)"/> {players.map((player, index) => (
<PlayerItemList pdp={Bot} name="Boat"/> <PlayerItemList key={player.id} pdp={PersonImg} name={player.name} id={player.id}/>
<PlayerItemList pdp={Bot} name="Bot-tom"/> ))}
</div> </div>
</div> </div>
@ -47,11 +134,23 @@ function Lobby() {
} }
</ul> </ul>
<center > <center >
<ButtonImgNav dest='/game' img={cible} text=' À la chasse !'/> {/* page de baptiste ici */} <button className='buttonNabImg' onClick={StartGame}>
<img src={cible} alt="Button Image" height="50" width="50"/>
<p>{"la chasse !"}</p>
</button>
</center> </center>
</div> </div>
</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; export default Lobby;

@ -1,5 +1,4 @@
import React from 'react'; import React, { useEffect, useState } from 'react';
import {useEffect, useState} from 'react';
/* Style */ /* Style */
import './Play.css'; import './Play.css';
@ -19,6 +18,10 @@ import Person from '../res/img/Person.png';
import trophy from '../res/icon/trophy.png'; import trophy from '../res/icon/trophy.png';
import param from '../res/icon/param.png'; import param from '../res/icon/param.png';
import share from '../res/icon/share.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() { 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 ( return (
@ -69,15 +114,10 @@ function Play() {
/> />
</div> </div>
<div className='buttonGroupVertical'> <div className='buttonGroupVertical'>
<Link to="/lobby"> <button onClick={launchMastermind} className="ButtonNav" style={{backgroundColor: theme.colors.primary, borderColor: theme.colors.secondary}}> Jouer seul </button>
<button 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>
</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> <button className="ButtonNav" style={{backgroundColor: theme.colors.primary, borderColor: theme.colors.secondary}}> Rejoindre </button>
</Link>
</div> </div>
</div> </div>
<div className='rightContainer'> <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; align-items: center;
} }
.item-horizontal-div-container{
display: flex;
align-items: center;
margin-right: 20px;
}
.item-horizontal-div{ .item-horizontal-div{
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -43,3 +49,7 @@
form{ form{
margin : auto 150px; margin : auto 150px;
} }
.listContainer{
columns: 2 auto;
}

@ -3,7 +3,7 @@ const theme = {
colors: { colors: {
primary: '#0064E0', primary: '#0064E0',
secondary: '#0052B8', secondary: '#0052B8',
tertiary: '#7aa3f4', //* Pour les boutons de l'interface.
text: '#fff' text: '#fff'
//faire une gestion dark/light //faire une gestion dark/light

@ -42,7 +42,7 @@
"and": "and", "and": "and",
"or": "or", "or": "or",
"or_sport": "or", "or_sport": "and/or",
"age_indice_start": "The suspect is between", "age_indice_start": "The suspect is between",
@ -62,5 +62,82 @@
"nb_sports_indice_end": "sport", "nb_sports_indice_end": "sport",
"sport_start": "The suspect plays at least", "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", "and": "et",
"or": "ou", "or": "ou",
"or_sport": "ou du", "or_sport": "et/ou du",
"age_indice_start": "Le suspect a entre", "age_indice_start": "Le suspect a entre",
"age_indice_more_start": "Le suspect a ou a plus de", "age_indice_more_start": "Le suspect a ou a plus de",
@ -61,5 +61,83 @@
"nb_sports_indice_end": "sport(s)", "nb_sports_indice_end": "sport(s)",
"sport_start": "Le suspect pratique au moins du", "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"; import Stub from "./Stub";
class GameCreator{ 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 edgesCreator = new EdgesCreator()
const chooser = new IndiceChooser() const chooser = new IndiceChooser()
@ -26,9 +26,7 @@ class GameCreator{
edgesCreator.CreateAllEdges(networkPerson, person, choosenIndices) edgesCreator.CreateAllEdges(networkPerson, person, choosenIndices)
const graph = GraphCreator.CreateGraph(networkPerson) return [networkPerson, person, choosenIndices]
return [networkPerson, person, choosenIndices, graph]
} }
} }

@ -28,6 +28,15 @@ class AgeIndice extends Indice {
getMaximum(): number{ getMaximum(): number{
return this.maximum return this.maximum
} }
toJSON() {
return {
type: "AgeIndice",
id: this.id,
minimum: this.minimum,
maximum: this.maximum
};
}
} }
export default AgeIndice export default AgeIndice

@ -29,6 +29,14 @@ class ColorEdgesIndice extends EdgesIndice {
} }
return `${string} ${json.color_edges_end}` return `${string} ${json.color_edges_end}`
} }
toJSON() {
return {
type: "ColorEdgesIndice",
id: this.id,
neighborsColors: this.neighborsColors,
};
}
} }
export default ColorEdgesIndice export default ColorEdgesIndice

@ -28,6 +28,15 @@ class ColorIndice extends Indice {
getColors(): Color[]{ getColors(): Color[]{
return this.colors return this.colors
} }
toJSON() {
return {
type: "ColorIndice",
id: this.id,
colors: this.colors,
};
}
} }
export default ColorIndice export default ColorIndice

@ -17,7 +17,10 @@ abstract class Indice {
// Méthode abstraite pour être implémentée par les classes dérivées // Méthode abstraite pour être implémentée par les classes dérivées
abstract ToString(lang: string): string; abstract ToString(lang: string): string;
abstract toJSON(): any
} }
//todo to string ?
export default Indice export default Indice

@ -18,6 +18,15 @@ class NbEdgesIndice extends EdgesIndice {
let json = GetJsonFile(lang) let json = GetJsonFile(lang)
return `${json.nb_friends_indice_start} ${this.nbNeighbors} ${json.nb_friends_indice_end}`; 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 export default NbEdgesIndice

@ -18,6 +18,14 @@ class NbSportIndice extends Indice {
let json = GetJsonFile(lang) let json = GetJsonFile(lang)
return `${json.nb_sports_indice_start} ${this.nbSport} ${json.nb_sports_indice_end}`; 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 export default NbSportIndice

@ -29,6 +29,14 @@ class SportIndice extends Indice {
getSports(): Sport[]{ getSports(): Sport[]{
return this.sports return this.sports
} }
toJSON() {
return {
type: "SportIndice",
id: this.id,
sports: this.sports,
};
}
} }
export default SportIndice export default SportIndice

@ -78,6 +78,24 @@ class Person {
setFriends(friends: Person[]): void { setFriends(friends: Person[]): void {
this.friends = friends; 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 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{ class Stub{
static GenerateIndice(): Indice[]{ static GenerateIndice(): Indice[]{
let indice = new NbEdgesIndice(1, 3) let indice = new NbEdgesIndice(1, 2)
let indice1 = new NbEdgesIndice(2, 4) let indice1 = new NbEdgesIndice(2, 3)
let ageIndice = new AgeIndice(3, 0, 14) let ageIndice = new AgeIndice(3, 0, 14)
let ageIndice1 = new AgeIndice(4, 15, 19) let ageIndice1 = new AgeIndice(4, 15, 19)
let ageIndice2 = new AgeIndice(5, 20, 29) let ageIndice2 = new AgeIndice(5, 20, 29)
@ -41,11 +41,13 @@ class Stub{
} }
} }
//* Voisin couleur
for (let i: Color=0; i<5; i++){ for (let i: Color=0; i<5; i++){
indices.push(new ColorEdgesIndice(test, [i])) indices.push(new ColorEdgesIndice(test, [i]))
test++ test++
} }
//* Nombre de sport
for (let i=1; i<3; i++){ for (let i=1; i<3; i++){
indices.push(new NbSportIndice(test, i)) indices.push(new NbSportIndice(test, i))
test++ test++

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

@ -1905,6 +1905,11 @@
dependencies: dependencies:
"@sinonjs/commons" "^1.7.0" "@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": "@surma/rollup-plugin-off-main-thread@^2.2.3":
version "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" 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: dependencies:
"@types/node" "*" "@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": "@types/eslint-scope@^3.7.3":
version "3.7.7" version "3.7.7"
resolved "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz" 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" resolved "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.44.tgz"
integrity sha512-pdGBkAh4ggfXAkiwgmTdROJe3mwvLWJYm6JiaAwCtskAU0Weh+JQyyMTbhvxjxD2n8sr8PrxVwyDzmpnK4pUrQ== 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": "@types/hoist-non-react-statics@^3.3.1":
version "3.3.5" version "3.3.5"
resolved "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz" resolved "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz"
@ -2299,7 +2321,7 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/node@*": "@types/node@*", "@types/node@>=10.0.0":
version "20.8.10" version "20.8.10"
resolved "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz" resolved "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz"
integrity sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w== integrity sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==
@ -2343,6 +2365,32 @@
dependencies: dependencies:
"@types/react" "*" "@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": "@types/react-transition-group@^4.4.6":
version "4.4.8" version "4.4.8"
resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.8.tgz" 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" resolved "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.5.tgz"
integrity sha512-I3pkr8j/6tmQtKV/ZzHtuaqYSQvyjGRKH4go60Rr0IDLlFxuRT5V32uvB1mecM5G1EVAUyF/4r4QZ1GHgz+mxA== 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": "@types/warning@^3.0.0":
version "3.0.2" version "3.0.2"
resolved "https://registry.npmjs.org/@types/warning/-/warning-3.0.2.tgz" 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" resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 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: batch@0.6.1:
version "0.6.1" version "0.6.1"
resolved "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz" 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" resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz"
integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
<<<<<<< HEAD
cookie@0.4.1: cookie@0.4.1:
version "0.4.1" version "0.4.1"
resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz" resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz"
integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==
cookie@0.4.2: cookie@0.4.2:
=======
cookie@~0.4.1:
>>>>>>> a8c529123b11a032c4ba44a1587af10373815560
version "0.4.2" version "0.4.2"
resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz" resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz"
integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== 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" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz"
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
<<<<<<< HEAD
cors@^2.8.5: cors@^2.8.5:
=======
cors@^2.8.5, cors@~2.8.5:
>>>>>>> a8c529123b11a032c4ba44a1587af10373815560
version "2.8.5" version "2.8.5"
resolved "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz" resolved "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz"
integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
@ -4115,7 +4181,11 @@ debug@^3.2.7:
dependencies: dependencies:
ms "^2.1.1" 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.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" version "4.3.4"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@ -4464,12 +4534,46 @@ encodeurl@~1.0.2:
resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz"
integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
<<<<<<< HEAD
encoding@^0.1.0, encoding@^0.1.12: encoding@^0.1.0, encoding@^0.1.12:
version "0.1.13" version "0.1.13"
resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz" resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz"
integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==
dependencies: dependencies:
iconv-lite "^0.6.2" 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: enhanced-resolve@^5.15.0:
version "5.15.0" version "5.15.0"
@ -5004,6 +5108,7 @@ expect@^29.0.0:
jest-message-util "^29.7.0" jest-message-util "^29.7.0"
jest-util "^29.7.0" jest-util "^29.7.0"
<<<<<<< HEAD
express-session@^1.17.3: express-session@^1.17.3:
version "1.17.3" version "1.17.3"
resolved "https://registry.npmjs.org/express-session/-/express-session-1.17.3.tgz" 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" safe-buffer "5.2.1"
uid-safe "~2.1.5" uid-safe "~2.1.5"
=======
>>>>>>> a8c529123b11a032c4ba44a1587af10373815560
express@^4.17.3, express@^4.18.2: express@^4.17.3, express@^4.18.2:
version "4.18.2" version "4.18.2"
resolved "https://registry.npmjs.org/express/-/express-4.18.2.tgz" resolved "https://registry.npmjs.org/express/-/express-4.18.2.tgz"
@ -8636,6 +8743,11 @@ react-bootstrap@^2.9.1:
uncontrollable "^7.2.1" uncontrollable "^7.2.1"
warning "^4.0.3" 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: react-dev-utils@^12.0.1:
version "12.0.1" version "12.0.1"
resolved "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz" 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" resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz"
integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A== 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" version "6.18.0"
resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.18.0.tgz" resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.18.0.tgz"
integrity sha512-Ubrue4+Ercc/BoDkFQfc6og5zRQ4A8YxSO3Knsne+eRbZ+IepAsK249XBH/XaFuOYOYr3L3r13CXTLvYt5JDjw== integrity sha512-Ubrue4+Ercc/BoDkFQfc6og5zRQ4A8YxSO3Knsne+eRbZ+IepAsK249XBH/XaFuOYOYr3L3r13CXTLvYt5JDjw==
@ -8743,6 +8855,13 @@ react-router-dom@^6.18.0:
"@remix-run/router" "1.11.0" "@remix-run/router" "1.11.0"
react-router "6.18.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: react-router@6.18.0:
version "6.18.0" version "6.18.0"
resolved "https://registry.npmjs.org/react-router/-/react-router-6.18.0.tgz" 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" loose-envify "^1.4.0"
prop-types "^15.6.2" 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" version "18.2.0"
resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz" resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz"
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== 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" resolved "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz"
integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==
<<<<<<< HEAD
smart-buffer@^4.2.0: smart-buffer@^4.2.0:
version "4.2.0" version "4.2.0"
resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz" resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz"
integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== 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: sockjs@^0.3.24:
version "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" resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz"
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== 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" version "8.3.2"
resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== 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" resolved "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz"
integrity sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g== 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: xml-name-validator@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz" 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" resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz"
integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== 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: y18n@^5.0.5:
version "5.0.8" version "5.0.8"
resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" 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