From d0b12137b53ac100d39a55480ee8ae9003ea0629 Mon Sep 17 00:00:00 2001 From: Wenszel Date: Sat, 11 Nov 2023 18:48:35 +0100 Subject: [PATCH] added moving pawn when player miss a turn --- backend/handlers/gameHandler.js | 131 ++++++++----------- backend/handlers/playerHandler.js | 8 +- backend/handlers/roomHandler.js | 2 +- backend/schemas/pawn.js | 24 ++++ backend/schemas/player.js | 12 ++ backend/schemas/room.js | 85 +++++++++--- src/components/game-board-components/Map.jsx | 5 +- 7 files changed, 162 insertions(+), 105 deletions(-) create mode 100644 backend/schemas/pawn.js create mode 100644 backend/schemas/player.js diff --git a/backend/handlers/gameHandler.js b/backend/handlers/gameHandler.js index 03d624f..b4f244c 100644 --- a/backend/handlers/gameHandler.js +++ b/backend/handlers/gameHandler.js @@ -1,109 +1,88 @@ -const RoomModel = require('../schemas/room'); +const Room = require('../schemas/room'); const { getPawnPositionAfterMove } = require('../utils/functions'); module.exports = (io, socket) => { const req = socket.request; - const getRoom = async () => { - return await RoomModel.findOne({ _id: req.session.roomId }).exec(); + const handleMovePawn = async pawnId => { + const room = await getRoom(); + const pawn = room.getPawn(pawnId); + if (isMoveValid(pawn, room)) { + const newPositionOfMovedPawn = getPawnPositionAfterMove(room.rolledNumber, pawn); + room.changePositionOfPawn(pawn, newPositionOfMovedPawn); + room.beatPawns(newPositionOfMovedPawn, req.session.color); + handleChangeOfPlayer(room); + } }; - const updateRoom = async room => { - return await RoomModel.findOneAndUpdate({ _id: req.session.roomId }, room).exec(); + const handleRollDice = async () => { + const rolledNumber = rollDice(); + const room = await updateRoom({ rolledNumber: rolledNumber }); + if (!canPlayerMove(room, rolledNumber)) { + handleChangeOfPlayer(room); + } }; - const sendToPlayersRolledNumber = rolledNumber => { - io.to(req.session.roomId.toString()).emit('game:roll', rolledNumber); - }; - - const sendToPlayersData = room => { - io.to(req.session.roomId.toString()).emit('room:data', JSON.stringify(room)); - }; - - const rollDice = async () => { + const rollDice = () => { const rolledNumber = Math.ceil(Math.random() * 6); sendToPlayersRolledNumber(rolledNumber); - let room = await updateRoom({ rolledNumber: rolledNumber }); - if (!canPlayerMove(room, rolledNumber)) { - room = changeMovingPlayer(room); - await updateRoom(room); - sendToPlayersData(room); - } + return rolledNumber; }; const canPlayerMove = (room, rolledNumber) => { - let isMovePossible = false; - const playerPawns = room.pawns.filter(pawn => pawn.color === req.session.color); + const playerPawns = room.getPlayerPawns(req.session.color); for (const pawn of playerPawns) { - // (if player's pawn is in base) if the rolled number is 1,6 - if (pawn.position === pawn.basePos && (rolledNumber === 6 || rolledNumber === 1)) { - isMovePossible = true; - } - // (if player's pawn is near finish line) if the move does not go beyond the win line - if (pawn.position !== getPawnPositionAfterMove(rolledNumber, pawn) && pawn.position !== pawn.basePos) { - isMovePossible = true; - } + if (pawn.canMove(rolledNumber)) return true; } - return isMovePossible; + return false; }; - const isMoveValid = async (pawn, room) => { + const isMoveValid = (pawn, room) => { if (req.session.color !== pawn.color) { return false; } - currentlyMovingPlayer = room.players.filter(player => player.nowMoving === true); - if (req.session.playerId !== currentlyMovingPlayer._id) { + if (req.session.playerId !== room.getCurrentlyMovingPlayer()._id.toString()) { return false; } return true; }; - const skipPlayerTurn = async () => { - let room = await getRoom(); - room = changeMovingPlayer(room); + const handleChangeOfPlayer = async room => { + room.changeMovingPlayer(); + room.timeoutID = setTimeout(makeRandomMove, 15000, room); await updateRoom(room); - sendToPlayersData(room); }; - const movePawn = async ({ pawnId }) => { - let room = await getRoom(); - const indexOfPawn = room.pawns.findIndex(pawn => pawn._id == pawnId); - if (!isMoveValid(room.pawns[indexOfPawn], room)) return; - const newPositionOfMovedPawn = getPawnPositionAfterMove(room.rolledNumber, room.pawns[indexOfPawn]); - room.pawns[indexOfPawn].position = newPositionOfMovedPawn; - room = beatPawns(newPositionOfMovedPawn, room); - room = changeMovingPlayer(room); - await updateRoom(room); - sendToPlayersData(room); - }; - - const beatPawns = (position, room) => { - const pawnsInTheSamePosition = room.pawns.filter(pawn => pawn.position === position); - pawnsInTheSamePosition.forEach(pawn => { - if (pawn.color !== req.session.color) { - const index = room.pawns.findIndex(i => i._id === pawn._id); - room.pawns[index].position = room.pawns[index].basePos; - } - }); - return room; - }; - - const changeMovingPlayer = room => { - if (room.timeoutID) clearTimeout(room.timeoutID); - const playerIndex = room.players.findIndex(player => player.nowMoving === true); - room.players[playerIndex].nowMoving = false; - if (playerIndex + 1 === room.players.length) { - room.players[0].nowMoving = true; - } else { - room.players[playerIndex + 1].nowMoving = true; + const makeRandomMove = async room => { + if (room.rolledNumber === null) room.rolledNumber = rollDice(); + const pawnsThatCanMove = room.getPawnsThatCanMove() + if (pawnsThatCanMove.length > 0) { + const randomPawn = pawnsThatCanMove[Math.floor(Math.random() * pawnsThatCanMove.length)]; + room.movePawn(randomPawn); } - room.nextMoveTime = Date.now() + 15000; - room.rolledNumber = null; - room.timeoutID = setTimeout(skipPlayerTurn, 15000); - return room; + await handleChangeOfPlayer(room); }; - socket.on('game:roll', rollDice); - socket.on('game:move', movePawn); - socket.on('game:skip', skipPlayerTurn); + Room.watch().on('change', async () => { + sendToPlayersData(await getRoom()); + }); + + const getRoom = async () => { + return await Room.findOne({ _id: req.session.roomId }).exec(); + }; + + const updateRoom = async room => { + return await Room.findOneAndUpdate({ _id: req.session.roomId }, room).exec(); + }; + + const sendToPlayersRolledNumber = rolledNumber => { + io.to(req.session.roomId).emit('game:roll', rolledNumber); + }; + + const sendToPlayersData = room => { + io.to(req.session.roomId).emit('room:data', JSON.stringify(room)); + }; + + socket.on('game:roll', handleRollDice); + socket.on('game:move', handleMovePawn); }; diff --git a/backend/handlers/playerHandler.js b/backend/handlers/playerHandler.js index 568b8f3..7640f16 100644 --- a/backend/handlers/playerHandler.js +++ b/backend/handlers/playerHandler.js @@ -70,8 +70,8 @@ module.exports = (io, socket) => { req.session.reload(err => { if (err) return socket.disconnect(); // Saving session data - req.session.roomId = room._id; - req.session.playerId = room.players[0]._id; + req.session.roomId = room._id.toString(); + req.session.playerId = room.players[0]._id.toString(); req.session.color = room.players[0].color; req.session.save(); // Sending data to the user, after which player will be redirected to the game @@ -108,8 +108,8 @@ module.exports = (io, socket) => { req.session.reload(err => { if (err) return socket.disconnect(); // Saving session data - req.session.roomId = room._id; - req.session.playerId = updatedRoom.players[updatedRoom.players.length - 1]._id; + req.session.roomId = room._id.toString(); + req.session.playerId = updatedRoom.players[updatedRoom.players.length - 1]._id.toString(); req.session.color = colors[updatedRoom.players.length - 1]; req.session.save(); socket.join(room._id.toString()); diff --git a/backend/handlers/roomHandler.js b/backend/handlers/roomHandler.js index b14b2d0..962bea7 100644 --- a/backend/handlers/roomHandler.js +++ b/backend/handlers/roomHandler.js @@ -28,7 +28,7 @@ module.exports = (io, socket) => { } room.nextMoveTime = Date.now() + 15000; RoomModel.findOneAndUpdate({ _id: req.session.roomId }, room, function (err, updatedRoom) { - io.to(req.session.roomId.toString()).emit('room:data', JSON.stringify(updatedRoom)); + io.to(req.session.roomId).emit('room:data', JSON.stringify(updatedRoom)); }); }); } diff --git a/backend/schemas/pawn.js b/backend/schemas/pawn.js new file mode 100644 index 0000000..3df2429 --- /dev/null +++ b/backend/schemas/pawn.js @@ -0,0 +1,24 @@ +const mongoose = require('mongoose'); + +const Schema = mongoose.Schema; + +const { getPawnPositionAfterMove } = require('../utils/functions'); + +const PawnSchema = new Schema({ + color: String, + basePos: Number, + position: Number, +}); + +PawnSchema.methods.canMove = function (rolledNumber) { + if (this.position === this.basePos && (rolledNumber === 6 || rolledNumber === 1)) { + return true; + } + // (if player's pawn is near finish line) if the move does not go beyond the win line + if (this.position !== getPawnPositionAfterMove(rolledNumber, this) && this.position !== this.basePos) { + return true; + } + return false; +}; + +module.exports = PawnSchema; diff --git a/backend/schemas/player.js b/backend/schemas/player.js new file mode 100644 index 0000000..4c8560b --- /dev/null +++ b/backend/schemas/player.js @@ -0,0 +1,12 @@ +const mongoose = require('mongoose'); + +const Schema = mongoose.Schema; + +const PlayerSchema = new Schema({ + name: String, + color: String, + ready: { type: Boolean, default: false }, + nowMoving: { type: Boolean, default: false }, +}); + +module.exports = PlayerSchema; diff --git a/backend/schemas/room.js b/backend/schemas/room.js index eb1223a..c6118e4 100644 --- a/backend/schemas/room.js +++ b/backend/schemas/room.js @@ -1,31 +1,76 @@ -var mongoose = require('mongoose'); +const mongoose = require('mongoose'); +const { getPawnPositionAfterMove } = require('../utils/functions'); +const Schema = mongoose.Schema; +const PawnSchema = require('./pawn'); +const PlayerSchema = require('./player'); -var Schema = mongoose.Schema; - -var RoomSchema = new Schema({ +const RoomSchema = new Schema({ createDate: Date, started: { type: Boolean, default: false }, full: { type: Boolean, default: false }, nextMoveTime: Number, timeoutID: Number, rolledNumber: Number, - players: [ - { - name: String, - color: String, - ready: { type: Boolean, default: false }, - nowMoving: { type: Boolean, default: false }, - }, - ], - pawns: [ - { - color: String, - basePos: Number, - position: Number, - }, - ], + players: [PlayerSchema], + pawns: [PawnSchema], }); -var RoomModel = mongoose.model('RoomModel', RoomSchema); +RoomSchema.methods.beatPawns = function (position, attackingPawnColor) { + const pawnsOnPosition = this.pawns.filter(pawn => pawn.position === position); + pawnsOnPosition.forEach(pawn => { + if (pawn.color !== attackingPawnColor) { + const index = this.getPawnIndex(pawn._id); + this.pawns[index].position = this.pawns[index].basePos; + } + }); +}; + +RoomSchema.methods.changeMovingPlayer = function () { + const playerIndex = this.players.findIndex(player => player.nowMoving === true); + this.players[playerIndex].nowMoving = false; + if (playerIndex + 1 === this.players.length) { + this.players[0].nowMoving = true; + } else { + this.players[playerIndex + 1].nowMoving = true; + } + this.nextMoveTime = Date.now() + 15000; + this.rolledNumber = null; + if (this.timeoutID) clearTimeout(this.timeoutID); +}; + +RoomSchema.methods.movePawn = function (pawn) { + const newPositionOfMovedPawn = getPawnPositionAfterMove(this.rolledNumber, pawn); + this.changePositionOfPawn(pawn, newPositionOfMovedPawn); + this.beatPawns(newPositionOfMovedPawn, pawn.color); +}; + +RoomSchema.methods.getPawnsThatCanMove = function () { + const movingPlayer = this.getCurrentlyMovingPlayer(); + const playerPawns = this.getPlayerPawns(movingPlayer.color); + return playerPawns.filter(pawn => pawn.canMove(this.rolledNumber)); +} + +RoomSchema.methods.changePositionOfPawn = function (pawn, newPosition) { + const pawnIndex = this.getPawnIndex(pawn._id); + this.pawns[pawnIndex].position = newPosition; +}; + +RoomSchema.methods.getPawnIndex = function (pawnId) { + return this.pawns.findIndex(pawn => pawn._id.toString() === pawnId.toString()); +}; + +RoomSchema.methods.getPawn = function (pawnId) { + return this.pawns.find(pawn => pawn._id.toString() === pawnId.toString()); +}; + +RoomSchema.methods.getPlayerPawns = function (color) { + return this.pawns.filter(pawn => pawn.color === color); +}; + +RoomSchema.methods.getCurrentlyMovingPlayer = function () { + return this.players.find(player => player.nowMoving === true); +}; + +const RoomModel = mongoose.model('Room', RoomSchema); module.exports = RoomModel; diff --git a/src/components/game-board-components/Map.jsx b/src/components/game-board-components/Map.jsx index e4e30f2..0d93155 100644 --- a/src/components/game-board-components/Map.jsx +++ b/src/components/game-board-components/Map.jsx @@ -78,7 +78,7 @@ const Map = ({ pawns, nowMoving, rolledNumber }) => { y = event.clientY - rect.top; for (const pawn of pawns) { if (ctx.isPointInPath(pawn.circle, x, y)) { - socket.emit('game:move', { pawnId: pawn._id }); + socket.emit('game:move', pawn._id); } } setHintPawn(null); @@ -212,9 +212,6 @@ const Map = ({ pawns, nowMoving, rolledNumber }) => { socket.on('game:move', () => { setHintPawn(null); }); - socket.on('game:skip', () => { - setHintPawn(null); - }); socket.on('game:roll', () => { setHintPawn(null); });