added validation for moves
This commit is contained in:
parent
4bd50f4a6f
commit
70442125b3
@ -1,40 +1,24 @@
|
|||||||
const RoomModel = require('../schemas/room');
|
const RoomModel = require('../schemas/room');
|
||||||
const { getPositionAfterMove } = require('../utils/functions');
|
const { getPawnPositionAfterMove } = require('../utils/functions');
|
||||||
/*
|
|
||||||
Function handle all requests
|
|
||||||
file constains functions:
|
|
||||||
1. roll
|
|
||||||
2. move
|
|
||||||
*/
|
|
||||||
module.exports = (io, socket) => {
|
module.exports = (io, socket) => {
|
||||||
const req = socket.request;
|
const req = socket.request;
|
||||||
|
/*
|
||||||
const roll = async () => {
|
Function responsible for drawing number in range from 1 to 6 and returning it to the player
|
||||||
|
if current player can move with drawed number allow the player to make a move
|
||||||
|
else skip player's turn
|
||||||
|
*/
|
||||||
|
const rollDiceNumber = async () => {
|
||||||
const rolledNumber = Math.ceil(Math.random() * 6);
|
const rolledNumber = Math.ceil(Math.random() * 6);
|
||||||
const room = await RoomModel.findOne({ _id: req.session.roomId }).exec();
|
let room = await RoomModel.findOne({ _id: req.session.roomId }).exec();
|
||||||
room.rolledNumber = rolledNumber;
|
room.rolledNumber = rolledNumber;
|
||||||
await RoomModel.findOneAndUpdate({ _id: req.session.roomId }, room).exec();
|
await RoomModel.findOneAndUpdate({ _id: req.session.roomId }, room).exec();
|
||||||
io.to(req.session.roomId.toString()).emit('game:roll', rolledNumber);
|
io.to(req.session.roomId.toString()).emit('game:roll', rolledNumber);
|
||||||
|
const isPossible = await canPlayerMoveAnyPawn(req.session.roomId, req.session.color, rolledNumber);
|
||||||
const isPossible = await isMovePossible(req.session.roomId, req.session.color, rolledNumber);
|
|
||||||
if (!isPossible) {
|
if (!isPossible) {
|
||||||
const room = await RoomModel.findOne({ _id: req.session.roomId }).exec();
|
room = changeMovingPlayer(room);
|
||||||
const playerIndex = room.players.findIndex(player => player.nowMoving === true);
|
await RoomModel.findOneAndUpdate({ _id: req.session.roomId }, room).exec();
|
||||||
const roomSize = room.players.length;
|
|
||||||
room.players[playerIndex].nowMoving = false;
|
|
||||||
if (playerIndex + 1 === roomSize) {
|
|
||||||
room.players[0].nowMoving = true;
|
|
||||||
} else {
|
|
||||||
room.players[playerIndex + 1].nowMoving = true;
|
|
||||||
}
|
|
||||||
// Updating timer
|
|
||||||
room.nextMoveTime = Date.now() + 15000;
|
|
||||||
room.rolledNumber = null;
|
|
||||||
// Pushing above data to database
|
|
||||||
RoomModel.findOneAndUpdate({ _id: req.session.roomId }, room, err => {
|
|
||||||
if (err) return err;
|
|
||||||
io.to(req.session.roomId.toString()).emit('room:data', JSON.stringify(room));
|
io.to(req.session.roomId.toString()).emit('room:data', JSON.stringify(room));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
/*
|
/*
|
||||||
@ -45,7 +29,7 @@ module.exports = (io, socket) => {
|
|||||||
2) (if player's pawn is near finish line) if the move does not go beyond the win line
|
2) (if player's pawn is near finish line) if the move does not go beyond the win line
|
||||||
Returns boolean
|
Returns boolean
|
||||||
*/
|
*/
|
||||||
const isMovePossible = async (roomId, playerColor, rolledNumber) => {
|
const canPlayerMoveAnyPawn = async (roomId, playerColor, rolledNumber) => {
|
||||||
let isMovePossible = false;
|
let isMovePossible = false;
|
||||||
const room = await RoomModel.findOne({ _id: roomId.toString() }).exec();
|
const room = await RoomModel.findOne({ _id: roomId.toString() }).exec();
|
||||||
const playerPawns = room.pawns.filter(pawn => pawn.color === playerColor);
|
const playerPawns = room.pawns.filter(pawn => pawn.color === playerColor);
|
||||||
@ -56,66 +40,77 @@ module.exports = (io, socket) => {
|
|||||||
isMovePossible = true;
|
isMovePossible = true;
|
||||||
}
|
}
|
||||||
// Checking the second condition
|
// Checking the second condition
|
||||||
if (pawn.position !== getPositionAfterMove(rolledNumber, pawn) && pawn.position !== pawn.basePos) {
|
if (pawn.position !== getPawnPositionAfterMove(rolledNumber, pawn) && pawn.position !== pawn.basePos) {
|
||||||
isMovePossible = true;
|
isMovePossible = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return isMovePossible;
|
return isMovePossible;
|
||||||
};
|
};
|
||||||
|
const isMoveValid = async (pawn, room) => {
|
||||||
const skip = async () => {
|
if (req.session.color !== pawn.color) {
|
||||||
const room = await RoomModel.findOne({ _id: req.session.roomId }).exec();
|
return false;
|
||||||
if (room.nextMoveTime >= Date.now()) return;
|
|
||||||
// Updating moving player
|
|
||||||
const playerIndex = room.players.findIndex(player => player.nowMoving === true);
|
|
||||||
const roomSize = room.players.length;
|
|
||||||
room.players[playerIndex].nowMoving = false;
|
|
||||||
if (playerIndex + 1 === roomSize) {
|
|
||||||
room.players[0].nowMoving = true;
|
|
||||||
} else {
|
|
||||||
room.players[playerIndex + 1].nowMoving = true;
|
|
||||||
}
|
}
|
||||||
// Updating timer
|
currentlyMovingPlayer = room.players.filter(player => player.nowMoving === true);
|
||||||
room.nextMoveTime = Date.now() + 15000;
|
if (req.session.playerId !== currentlyMovingPlayer._id) {
|
||||||
room.rolledNumber = null;
|
return false;
|
||||||
setTimeout(skip, 15000);
|
}
|
||||||
// Pushing above data to database
|
return true;
|
||||||
RoomModel.findOneAndUpdate({ _id: req.session.roomId }, room, err => {
|
|
||||||
if (err) return err;
|
|
||||||
io.to(req.session.roomId.toString()).emit('room:data', JSON.stringify(room));
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
const move = async ({ pawnId }) => {
|
/*
|
||||||
const room = await RoomModel.findOne({ _id: req.session.roomId }).exec();
|
Function responsible for skipping a player's turn, if he did not move within the allotted time
|
||||||
const pawnIndex = room.pawns.findIndex(pawn => pawn._id == pawnId);
|
Function is used in timeouts that start after a player's move or after skipping his turn
|
||||||
room.pawns[pawnIndex].position = getPositionAfterMove(room.rolledNumber, room.pawns[pawnIndex]);
|
*/
|
||||||
const pawnsOnPos = room.pawns.filter(pawn => pawn.position == room.pawns[pawnIndex].position);
|
const skipPlayerTurn = async () => {
|
||||||
pawnsOnPos.forEach(pawn => {
|
let room = await RoomModel.findOne({ _id: req.session.roomId }).exec();
|
||||||
|
room = changeMovingPlayer(room);
|
||||||
|
await RoomModel.findOneAndUpdate({ _id: req.session.roomId }, room).exec();
|
||||||
|
io.to(req.session.roomId.toString()).emit('room:data', JSON.stringify(room));
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
Function responsible for moving the pawn by the number of spots that have been drawn
|
||||||
|
Props: pawnId - Id which is needed to find a pawn in the board. Id is the only thing that distinguishes pawns of the same color.
|
||||||
|
*/
|
||||||
|
const movePawn = async ({ pawnId }) => {
|
||||||
|
let room = await RoomModel.findOne({ _id: req.session.roomId }).exec();
|
||||||
|
const indexOfMovedPawn = room.pawns.findIndex(pawn => pawn._id == pawnId);
|
||||||
|
const newPositionOfMovedPawn = getPawnPositionAfterMove(room.rolledNumber, room.pawns[indexOfMovedPawn]);
|
||||||
|
if (!isMoveValid(room.pawns[indexOfMovedPawn], room)) return;
|
||||||
|
room.pawns[indexOfMovedPawn].position = newPositionOfMovedPawn;
|
||||||
|
// Looking for pawns in the same position as the new position of the pawn
|
||||||
|
const pawnsInTheSamePosition = room.pawns.filter(pawn => pawn.position === newPositionOfMovedPawn);
|
||||||
|
// Each pawn in this position is checked to see if it has the same color as the pawn that has now moved to this position, if so, it is moved to the base (captured)
|
||||||
|
pawnsInTheSamePosition.forEach(pawn => {
|
||||||
if (pawn.color !== req.session.color) {
|
if (pawn.color !== req.session.color) {
|
||||||
const index = room.pawns.findIndex(i => i._id === pawn._id);
|
const index = room.pawns.findIndex(i => i._id === pawn._id);
|
||||||
room.pawns[index].position = room.pawns[index].basePos;
|
room.pawns[index].position = room.pawns[index].basePos;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Updating moving player
|
room = changeMovingPlayer(room);
|
||||||
|
await RoomModel.findOneAndUpdate({ _id: req.session.roomId }, room).exec();
|
||||||
|
io.to(req.session.roomId.toString()).emit('room:data', JSON.stringify(room));
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
Function responsible for changing the currently moving player in room object.
|
||||||
|
It changes the value of nowMoving for both players and sets a new turn-end time and erases the currently drawn number.
|
||||||
|
The function is used as an auxiliary function in other functions because many of them perform the operation of changing the currently moving player.
|
||||||
|
Args: room (object) from mongoDB
|
||||||
|
Returns: room object after changes
|
||||||
|
*/
|
||||||
|
const changeMovingPlayer = room => {
|
||||||
const playerIndex = room.players.findIndex(player => player.nowMoving === true);
|
const playerIndex = room.players.findIndex(player => player.nowMoving === true);
|
||||||
const roomSize = room.players.length;
|
|
||||||
room.players[playerIndex].nowMoving = false;
|
room.players[playerIndex].nowMoving = false;
|
||||||
if (playerIndex + 1 === roomSize) {
|
if (playerIndex + 1 === room.players.length) {
|
||||||
room.players[0].nowMoving = true;
|
room.players[0].nowMoving = true;
|
||||||
} else {
|
} else {
|
||||||
room.players[playerIndex + 1].nowMoving = true;
|
room.players[playerIndex + 1].nowMoving = true;
|
||||||
}
|
}
|
||||||
// Updating timer
|
|
||||||
room.nextMoveTime = Date.now() + 15000;
|
room.nextMoveTime = Date.now() + 15000;
|
||||||
room.rolledNumber = null;
|
room.rolledNumber = null;
|
||||||
setTimeout(skip, 15000);
|
setTimeout(skipPlayerTurn, 15000);
|
||||||
// Pushing above data to database
|
return room;
|
||||||
RoomModel.findOneAndUpdate({ _id: req.session.roomId }, room, (err, updatedRoom) => {
|
|
||||||
if (!updatedRoom) return err;
|
|
||||||
io.to(req.session.roomId.toString()).emit('room:data', JSON.stringify(room));
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
socket.on('game:roll', roll);
|
|
||||||
socket.on('game:move', move);
|
socket.on('game:roll', rollDiceNumber);
|
||||||
socket.on('game:skip', skip);
|
socket.on('game:move', movePawn);
|
||||||
|
socket.on('game:skip', skipPlayerTurn);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,15 +1,7 @@
|
|||||||
const RoomModel = require('../schemas/room');
|
const RoomModel = require('../schemas/room');
|
||||||
const { colors } = require('../utils/constants');
|
const { colors } = require('../utils/constants');
|
||||||
const { getStartPositions } = require('../utils/functions');
|
const { getStartPositions } = require('../utils/functions');
|
||||||
/*
|
|
||||||
Function handle all player's requests to server
|
|
||||||
file constains functions:
|
|
||||||
1. login
|
|
||||||
with helper functions:
|
|
||||||
- addPlayerToExistingRoom
|
|
||||||
- createNewRoom
|
|
||||||
2. ready
|
|
||||||
*/
|
|
||||||
module.exports = (io, socket) => {
|
module.exports = (io, socket) => {
|
||||||
const req = socket.request;
|
const req = socket.request;
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ function getStartPositions() {
|
|||||||
}
|
}
|
||||||
return startPositions;
|
return startPositions;
|
||||||
}
|
}
|
||||||
function getPositionAfterMove(rolledNumber, pawn) {
|
function getPawnPositionAfterMove(rolledNumber, pawn) {
|
||||||
const { position, color } = pawn;
|
const { position, color } = pawn;
|
||||||
switch (color) {
|
switch (color) {
|
||||||
case 'red':
|
case 'red':
|
||||||
@ -72,4 +72,4 @@ function getPositionAfterMove(rolledNumber, pawn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module.exports = { getStartPositions, getPositionAfterMove };
|
module.exports = { getStartPositions, getPawnPositionAfterMove };
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import Navbar from './Navbar';
|
|||||||
const Gameboard = () => {
|
const Gameboard = () => {
|
||||||
// Context data
|
// Context data
|
||||||
const socket = useContext(SocketContext);
|
const socket = useContext(SocketContext);
|
||||||
const player = useContext(PlayerDataContext);
|
const context = useContext(PlayerDataContext);
|
||||||
// Render data
|
// Render data
|
||||||
const [pawns, setPawns] = useState([]);
|
const [pawns, setPawns] = useState([]);
|
||||||
const [players, setPlayers] = useState([]);
|
const [players, setPlayers] = useState([]);
|
||||||
@ -32,7 +32,7 @@ const Gameboard = () => {
|
|||||||
}
|
}
|
||||||
}, [pawns]);
|
}, [pawns]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
socket.emit('room:data', player.roomId);
|
socket.emit('room:data', context.roomId);
|
||||||
socket.on('room:data', data => {
|
socket.on('room:data', data => {
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
// Filling navbar with empty player nick container
|
// Filling navbar with empty player nick container
|
||||||
@ -42,15 +42,14 @@ const Gameboard = () => {
|
|||||||
// Checks if client is currently moving player by session ID
|
// Checks if client is currently moving player by session ID
|
||||||
const nowMovingPlayer = data.players.find(player => player.nowMoving === true);
|
const nowMovingPlayer = data.players.find(player => player.nowMoving === true);
|
||||||
if (nowMovingPlayer) {
|
if (nowMovingPlayer) {
|
||||||
if (nowMovingPlayer._id === player.playerId) {
|
if (nowMovingPlayer._id === context.playerId) {
|
||||||
setNowMoving(true);
|
setNowMoving(true);
|
||||||
} else {
|
} else {
|
||||||
setNowMoving(false);
|
setNowMoving(false);
|
||||||
}
|
}
|
||||||
setMovingPlayer(nowMovingPlayer.color);
|
setMovingPlayer(nowMovingPlayer.color);
|
||||||
}
|
}
|
||||||
const currentPlayer = data.players.find(player => player._id === player.playerId);
|
const currentPlayer = data.players.find(player => player._id === context.playerId);
|
||||||
|
|
||||||
checkWin();
|
checkWin();
|
||||||
setIsReady(currentPlayer.ready);
|
setIsReady(currentPlayer.ready);
|
||||||
setRolledNumber(data.rolledNumber);
|
setRolledNumber(data.rolledNumber);
|
||||||
|
|||||||
@ -10,7 +10,7 @@ const Navbar = ({ players, started, time, isReady, rolledNumber, nowMoving, roll
|
|||||||
<div className='navbar-container'>
|
<div className='navbar-container'>
|
||||||
{players.map((player, index) => (
|
{players.map((player, index) => (
|
||||||
<div className={`player-container ${colors[index]}`} key={index}>
|
<div className={`player-container ${colors[index]}`} key={index}>
|
||||||
<NameContainer player={player} time={time} containerColor={colors[index]} />
|
<NameContainer player={player} time={time} />
|
||||||
<Dice
|
<Dice
|
||||||
movingPlayer={movingPlayer}
|
movingPlayer={movingPlayer}
|
||||||
rolledNumber={rolledNumber}
|
rolledNumber={rolledNumber}
|
||||||
|
|||||||
@ -6,7 +6,6 @@ const Map = ({ pawns, nowMoving, rolledNumber }) => {
|
|||||||
const context = useContext(PlayerDataContext);
|
const context = useContext(PlayerDataContext);
|
||||||
const socket = useContext(SocketContext);
|
const socket = useContext(SocketContext);
|
||||||
const [hintPawn, setHintPawn] = useState();
|
const [hintPawn, setHintPawn] = useState();
|
||||||
const [blinking, setBlinking] = useState(false);
|
|
||||||
const paintPawn = (context, x, y, color) => {
|
const paintPawn = (context, x, y, color) => {
|
||||||
const circle = new Path2D();
|
const circle = new Path2D();
|
||||||
circle.arc(x, y, 12, 0, 2 * Math.PI);
|
circle.arc(x, y, 12, 0, 2 * Math.PI);
|
||||||
@ -150,7 +149,6 @@ const Map = ({ pawns, nowMoving, rolledNumber }) => {
|
|||||||
checkIfPawnCanMove(pawn)
|
checkIfPawnCanMove(pawn)
|
||||||
) {
|
) {
|
||||||
const pawnPosition = getHintPawnPosition(pawn);
|
const pawnPosition = getHintPawnPosition(pawn);
|
||||||
setBlinking(false);
|
|
||||||
// Checks if pawn can make a move
|
// Checks if pawn can make a move
|
||||||
if (pawnPosition) {
|
if (pawnPosition) {
|
||||||
canvas.style.cursor = 'pointer';
|
canvas.style.cursor = 'pointer';
|
||||||
@ -172,7 +170,7 @@ const Map = ({ pawns, nowMoving, rolledNumber }) => {
|
|||||||
image.onload = function () {
|
image.onload = function () {
|
||||||
ctx.drawImage(image, 0, 0);
|
ctx.drawImage(image, 0, 0);
|
||||||
pawns.forEach((pawn, index) => {
|
pawns.forEach((pawn, index) => {
|
||||||
if (nowMoving && rolledNumber && blinking && pawn.color === context.color && checkIfPawnCanMove(pawn)) {
|
if (nowMoving && rolledNumber && pawn.color === context.color && checkIfPawnCanMove(pawn)) {
|
||||||
pawns[index].circle = paintPawn(
|
pawns[index].circle = paintPawn(
|
||||||
ctx,
|
ctx,
|
||||||
positions[pawn.position].x,
|
positions[pawn.position].x,
|
||||||
@ -187,7 +185,6 @@ const Map = ({ pawns, nowMoving, rolledNumber }) => {
|
|||||||
pawn.color
|
pawn.color
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
setBlinking(!blinking);
|
|
||||||
});
|
});
|
||||||
if (hintPawn) {
|
if (hintPawn) {
|
||||||
paintPawn(ctx, positions[hintPawn.position].x, positions[hintPawn.position].y, hintPawn.color);
|
paintPawn(ctx, positions[hintPawn.position].x, positions[hintPawn.position].y, hintPawn.color);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user