diff --git a/package.json b/package.json index deede2b..329d587 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,9 @@ "scripts": { "build": "npx tsc", "start": "node dist/index.js", - "dev": "concurrently \"npx tsc --watch\" \"nodemon -q dist/index.js\"" + "dev": "concurrently \"npx tsc --watch\" \"nodemon -q dist/index.js\"", + "buildDocker": "docker build -t nuark/huacu_server:latest .", + "pushDocker": "docker push nuark/huacu_server:latest" }, "keywords": [], "author": "", diff --git a/src/index.ts b/src/index.ts index 341942c..d2260f4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,8 @@ import { v4 as uuidv4 } from "uuid"; import { Server, Socket } from "socket.io"; import { instrument } from "@socket.io/admin-ui"; +import { pallette, availableColors } from "./pallette"; + const app = express(); const server = http.createServer(app); @@ -53,20 +55,36 @@ class Game { private player1: Client; private player2: Client; + private guesses: Set; + private colors: Set; + public get Id() { return this.id; } - public get Player1() { + public get Guesser() { return this.player1; } - public get Player2() { + public get Suggester() { return this.player2; } + public get Guesses() { + return this.guesses; + } + public get Colors() { + return this.colors; + } constructor(id: String, player1: Client, player2: Client) { this.id = id; this.player1 = player1; this.player2 = player2; + this.guesses = new Set(); + this.colors = new Set(); + + while (this.colors.size < 6) { + const key = availableColors[Math.floor(Math.random() * availableColors.length)]; + this.colors.add(key); + } } public Opponent(player: Client): Client { @@ -76,6 +94,35 @@ class Game { return this.player1; } + public Guess(player: Client, guess: String) { + if (this.guesses.has(guess)) { + return true; + } + this.guesses.add(guess); + const opponent = this.Opponent(player); + const opponentSocket = Array.from(onlineClients.keys()).find((socket) => onlineClients.get(socket) === opponent); + if (opponentSocket) { + opponentSocket.emit("guess", guess); + } else { + console.log("opponent socket not found"); + return false; + } + return true; + } + + public GameWon() { + for (const color of this.colors) { + if (!this.guesses.has(color)) { + return false; + } + } + return true; + } + + public GameLost() { + return this.guesses.size >= 10; + } + public simplify() { return { id: this.id, @@ -115,6 +162,10 @@ app.get("/", (req, res) => { res.send("

Hello world

"); }); +app.get("/pallette", (req, res) => { + res.json(pallette); +}); + io.on("connection", (socket) => { console.log("someone connected"); @@ -269,14 +320,22 @@ io.on("connection", (socket) => { socket.emit("requestResponseResult", false, 404); return; } + const otherClient = onlineClients.get(otherClientSocket)!; if (response) { - const game = new Game(uuidv4(), client, onlineClients.get(otherClientSocket)!); + const isClientInGuessers = guessersRoom.availablePlayers.has(client.login); + guessersRoom.removePlayer(client); + suggestersRoom.removePlayer(client); + guessersRoom.removePlayer(otherClient); + suggestersRoom.removePlayer(otherClient); + io.emit("updateNeeded"); + + const game = new Game(uuidv4(), isClientInGuessers ? client : otherClient, isClientInGuessers ? otherClient : client); runningGames.set(game.Id, game); client.setInGame(true); - onlineClients.get(otherClientSocket)!.setInGame(true); - socket.emit("requestResponseResult", true, game.simplify()); - otherClientSocket.emit("requestResponseResult", true, game.simplify()); + otherClient.setInGame(true); + socket.emit("requestResponseResult", true, game.simplify(), Array.from(game.Guesses)); + otherClientSocket.emit("requestResponseResult", true, game.simplify(), Array.from(game.Colors)); } else { socket.emit("requestResponseResult", false, `You declined ${client.login} request`); otherClientSocket.emit("requestResponseResult", false, `${client.login} declined your request`); @@ -317,6 +376,87 @@ io.on("connection", (socket) => { }); }); + socket.on("guess", (gameId, guess) => { + const client = onlineClients.get(socket); + if (client === undefined) { + socket.emit("guessResponse", false, 403); + return; + } + + const game = runningGames.get(gameId); + if (game === undefined || !client.inGame) { + socket.emit("guessResponse", false, 400); + console.log("user " + client.login + " tried to guess in non existing game"); + + return; + } + + if (game.Guesser.login !== client.login) { + socket.emit("guessResponse", false, 400); + console.log("user " + client.login + " tried to guess in game he is not guessing in"); + + return; + } + + if (!game.Guess(client, guess)) { + socket.emit("guessResponse", false, 400); + console.log("user " + client.login + " tried to guess but something gone terribly wrong"); + + return; + } + + const opponentPlayer = game.Opponent(client); + const otherClientSocket = Array.from(onlineClients.keys()).find((key) => onlineClients.get(key)?.login === opponentPlayer.login)!; + if (game.GameWon()) { + console.log(`game ${gameId} won by ${client.login} and ${opponentPlayer.login}`); + + socket.emit("gameStatus", [true]); + otherClientSocket.emit("gameStatus", [true]); + + client.setInGame(false); + opponentPlayer.setInGame(false); + runningGames.delete(gameId); + return; + } + if (game.GameLost()) { + console.log(`game ${gameId} lost by ${client.login} and ${opponentPlayer.login}`); + + socket.emit("gameStatus", [false]); + otherClientSocket.emit("gameStatus", [false]); + + client.setInGame(false); + opponentPlayer.setInGame(false); + runningGames.delete(gameId); + } + }); + + socket.on("leaveGame", (gameId) => { + const client = onlineClients.get(socket); + if (client === undefined) { + socket.emit("guessResponse", false, 403); + return; + } + + const game = runningGames.get(gameId); + if (game === undefined || !client.inGame) { + socket.emit("guessResponse", false, 400); + console.log("user " + client.login + " tried to guess in non existing game"); + + return; + } + + socket.emit("leaveGameResponse", true, 200); + const opponentPlayer = game.Opponent(client); + const otherClientSocket = Array.from(onlineClients.keys()).find((key) => onlineClients.get(key)?.login === opponentPlayer.login); + if (otherClientSocket !== undefined) { + otherClientSocket.emit("leaveGameResponse", true, 410); + } + + client.setInGame(false); + opponentPlayer.setInGame(false); + runningGames.delete(game.Id); + }); + socket.on("disconnect", () => { const client = onlineClients.get(socket); if (client !== undefined) { @@ -324,14 +464,15 @@ io.on("connection", (socket) => { guessersRoom.removePlayer(client); suggestersRoom.removePlayer(client); if (client.inGame) { - const game = Array.from(runningGames.values()).find((game) => game.Player1 === client || game.Player2 === client); + const game = Array.from(runningGames.values()).find((game) => game.Guesser === client || game.Suggester === client); if (game !== undefined) { const opponentPlayer = game.Opponent(client); const otherClientSocket = Array.from(onlineClients.keys()).find((key) => onlineClients.get(key)?.login === opponentPlayer.login); if (otherClientSocket !== undefined) { - // TODO: For now chatResponse used - otherClientSocket.emit("chatResponse", false, 410); + otherClientSocket.emit("leaveGameResponse", true, 410); } + client.setInGame(false); + opponentPlayer.setInGame(false); runningGames.delete(game.Id); } diff --git a/src/pallette.ts b/src/pallette.ts new file mode 100644 index 0000000..b178070 --- /dev/null +++ b/src/pallette.ts @@ -0,0 +1,204 @@ +export const pallette = { + A0: [0, 0, 186], + A1: [0, 26, 186], + A2: [0, 51, 186], + A3: [0, 77, 186], + A4: [0, 102, 186], + A5: [0, 128, 186], + A6: [0, 153, 186], + A7: [0, 179, 186], + A8: [0, 204, 186], + A9: [0, 230, 186], + B0: [13, 0, 186], + B1: [13, 26, 186], + B2: [13, 51, 186], + B3: [13, 77, 186], + B4: [13, 102, 186], + B5: [13, 128, 186], + B6: [13, 153, 186], + B7: [13, 179, 186], + B8: [13, 204, 186], + B9: [13, 230, 186], + C0: [26, 0, 186], + C1: [26, 26, 186], + C2: [26, 51, 186], + C3: [26, 77, 186], + C4: [26, 102, 186], + C5: [26, 128, 186], + C6: [26, 153, 186], + C7: [26, 179, 186], + C8: [26, 204, 186], + C9: [26, 230, 186], + D0: [38, 0, 186], + D1: [38, 26, 186], + D2: [38, 51, 186], + D3: [38, 77, 186], + D4: [38, 102, 186], + D5: [38, 128, 186], + D6: [38, 153, 186], + D7: [38, 179, 186], + D8: [38, 204, 186], + D9: [38, 230, 186], + E0: [51, 0, 186], + E1: [51, 26, 186], + E2: [51, 51, 186], + E3: [51, 77, 186], + E4: [51, 102, 186], + E5: [51, 128, 186], + E6: [51, 153, 186], + E7: [51, 179, 186], + E8: [51, 204, 186], + E9: [51, 230, 186], + F0: [64, 0, 186], + F1: [64, 26, 186], + F2: [64, 51, 186], + F3: [64, 77, 186], + F4: [64, 102, 186], + F5: [64, 128, 186], + F6: [64, 153, 186], + F7: [64, 179, 186], + F8: [64, 204, 186], + F9: [64, 230, 186], + G0: [77, 0, 186], + G1: [77, 26, 186], + G2: [77, 51, 186], + G3: [77, 77, 186], + G4: [77, 102, 186], + G5: [77, 128, 186], + G6: [77, 153, 186], + G7: [77, 179, 186], + G8: [77, 204, 186], + G9: [77, 230, 186], + H0: [89, 0, 186], + H1: [89, 26, 186], + H2: [89, 51, 186], + H3: [89, 77, 186], + H4: [89, 102, 186], + H5: [89, 128, 186], + H6: [89, 153, 186], + H7: [89, 179, 186], + H8: [89, 204, 186], + H9: [89, 230, 186], + I0: [102, 0, 186], + I1: [102, 26, 186], + I2: [102, 51, 186], + I3: [102, 77, 186], + I4: [102, 102, 186], + I5: [102, 128, 186], + I6: [102, 153, 186], + I7: [102, 179, 186], + I8: [102, 204, 186], + I9: [102, 230, 186], + J0: [115, 0, 186], + J1: [115, 26, 186], + J2: [115, 51, 186], + J3: [115, 77, 186], + J4: [115, 102, 186], + J5: [115, 128, 186], + J6: [115, 153, 186], + J7: [115, 179, 186], + J8: [115, 204, 186], + J9: [115, 230, 186], + K0: [128, 0, 186], + K1: [128, 26, 186], + K2: [128, 51, 186], + K3: [128, 77, 186], + K4: [128, 102, 186], + K5: [128, 128, 186], + K6: [128, 153, 186], + K7: [128, 179, 186], + K8: [128, 204, 186], + K9: [128, 230, 186], + L0: [140, 0, 186], + L1: [140, 26, 186], + L2: [140, 51, 186], + L3: [140, 77, 186], + L4: [140, 102, 186], + L5: [140, 128, 186], + L6: [140, 153, 186], + L7: [140, 179, 186], + L8: [140, 204, 186], + L9: [140, 230, 186], + M0: [153, 0, 186], + M1: [153, 26, 186], + M2: [153, 51, 186], + M3: [153, 77, 186], + M4: [153, 102, 186], + M5: [153, 128, 186], + M6: [153, 153, 186], + M7: [153, 179, 186], + M8: [153, 204, 186], + M9: [153, 230, 186], + N0: [166, 0, 186], + N1: [166, 26, 186], + N2: [166, 51, 186], + N3: [166, 77, 186], + N4: [166, 102, 186], + N5: [166, 128, 186], + N6: [166, 153, 186], + N7: [166, 179, 186], + N8: [166, 204, 186], + N9: [166, 230, 186], + O0: [179, 0, 186], + O1: [179, 26, 186], + O2: [179, 51, 186], + O3: [179, 77, 186], + O4: [179, 102, 186], + O5: [179, 128, 186], + O6: [179, 153, 186], + O7: [179, 179, 186], + O8: [179, 204, 186], + O9: [179, 230, 186], + P0: [191, 0, 186], + P1: [191, 26, 186], + P2: [191, 51, 186], + P3: [191, 77, 186], + P4: [191, 102, 186], + P5: [191, 128, 186], + P6: [191, 153, 186], + P7: [191, 179, 186], + P8: [191, 204, 186], + P9: [191, 230, 186], + Q0: [204, 0, 186], + Q1: [204, 26, 186], + Q2: [204, 51, 186], + Q3: [204, 77, 186], + Q4: [204, 102, 186], + Q5: [204, 128, 186], + Q6: [204, 153, 186], + Q7: [204, 179, 186], + Q8: [204, 204, 186], + Q9: [204, 230, 186], + R0: [217, 0, 186], + R1: [217, 26, 186], + R2: [217, 51, 186], + R3: [217, 77, 186], + R4: [217, 102, 186], + R5: [217, 128, 186], + R6: [217, 153, 186], + R7: [217, 179, 186], + R8: [217, 204, 186], + R9: [217, 230, 186], + S0: [230, 0, 186], + S1: [230, 26, 186], + S2: [230, 51, 186], + S3: [230, 77, 186], + S4: [230, 102, 186], + S5: [230, 128, 186], + S6: [230, 153, 186], + S7: [230, 179, 186], + S8: [230, 204, 186], + S9: [230, 230, 186], + T0: [242, 0, 186], + T1: [242, 26, 186], + T2: [242, 51, 186], + T3: [242, 77, 186], + T4: [242, 102, 186], + T5: [242, 128, 186], + T6: [242, 153, 186], + T7: [242, 179, 186], + T8: [242, 204, 186], + T9: [242, 230, 186], +}; + +export const availableColors = Object.keys(pallette);