From acdbad41cd867132062aa896d164b3789fc08847 Mon Sep 17 00:00:00 2001 From: MaciejkaG Date: Sat, 6 Apr 2024 00:05:11 +0200 Subject: [PATCH] Major changes - Minor improvements - Added random ship depletion. When prep phase ends, remaining ships are automatically placed in random valid positions --- index.js | 29 +++++-- lang/en.json | 1 + lang/pl.json | 1 + utils/battleships.js | 178 +++++++++++++++++++++++++++++++++++++------ 4 files changed, 176 insertions(+), 33 deletions(-) diff --git a/index.js b/index.js index dbf0de1..2e79496 100644 --- a/index.js +++ b/index.js @@ -230,7 +230,7 @@ app.post('/api/login', (req, res) => { helpers: { error: "Niepoprawny adres e-mail", fallback: "/login", - + t: (key) => { return locale.t(key) } } }); } @@ -277,7 +277,13 @@ app.post('/api/nickname', (req, res) => { res.redirect('/'); }); } else { - res.sendStatus(400); + res.render("error", { + helpers: { + error: "Nazwa nie spełnia wymogów: Od 3 do 16 znaków, nie może być pusta", + fallback: "/nickname", + t: (key) => { return locale.t(key) } + } + }); } }); @@ -482,12 +488,19 @@ io.on('connection', async (socket) => { let UTCTs = Math.floor((new Date()).getTime() / 1000 + 90); io.to(playerGame.id).emit('turn update', { turn: 0, phase: "preparation", timerToUTC: UTCTs }); GInfo.timer(playerGame.id, 90, async () => { - const playerGame = await GInfo.getPlayerGameData(socket); - for (let i = 0; i < playerGame.data.boards.length; i++) { - const ships = playerGame.data.boards[i].ships; - if (!ships.length) { - AFKEnd(playerGame.id); - return; + const members = [...roomMemberIterator(playerGame.id)]; + for (let i = 0; i < members.length; i++) { + const sid = members[i][0]; + const socket = io.sockets.sockets.get(sid); + + let placedShips = await GInfo.depleteShips(socket); + placedShips.forEach(shipData => { + socket.emit("placed ship", shipData) + }); + + if (placedShips.length > 0) { + const locale = new Lang(session.langs); + socket.emit("toast", locale.t("board.Your remaining ships have been randomly placed")) } } diff --git a/lang/en.json b/lang/en.json index d8f752a..3201458 100644 --- a/lang/en.json +++ b/lang/en.json @@ -112,6 +112,7 @@ "You cannot place a ship like this": "You cannot place a ship like this", "You have ran out of ships of that type": "You have ran out of ships of that type", "You have already shot at this field": "You have already shot at this field", + "Your remaining ships have been randomly placed": "Your remaining ships have been automatically placed", "Victory": "Victory", "Defeat": "Defeat" diff --git a/lang/pl.json b/lang/pl.json index ef2b30c..b327e8c 100644 --- a/lang/pl.json +++ b/lang/pl.json @@ -114,6 +114,7 @@ "You cannot place a ship like this": "Nie możesz tak postawić statku", "You have ran out of ships of that type": "Skończyły ci się statki tego typu", "You have already shot at this field": "Już strzelałeś w to pole", + "Your remaining ships have been randomly placed": "Twoje pozostałe statki zostały automatycznie rozstawione", "Victory": "Zwycięstwo", "Defeat": "Porażka" diff --git a/utils/battleships.js b/utils/battleships.js index ef081e7..1bb89db 100644 --- a/utils/battleships.js +++ b/utils/battleships.js @@ -46,7 +46,6 @@ export class GameInfo { const boards = await this.redis.json.get(`game:${socket.session.activeGame}`, { path: ".boards" }); let stats = []; - console.log(boards); boards.forEach(board => { stats.push(board.stats); }); @@ -100,6 +99,113 @@ export class GameInfo { await this.redis.json.arrAppend(key, `.boards[${playerIdx}].ships`, shipData); } + async depleteShips(socket) { + const gameId = socket.session.activeGame; + const key = `game:${gameId}`; + const hostId = (await this.redis.json.get(key, { path: '.hostId' })); + + const playerIdx = socket.request.session.id === hostId ? 0 : 1; + + var playerShips = (await this.redis.json.get(key, { path: `.boards[${playerIdx}].ships` })); + + const availableShips = getShipsAvailable(playerShips); + + const boardRender = []; + const subtrahents = [[0, 0], [0, 1], [1, 0], [0, -1], [-1, 0], [1, 1], [-1, -1], [1, -1], [-1, 1]]; + + for (let i = 0; i < 10; i++) { + var array = []; + for (let i = 0; i < 10; i++) { + array.push(false); + } + boardRender.push(array); + } + + playerShips.forEach(ship => { + let multips; + + switch (ship.rot) { + case 0: + multips = [1, 0]; + break; + + case 1: + multips = [0, 1]; + break; + + case 2: + multips = [-1, 0]; + break; + + case 3: + multips = [0, -1]; + break; + } + + for (let i = 0; i <= ship.type; i++) { + for (let l = 0; l < subtrahents.length; l++) { + const idxX = ship.posX - subtrahents[l][0] + multips[0] * i; + const idxY = ship.posY - subtrahents[l][1] + multips[1] * i; + if (!(idxX < 0 || idxX > 9 || idxY < 0 || idxY > 9)) { + boardRender[idxX][idxY] = true; + } + } + } + }); + + const placedShips = []; + + for (let i = 0; i < availableShips.length; i++) { + let availableShipsOfType = availableShips[i]; + for (let j = 0; j < availableShipsOfType; j++) { + playerShips = (await this.redis.json.get(key, { path: `.boards[${playerIdx}].ships` })); + for (let y = 0; y < 10; y++) { + let row = ""; + for (let x = 0; x < 10; x++) { + row += `${boardRender[x][y] ? "\x1b[31m" : "\x1b[32m"}${boardRender[x][y]}\x1b[0m\t`; + } + } + const search = findEmptyFields(boardRender, i+1); + + const rPos = search[Math.floor(Math.random() * search.length)]; + + placedShips.push({ type: i, posX: rPos.posX, posY: rPos.posY, rot: rPos.rot }); + await this.redis.json.arrAppend(key, `.boards[${playerIdx}].ships`, { type: i, posX: rPos.posX, posY: rPos.posY, rot: rPos.rot, hits: Array.from(new Array(i + 1), () => false) }); + let multips; + + switch (rPos.rot) { + case 0: + multips = [1, 0]; + break; + + case 1: + multips = [0, 1]; + break; + + case 2: + multips = [-1, 0]; + break; + + case 3: + multips = [0, -1]; + break; + } + + for (let k = 0; k <= i; k++) { + for (let l = 0; l < subtrahents.length; l++) { + const idxX = rPos.posX - subtrahents[l][0] + multips[0] * k; + const idxY = rPos.posY - subtrahents[l][1] + multips[1] * k; + if (!(idxX < 0 || idxX > 9 || idxY < 0 || idxY > 9)) { + boardRender[idxX][idxY] = true; + } + } + } + } + } + + return placedShips; + } + async removeShip(socket, posX, posY) { const gameId = socket.session.activeGame; const key = `game:${gameId}`; @@ -175,30 +281,6 @@ export function isPlayerInRoom(socket) { return !socket.rooms.size === 1; } -var lastTimeChange = new Date().getTime(); - -// export function getShipsLeft(data, playerIdx) { -// let shipsLeft = [4, 3, 2, 1]; - -// const playerShips = shipsLeft.boards[playerIdx].ships; - -// playerShips.forEach(ship => { -// var isSunk = true; -// ship.hits.every(isHit => { -// isSunk = isHit; -// return isHit; -// }); -// switch (ship.type) { -// case 0: -// shipsLeft[0]--; -// break; - -// default: -// break; -// } -// }); -// } - export function getShipsAvailable(ships) { let shipsLeft = [4, 3, 2, 1]; @@ -340,6 +422,52 @@ export function checkTurn(data, playerId) { } } +function findEmptyFields(grid, len) { + const rowPlacements = []; + + // Helper function to check if a row can be placed horizontally at a given position + function canPlaceHorizontally(x, y) { + if (x + len >= grid[0].length) { + return false; // Ship exceeds board boundaries + } + for (let i = x; i <= x + len; i++) { + if (grid[i][y]) { + return false; // One of ship's fields is already occupied + } + } + return true; + } + + // Helper function to check if a row can be placed vertically at a given position + function canPlaceVertically(x, y) { + if (y + len >= grid.length) { + return false; // Ship exceeds board boundaries + } + for (let i = y; i <= y + len; i++) { + if (grid[x][i]) { + return false; // One of ship's fields is already occupied + } + } + return true; + } + + for (let i = 0; i < grid.length; i++) { + for (let j = 0; j < grid[0].length; j++) { + if (grid[j][i] === false) { + if (canPlaceHorizontally(j, i)) { + rowPlacements.push({ posX: j, posY: i, rot: 0 }); + } + + if (canPlaceVertically(j, i)) { + rowPlacements.push({ posX: j, posY: i, rot: 1 }); + } + } + } + } + + return rowPlacements; +} + function clamp(n, min, max) { return Math.min(Math.max(n, min), max); } \ No newline at end of file