From 017921b90c282b70afee432cf526bf0b19539062 Mon Sep 17 00:00:00 2001 From: Andrius Iljinych Date: Tue, 14 Mar 2023 19:00:05 +0200 Subject: [PATCH 1/4] PLAN-156 made game state calculation in BE --- services/api/src/domain/game.ts | 6 ++ services/api/src/domain/messages.ts | 2 + .../game-room.service.test.ts.snap | 2 + services/api/src/game/game-room.service.ts | 11 ++- services/api/src/game/game.service.ts | 32 ++++++-- .../__tests__/player.service.test.ts | 2 +- services/api/src/messaging/players.service.ts | 81 +++++++++++++++++++ 7 files changed, 129 insertions(+), 7 deletions(-) diff --git a/services/api/src/domain/game.ts b/services/api/src/domain/game.ts index da650be9..19708220 100644 --- a/services/api/src/domain/game.ts +++ b/services/api/src/domain/game.ts @@ -12,3 +12,9 @@ export enum TurnType { MoveSkipped = 'MoveSkipped', FigurePlaced = 'FigurePlaced', } + +export enum GameState { + GAME_NOT_STARTED = 'GAME_NOT_STARTED', + GAME_IN_PROGRESS = 'GAME_IN_PROGRESS', + GAME_FINISHED = 'GAME_FINISHED', +} diff --git a/services/api/src/domain/messages.ts b/services/api/src/domain/messages.ts index 63499d6d..06d146d8 100644 --- a/services/api/src/domain/messages.ts +++ b/services/api/src/domain/messages.ts @@ -19,6 +19,7 @@ export enum MessageType { ErrorMessage = 'ErrorMessage', ActionMade = 'ActionMade', AvatarUpdate = 'AvatarUpdate', + UpdateGameState = 'UpdateGameState', } export type SendMessagePayloads = { @@ -33,6 +34,7 @@ export type SendMessagePayloads = { [MessageType.PlayerSuccessfullyJoined]: string; [MessageType.ErrorMessage]: string; [MessageType.Pong]: void; + [MessageType.UpdateGameState]: string; }; export interface SendMessage { diff --git a/services/api/src/game/__tests__/__snapshots__/game-room.service.test.ts.snap b/services/api/src/game/__tests__/__snapshots__/game-room.service.test.ts.snap index fce80ab8..bc1ada1c 100644 --- a/services/api/src/game/__tests__/__snapshots__/game-room.service.test.ts.snap +++ b/services/api/src/game/__tests__/__snapshots__/game-room.service.test.ts.snap @@ -2,6 +2,7 @@ exports[`gameRoomService should create new room 1`] = ` Object { + "gameState": "GAME_NOT_STARTED", "players": Map {}, "roomId": "some-short-v4-uuid-0", "server": WebSocketServer { @@ -34,6 +35,7 @@ Object { exports[`gameRoomService should get existing room 1`] = ` Object { + "gameState": "GAME_NOT_STARTED", "players": Map {}, "roomId": "abcd-1234", "server": WebSocketServer { diff --git a/services/api/src/game/game-room.service.ts b/services/api/src/game/game-room.service.ts index 3e70531c..d493080f 100644 --- a/services/api/src/game/game-room.service.ts +++ b/services/api/src/game/game-room.service.ts @@ -2,13 +2,14 @@ import WebSocket, { WebSocketServer } from 'ws'; import { v4 as uuidv4 } from 'uuid'; import logger from '../logger'; import { Player } from '../domain'; -import { Turn } from '../domain/game'; +import { Turn, GameState } from '../domain/game'; interface GameRoom { roomId: string; server: WebSocketServer; players: Map; turns: Turn[]; + gameState: GameState; } export const rooms = new Map(); @@ -31,12 +32,20 @@ export const getOrCreateRoom = (id?: string): GameRoom => { server, players: new Map(), turns: [], + gameState: GameState.GAME_NOT_STARTED, }; rooms.set(roomId, newRoom); return newRoom; }; +export const setGameState = (roomId: string, gameState: GameState): void => { + getOrCreateRoom(roomId).gameState = gameState; +}; + +export const getGameState = (roomId: string): GameState => + getOrCreateRoom(roomId).gameState; + export const getClients = (id: string): Set => rooms.get(id)?.server.clients; diff --git a/services/api/src/game/game.service.ts b/services/api/src/game/game.service.ts index 2e142204..e1ea674f 100644 --- a/services/api/src/game/game.service.ts +++ b/services/api/src/game/game.service.ts @@ -1,9 +1,22 @@ import { PlaceFigureMessage } from '../domain/messages'; +import { GameState } from '../domain/game'; import { calculateScore } from '../helpers/calculate-score'; import * as gameRoomService from './game-room.service'; import logger from '../logger'; import { Turn, TurnType } from '../domain/game'; -import { PlayerStatus, PlayerRole } from '../domain/player'; +import { PlayerStatus, PlayerRole, Player } from '../domain/player'; + +export const getVoters = (roomId: string): Player[] => { + const players = gameRoomService.getPlayers(roomId); + return Array.from(players.values()).filter( + (p) => p.role === PlayerRole.Voter, + ); +}; + +export const getVoterWhoMadeActionCount = (roomId: string): number => + getVoters(roomId).filter( + (voter) => voter.status !== PlayerStatus.ActionNotTaken, + ).length; export const playerHasMove = (roomId: string, playerId: string): boolean => Boolean(findMoveByPlayerId(roomId, playerId)); @@ -22,10 +35,19 @@ export const playerHasSkipped = (roomId: string, playerId: string): boolean => { }; export const areAllPlayersDone = (roomId: string): boolean => { - const players = gameRoomService.getPlayers(roomId); - return Array.from(players.values()) - .filter((p) => p.role === PlayerRole.Voter) - .every((player) => player.status !== PlayerStatus.ActionNotTaken); + const voters = getVoters(roomId); + if (voters.length < 2) { + return false; + } + + const arePlayersDone = voters.every( + (player) => player.status !== PlayerStatus.ActionNotTaken, + ); + if (arePlayersDone) { + gameRoomService.setGameState(roomId, GameState.GAME_FINISHED); + } + + return arePlayersDone; }; export const figureMoved = ( diff --git a/services/api/src/messaging/__tests__/player.service.test.ts b/services/api/src/messaging/__tests__/player.service.test.ts index 28bb9cd9..c6e7e8e6 100644 --- a/services/api/src/messaging/__tests__/player.service.test.ts +++ b/services/api/src/messaging/__tests__/player.service.test.ts @@ -67,7 +67,7 @@ describe('player.service', () => { it('should create new id and assign voter role to player on connect', () => { const message: ReceivedMessage = { type: MessageType.PlayerConnected, - payload: { playerName: 'player1', id: '', role: null, avatar: null }, + payload: { playerName: 'player1', id: '', role: null, avatar: undefined }, }; const messageSpy = jest.spyOn(playerService, 'subscribe'); playerService.newMessageReceived(ws, message); diff --git a/services/api/src/messaging/players.service.ts b/services/api/src/messaging/players.service.ts index f7c7622d..5c46f16f 100644 --- a/services/api/src/messaging/players.service.ts +++ b/services/api/src/messaging/players.service.ts @@ -1,6 +1,7 @@ import WebSocket from 'ws'; import { v4 as uuidv4 } from 'uuid'; import { Player, PlayerStatus, PlayerRole } from '../domain'; +import { GameState } from '../domain/game'; import { getPlayerAvatarColor } from '../helpers/player-avatar-color'; import logger from '../logger'; import { @@ -36,6 +37,33 @@ export const findPlayerById = ( return player; }; +export const findPlayerByConnection = (ws: GameWebSocket): Player => { + const players = gameRoomService.getPlayers(ws.roomId); + const player = players.get(ws); + if (!player) { + throw new Error('player with this ws connection not found'); + } + return player; +}; + +export const checkIfLastToVote = ( + roomId: string, + playerId: string, +): boolean => { + const player = findPlayerById(roomId, playerId); + const voters = gameService.getVoters(roomId); + const votersWhoMadeMoveCount = gameService.getVoterWhoMadeActionCount(roomId); + const playerCount = gameRoomService.getPlayers(roomId).size; + + const isOneVoteMissing = playerCount === votersWhoMadeMoveCount + 1; + const hasPlayerMoved = player[1].status !== PlayerStatus.ActionNotTaken; + + if (isOneVoteMissing && voters.length > 1 && !hasPlayerMoved) { + return true; + } + return false; +}; + const playerExists = (roomId: string, playerId: string): boolean => { try { findPlayerById(roomId, playerId); @@ -55,6 +83,10 @@ const publishFinalBoard = (ws: GameWebSocket): void => { }; export const figureMoved: Handler = (ws, payload: PlaceFigureMessage): void => { + if (gameRoomService.getGameState(ws.roomId) === GameState.GAME_FINISHED) { + return; + } + const players = getPlayers(ws.roomId); logger.info(`Player ${players.get(ws)?.name} moved a figure.`); players.set(ws, { @@ -68,6 +100,7 @@ export const figureMoved: Handler = (ws, payload: PlaceFigureMessage): void => { publishAllPlayers(ws.roomId); if (gameService.areAllPlayersDone(ws.roomId)) { publishFinalBoard(ws); + // TODO: send a message that the game is finished } }; @@ -80,6 +113,11 @@ const setDefaultStatusForPlayers = (ws: GameWebSocket): void => { export const resetGame = (ws: GameWebSocket): void => { gameService.clearBoard(ws.roomId); + if (gameService.getVoters.length < 2) { + gameRoomService.setGameState(ws.roomId, GameState.GAME_NOT_STARTED); + } else { + gameRoomService.setGameState(ws.roomId, GameState.GAME_IN_PROGRESS); + } setDefaultStatusForPlayers(ws); publishBoard(ws.roomId); publishAllPlayers(ws.roomId); @@ -90,6 +128,9 @@ export const moveSkipped: Handler = ( { playerId }: MoveSkippedMessage, ): void => { const players = getPlayers(ws.roomId); + if (gameRoomService.getGameState(ws.roomId) === GameState.GAME_FINISHED) { + return; + } try { const [playerConnection, player] = findPlayerById(ws.roomId, playerId); @@ -120,6 +161,7 @@ export const moveSkipped: Handler = ( }); if (gameService.areAllPlayersDone(ws.roomId)) { publishFinalBoard(ws); + // TODO: send a message that the game is done } } catch (err) { logger.error(err?.message); @@ -146,6 +188,8 @@ const createNewPlayer = (params: { newPlayer.status = PlayerStatus.FigurePlaced; } else if (gameService.playerHasSkipped(params.roomId, params.playerId)) { newPlayer.status = PlayerStatus.MoveSkipped; + } else if (gameRoomService.getGameState(params.roomId) === GameState.GAME_FINISHED) { + newPlayer.status = PlayerStatus.MoveSkipped; } return newPlayer; @@ -186,7 +230,14 @@ export const playerConnected: Handler = ( sendMessage(ws, MessageType.SetMyTurn, myTurn); } + if (gameRoomService.getGameState(ws.roomId) === GameState.GAME_NOT_STARTED) { + if (gameService.getVoters(ws.roomId).length > 1) { + gameRoomService.setGameState(ws.roomId, GameState.GAME_IN_PROGRESS); + } + } + publishAllPlayers(ws.roomId); + // TODO: send a gameState to FE if (gameService.areAllPlayersDone(ws.roomId)) { publishFinalBoard(ws); @@ -232,6 +283,36 @@ export const subscribe = (ws: GameWebSocket, newPlayer: Player): void => { export const unsubscribe = (ws: GameWebSocket): void => { const players = getPlayers(ws.roomId); + const playerId = findPlayerByConnection(ws).id; + + if ( + gameService.getVoters(ws.roomId).length === 2 + && gameRoomService.getGameState(ws.roomId) !== GameState.GAME_FINISHED + ) { + gameRoomService.setGameState(ws.roomId, GameState.GAME_NOT_STARTED); + } else if (checkIfLastToVote(ws.roomId, playerId)) { + players.delete(ws); + setTimeout(() => { + try { + const player = findPlayerById(ws.roomId, playerId); + if (player) { + return; + } + } catch (err) { + logger.error(err?.message); + logger.info('Publishing: player disconnected the game.'); + gameRoomService.setGameState(ws.roomId, GameState.GAME_FINISHED); + const allPlayers = Array.from(players.values()); + publish(ws.roomId, { + type: MessageType.PlayerDisconnected, + payload: allPlayers, + }); + publishFinalBoard(ws); + } + }, 2000); + return; + } + logger.info(`Unsubscribing player ${players.get(ws)?.name}`); players.delete(ws); From 5189a81fdf2f75d07f5fb4939025ff9f14caca33 Mon Sep 17 00:00:00 2001 From: Andrius Iljinych Date: Tue, 14 Mar 2023 23:38:29 +0200 Subject: [PATCH 2/4] PLAN-156 send gameState to FE --- services/api/src/domain/messages.ts | 4 ++-- services/api/src/messaging/players.service.ts | 20 +++++++++++++++---- .../src/components/gameFooter/GameFooter.jsx | 7 +++++-- services/app/src/constants/messages.js | 1 + .../app/src/contexts/ChessBoardContext.jsx | 19 +++++------------- 5 files changed, 29 insertions(+), 22 deletions(-) diff --git a/services/api/src/domain/messages.ts b/services/api/src/domain/messages.ts index 06d146d8..ce60c48a 100644 --- a/services/api/src/domain/messages.ts +++ b/services/api/src/domain/messages.ts @@ -1,6 +1,6 @@ import { GameWebSocket } from './GameRoom'; import { Player, PlayerRole } from './player'; -import { Turn } from './game'; +import { Turn, GameState } from './game'; export enum MessageType { PlayerSuccessfullyJoined = 'PlayerSuccessfullyJoined', @@ -34,7 +34,7 @@ export type SendMessagePayloads = { [MessageType.PlayerSuccessfullyJoined]: string; [MessageType.ErrorMessage]: string; [MessageType.Pong]: void; - [MessageType.UpdateGameState]: string; + [MessageType.UpdateGameState]: GameState; }; export interface SendMessage { diff --git a/services/api/src/messaging/players.service.ts b/services/api/src/messaging/players.service.ts index 5c46f16f..1f769802 100644 --- a/services/api/src/messaging/players.service.ts +++ b/services/api/src/messaging/players.service.ts @@ -82,6 +82,13 @@ const publishFinalBoard = (ws: GameWebSocket): void => { }); }; +const publishGameState = (ws: GameWebSocket): void => { + publish(ws.roomId, { + type: MessageType.UpdateGameState, + payload: gameRoomService.getGameState(ws.roomId), + }); +}; + export const figureMoved: Handler = (ws, payload: PlaceFigureMessage): void => { if (gameRoomService.getGameState(ws.roomId) === GameState.GAME_FINISHED) { return; @@ -99,8 +106,8 @@ export const figureMoved: Handler = (ws, payload: PlaceFigureMessage): void => { publish(ws.roomId, { type: MessageType.ActionMade, payload: newBoardState }); publishAllPlayers(ws.roomId); if (gameService.areAllPlayersDone(ws.roomId)) { + publishGameState(ws); publishFinalBoard(ws); - // TODO: send a message that the game is finished } }; @@ -113,11 +120,12 @@ const setDefaultStatusForPlayers = (ws: GameWebSocket): void => { export const resetGame = (ws: GameWebSocket): void => { gameService.clearBoard(ws.roomId); - if (gameService.getVoters.length < 2) { + if (gameService.getVoters(ws.roomId).length < 2) { gameRoomService.setGameState(ws.roomId, GameState.GAME_NOT_STARTED); } else { gameRoomService.setGameState(ws.roomId, GameState.GAME_IN_PROGRESS); } + publishGameState(ws); setDefaultStatusForPlayers(ws); publishBoard(ws.roomId); publishAllPlayers(ws.roomId); @@ -160,8 +168,8 @@ export const moveSkipped: Handler = ( payload: gameRoomService.getTurns(ws.roomId), }); if (gameService.areAllPlayersDone(ws.roomId)) { + publishGameState(ws); publishFinalBoard(ws); - // TODO: send a message that the game is done } } catch (err) { logger.error(err?.message); @@ -230,14 +238,16 @@ export const playerConnected: Handler = ( sendMessage(ws, MessageType.SetMyTurn, myTurn); } + sendMessage(ws, MessageType.UpdateGameState, gameRoomService.getGameState(ws.roomId)); + if (gameRoomService.getGameState(ws.roomId) === GameState.GAME_NOT_STARTED) { if (gameService.getVoters(ws.roomId).length > 1) { gameRoomService.setGameState(ws.roomId, GameState.GAME_IN_PROGRESS); + publishGameState(ws); } } publishAllPlayers(ws.roomId); - // TODO: send a gameState to FE if (gameService.areAllPlayersDone(ws.roomId)) { publishFinalBoard(ws); @@ -290,6 +300,7 @@ export const unsubscribe = (ws: GameWebSocket): void => { && gameRoomService.getGameState(ws.roomId) !== GameState.GAME_FINISHED ) { gameRoomService.setGameState(ws.roomId, GameState.GAME_NOT_STARTED); + publishGameState(ws); } else if (checkIfLastToVote(ws.roomId, playerId)) { players.delete(ws); setTimeout(() => { @@ -307,6 +318,7 @@ export const unsubscribe = (ws: GameWebSocket): void => { type: MessageType.PlayerDisconnected, payload: allPlayers, }); + publishGameState(ws); publishFinalBoard(ws); } }, 2000); diff --git a/services/app/src/components/gameFooter/GameFooter.jsx b/services/app/src/components/gameFooter/GameFooter.jsx index 5d2eebf7..769bf27d 100644 --- a/services/app/src/components/gameFooter/GameFooter.jsx +++ b/services/app/src/components/gameFooter/GameFooter.jsx @@ -3,14 +3,17 @@ import PropTypes from 'prop-types'; import { useChessBoardContext } from '../../contexts/ChessBoardContext'; import GameFooterActive from './GameFooterActive'; import GameFooterInactive from './GameFooterInactive'; +import { GameState } from '../../constants/gameConstants'; const GameFooter = ({ skipCurrentPlayerMove }) => { - const { voters } = useChessBoardContext() + const { gameState } = useChessBoardContext(); return ( ) diff --git a/services/app/src/constants/messages.js b/services/app/src/constants/messages.js index ca88ce4a..4f9ed977 100644 --- a/services/app/src/constants/messages.js +++ b/services/app/src/constants/messages.js @@ -8,4 +8,5 @@ export const MessageType = { ActionMade: 'ActionMade', SetMyTurn: 'SetMyTurn', NewBoardState: 'NewBoardState', + UpdateGameState: 'UpdateGameState', } \ No newline at end of file diff --git a/services/app/src/contexts/ChessBoardContext.jsx b/services/app/src/contexts/ChessBoardContext.jsx index f862db9a..a5eb1db3 100644 --- a/services/app/src/contexts/ChessBoardContext.jsx +++ b/services/app/src/contexts/ChessBoardContext.jsx @@ -28,6 +28,7 @@ const ChessBoardContextProvider = ({ children }) => { const [players, setPlayers] = useState([]); const [turns, setTurns] = useState([]); const [errorMessage, setErrorMessage] = useState(''); + const [gameState, setGameState] = useState(GameState.GAME_NOT_STARTED); const currentPlayer = useMemo( () => players.find((user) => user.id === currentPlayerId), @@ -74,20 +75,6 @@ const ChessBoardContextProvider = ({ children }) => { PlayerStatuses.MoveSkipped ].includes(currentPlayer?.status), [currentPlayer]); - const gameState = useMemo(() => { - const votersWhoDidNotMove = voters - .filter(p => p.status === PlayerStatuses.ActionNotTaken); - - if (voters.length > 1) { - if (votersWhoDidNotMove.length === 0) { - return GameState.GAME_FINISHED; - } - return GameState.GAME_IN_PROGRESS; - } - - return GameState.GAME_NOT_STARTED; - }, [players]); - const votersListWithScores = useMemo(() => { if (gameState === GameState.GAME_FINISHED && turns) { const voterList = voters.map(voter => { @@ -155,6 +142,10 @@ const ChessBoardContextProvider = ({ children }) => { chessBoard.clearChessBoard(); } + addWsEventListener(MessageType.UpdateGameState, (payload) => { + setGameState(payload); + }); + addWsEventListener(MessageType.PlayerSuccessfullyJoined, (payload) => { userContext.setUserId(payload) setCurrentPlayerId(payload); From 6ac0da13727dc9750c74bd625e3115c5c5e4b897 Mon Sep 17 00:00:00 2001 From: Andrius Iljinych Date: Wed, 15 Mar 2023 10:13:47 +0200 Subject: [PATCH 3/4] PLAN-156 added try catch statement --- services/api/src/messaging/players.service.ts | 58 ++++++++++--------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/services/api/src/messaging/players.service.ts b/services/api/src/messaging/players.service.ts index 1f769802..27ceb5a8 100644 --- a/services/api/src/messaging/players.service.ts +++ b/services/api/src/messaging/players.service.ts @@ -293,35 +293,39 @@ export const subscribe = (ws: GameWebSocket, newPlayer: Player): void => { export const unsubscribe = (ws: GameWebSocket): void => { const players = getPlayers(ws.roomId); - const playerId = findPlayerByConnection(ws).id; + try { + const playerId = findPlayerByConnection(ws).id; - if ( - gameService.getVoters(ws.roomId).length === 2 - && gameRoomService.getGameState(ws.roomId) !== GameState.GAME_FINISHED - ) { - gameRoomService.setGameState(ws.roomId, GameState.GAME_NOT_STARTED); - publishGameState(ws); - } else if (checkIfLastToVote(ws.roomId, playerId)) { - players.delete(ws); - setTimeout(() => { - try { - const player = findPlayerById(ws.roomId, playerId); - if (player) { - return; + if ( + gameService.getVoters(ws.roomId).length === 2 + && gameRoomService.getGameState(ws.roomId) !== GameState.GAME_FINISHED + ) { + gameRoomService.setGameState(ws.roomId, GameState.GAME_NOT_STARTED); + publishGameState(ws); + } else if (checkIfLastToVote(ws.roomId, playerId)) { + players.delete(ws); + setTimeout(() => { + try { + const player = findPlayerById(ws.roomId, playerId); + if (player) { + return; + } + } catch (err) { + logger.error(err?.message); + logger.info('Publishing: player disconnected the game.'); + gameRoomService.setGameState(ws.roomId, GameState.GAME_FINISHED); + const allPlayers = Array.from(players.values()); + publish(ws.roomId, { + type: MessageType.PlayerDisconnected, + payload: allPlayers, + }); + publishGameState(ws); + publishFinalBoard(ws); } - } catch (err) { - logger.error(err?.message); - logger.info('Publishing: player disconnected the game.'); - gameRoomService.setGameState(ws.roomId, GameState.GAME_FINISHED); - const allPlayers = Array.from(players.values()); - publish(ws.roomId, { - type: MessageType.PlayerDisconnected, - payload: allPlayers, - }); - publishGameState(ws); - publishFinalBoard(ws); - } - }, 2000); + }, 2000); + return; + } + } catch { return; } From bdf21146d7ca499603640eb528cf24fe0e36cf4c Mon Sep 17 00:00:00 2001 From: Andrius Iljinych Date: Wed, 15 Mar 2023 11:54:59 +0200 Subject: [PATCH 4/4] PLAN-156 game state calculation made better --- services/api/src/messaging/players.service.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/services/api/src/messaging/players.service.ts b/services/api/src/messaging/players.service.ts index 27ceb5a8..696dcd34 100644 --- a/services/api/src/messaging/players.service.ts +++ b/services/api/src/messaging/players.service.ts @@ -90,7 +90,7 @@ const publishGameState = (ws: GameWebSocket): void => { }; export const figureMoved: Handler = (ws, payload: PlaceFigureMessage): void => { - if (gameRoomService.getGameState(ws.roomId) === GameState.GAME_FINISHED) { + if (gameRoomService.getGameState(ws.roomId) !== GameState.GAME_IN_PROGRESS) { return; } @@ -136,7 +136,7 @@ export const moveSkipped: Handler = ( { playerId }: MoveSkippedMessage, ): void => { const players = getPlayers(ws.roomId); - if (gameRoomService.getGameState(ws.roomId) === GameState.GAME_FINISHED) { + if (gameRoomService.getGameState(ws.roomId) !== GameState.GAME_IN_PROGRESS) { return; } @@ -196,7 +196,9 @@ const createNewPlayer = (params: { newPlayer.status = PlayerStatus.FigurePlaced; } else if (gameService.playerHasSkipped(params.roomId, params.playerId)) { newPlayer.status = PlayerStatus.MoveSkipped; - } else if (gameRoomService.getGameState(params.roomId) === GameState.GAME_FINISHED) { + } else if ( + gameRoomService.getGameState(params.roomId) === GameState.GAME_FINISHED + ) { newPlayer.status = PlayerStatus.MoveSkipped; } @@ -238,7 +240,11 @@ export const playerConnected: Handler = ( sendMessage(ws, MessageType.SetMyTurn, myTurn); } - sendMessage(ws, MessageType.UpdateGameState, gameRoomService.getGameState(ws.roomId)); + sendMessage( + ws, + MessageType.UpdateGameState, + gameRoomService.getGameState(ws.roomId), + ); if (gameRoomService.getGameState(ws.roomId) === GameState.GAME_NOT_STARTED) { if (gameService.getVoters(ws.roomId).length > 1) { @@ -297,8 +303,8 @@ export const unsubscribe = (ws: GameWebSocket): void => { const playerId = findPlayerByConnection(ws).id; if ( - gameService.getVoters(ws.roomId).length === 2 - && gameRoomService.getGameState(ws.roomId) !== GameState.GAME_FINISHED + gameService.getVoters(ws.roomId).length === 2 && + gameRoomService.getGameState(ws.roomId) !== GameState.GAME_FINISHED ) { gameRoomService.setGameState(ws.roomId, GameState.GAME_NOT_STARTED); publishGameState(ws);