mirror of
https://github.com/MaciejkaG/statki.git
synced 2024-11-30 05:22:55 +01:00
Major update
- UI/UX improvements - Multiple bug fixes and improvements
This commit is contained in:
parent
7cfbfa1109
commit
b956120312
94
index.js
94
index.js
@ -447,6 +447,7 @@ io.on('connection', async (socket) => {
|
|||||||
hostId: opp.request.session.id,
|
hostId: opp.request.session.id,
|
||||||
state: "pregame",
|
state: "pregame",
|
||||||
startTs: (new Date()).getTime() / 1000,
|
startTs: (new Date()).getTime() / 1000,
|
||||||
|
ready: [false, false],
|
||||||
boards: [
|
boards: [
|
||||||
{ // typ 2 to trójmasztowiec pozycja i obrót na planszy które pola zostały trafione
|
{ // typ 2 to trójmasztowiec pozycja i obrót na planszy które pola zostały trafione
|
||||||
ships: [], // zawiera np. {type: 2, posX: 3, posY: 4, rot: 2, hits: [false, false, true]}
|
ships: [], // zawiera np. {type: 2, posX: 3, posY: 4, rot: 2, hits: [false, false, true]}
|
||||||
@ -528,29 +529,10 @@ io.on('connection', async (socket) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let UTCTs = Math.floor((new Date()).getTime() / 1000 + 90);
|
let UTCTs = Math.floor((new Date()).getTime() / 1000 + 180);
|
||||||
io.to(playerGame.id).emit('turn update', { turn: 0, phase: "preparation", timerToUTC: UTCTs });
|
io.to(playerGame.id).emit('turn update', { turn: 0, phase: "preparation", timerToUTC: UTCTs });
|
||||||
GInfo.timer(playerGame.id, 90, async () => {
|
GInfo.timer(playerGame.id, 180, async () => {
|
||||||
const members = [...roomMemberIterator(playerGame.id)];
|
finishPrepPhase(socket, playerGame);
|
||||||
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"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GInfo.endPrepPhase(socket);
|
|
||||||
GInfo.timer(playerGame.id, 30, () => {
|
|
||||||
AFKEnd(playerGame.id);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await redis.json.set(`game:${playerGame.id}`, '$.state', "preparation");
|
await redis.json.set(`game:${playerGame.id}`, '$.state', "preparation");
|
||||||
@ -563,6 +545,50 @@ io.on('connection', async (socket) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
socket.on('ready', async (callback) => {
|
||||||
|
const playerGame = await GInfo.getPlayerGameData(socket);
|
||||||
|
let timeLeft = await GInfo.timerLeft(playerGame.id);
|
||||||
|
|
||||||
|
if (timeLeft > 170) {
|
||||||
|
const locale = new Lang(session.langs);
|
||||||
|
socket.emit('toast', locale.t("board.You cannot ready up so early"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playerGame && playerGame.data.state === 'preparation') {
|
||||||
|
await GInfo.setReady(socket);
|
||||||
|
const playerGame = await GInfo.getPlayerGameData(socket);
|
||||||
|
|
||||||
|
if (playerGame.data.ready[0] && playerGame.data.ready[1]) {
|
||||||
|
// Both set ready
|
||||||
|
await GInfo.resetTimer(playerGame.id);
|
||||||
|
|
||||||
|
await finishPrepPhase(socket, playerGame);
|
||||||
|
} else if (playerGame.data.ready[0] || playerGame.data.ready[1]) {
|
||||||
|
// One player set ready
|
||||||
|
|
||||||
|
const members = [...roomMemberIterator(playerGame.id)];
|
||||||
|
for (let i = 0; i < members.length; i++) {
|
||||||
|
const sid = members[i][0];
|
||||||
|
const pSocket = io.sockets.sockets.get(sid);
|
||||||
|
if (pSocket.session.id !== socket.session.id) {
|
||||||
|
const locale = new Lang(pSocket.session.langs);
|
||||||
|
|
||||||
|
pSocket.emit("toast", locale.t("board.Your opponent is ready"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let UTCTs = Math.floor((new Date()).getTime() / 1000 + Math.max(timeLeft / 2.5, 15));
|
||||||
|
io.to(playerGame.id).emit('turn update', { turn: 0, phase: "preparation", timerToUTC: UTCTs });
|
||||||
|
await GInfo.timer(playerGame.id, Math.max(timeLeft / 2.5, 15), async () => {
|
||||||
|
await finishPrepPhase(socket, playerGame);
|
||||||
|
});
|
||||||
|
} // else if (playerGame.data.ready[1]) {
|
||||||
|
// // Guest set ready
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
socket.on('place ship', async (type, posX, posY, rot) => {
|
socket.on('place ship', async (type, posX, posY, rot) => {
|
||||||
const playerGame = await GInfo.getPlayerGameData(socket);
|
const playerGame = await GInfo.getPlayerGameData(socket);
|
||||||
|
|
||||||
@ -736,3 +762,27 @@ function checkFlag(key) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function finishPrepPhase(socket, playerGame) {
|
||||||
|
await GInfo.endPrepPhase(socket);
|
||||||
|
|
||||||
|
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(socket.session.langs);
|
||||||
|
socket.emit("toast", locale.t("board.Your remaining ships have been randomly placed"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GInfo.timer(playerGame.id, 30, () => {
|
||||||
|
AFKEnd(playerGame.id);
|
||||||
|
});
|
||||||
|
}
|
11
lang/en.json
11
lang/en.json
@ -103,6 +103,15 @@
|
|||||||
"Four-masted": "Four-masted",
|
"Four-masted": "Four-masted",
|
||||||
"Available:": "Available:",
|
"Available:": "Available:",
|
||||||
|
|
||||||
|
"Sunk ships": "Sunk ships",
|
||||||
|
"Single-mastedPlu": "Single-masted:",
|
||||||
|
"Two-mastedPlu": "Two-masted:",
|
||||||
|
"Three-mastedPlu": "Three-masted:",
|
||||||
|
"Four-mastedPlu": "Four-masted:",
|
||||||
|
"Your accuracy": "Your accuracy",
|
||||||
|
|
||||||
|
"Ready up": "Ready up",
|
||||||
|
|
||||||
"Controls": "Controls",
|
"Controls": "Controls",
|
||||||
"Change ship": "Change ship",
|
"Change ship": "Change ship",
|
||||||
"Rotate ship": "Rotate ship",
|
"Rotate ship": "Rotate ship",
|
||||||
@ -116,6 +125,8 @@
|
|||||||
"You have ran out of ships of that type": "You have ran out of ships of that type",
|
"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",
|
"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",
|
"Your remaining ships have been randomly placed": "Your remaining ships have been automatically placed",
|
||||||
|
"Your opponent is ready": "Your opponent is ready.\nTime for preparation has been reduced",
|
||||||
|
"You cannot ready up so early": "You cannot ready up so early!",
|
||||||
|
|
||||||
"Victory": "Victory",
|
"Victory": "Victory",
|
||||||
"Defeat": "Defeat"
|
"Defeat": "Defeat"
|
||||||
|
11
lang/pl.json
11
lang/pl.json
@ -104,6 +104,15 @@
|
|||||||
"Four-masted": "Czteromasztowiec",
|
"Four-masted": "Czteromasztowiec",
|
||||||
"Available:": "Dostępne:",
|
"Available:": "Dostępne:",
|
||||||
|
|
||||||
|
"Sunk ships": "Zatopione statki",
|
||||||
|
"Single-mastedPlu": "Jednomasztowce:",
|
||||||
|
"Two-mastedPlu": "Dwumasztowce:",
|
||||||
|
"Three-mastedPlu": "Trójmasztowce:",
|
||||||
|
"Four-mastedPlu": "Czteromasztowce:",
|
||||||
|
"Your accuracy": "Twoja celność",
|
||||||
|
|
||||||
|
"Ready up": "Gotowy",
|
||||||
|
|
||||||
"Controls": "Sterowanie",
|
"Controls": "Sterowanie",
|
||||||
"Change ship": "Zmień statek",
|
"Change ship": "Zmień statek",
|
||||||
"Rotate ship": "Obróć statek",
|
"Rotate ship": "Obróć statek",
|
||||||
@ -117,6 +126,8 @@
|
|||||||
"You have ran out of ships of that type": "Skończyły ci się statki tego typu",
|
"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",
|
"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",
|
"Your remaining ships have been randomly placed": "Twoje pozostałe statki zostały automatycznie rozstawione",
|
||||||
|
"Your opponent is ready": "Twój przeciwnik jest gotowy.\nCzas na przygotowania został skrócony",
|
||||||
|
"You cannot ready up so early": "Nie możesz zgłosić gotowości tak wcześnie!",
|
||||||
|
|
||||||
"Victory": "Zwycięstwo",
|
"Victory": "Zwycięstwo",
|
||||||
"Defeat": "Porażka"
|
"Defeat": "Porażka"
|
||||||
|
@ -176,6 +176,7 @@ h1,h2,h3,h4,h5,h6 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ownBoardInfo {
|
.ownBoardInfo {
|
||||||
|
height: 11rem;
|
||||||
transition: opacity 0.3s;
|
transition: opacity 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,7 +209,7 @@ h1,h2,h3,h4,h5,h6 {
|
|||||||
to {transform: translateX(0);opacity:1;}
|
to {transform: translateX(0);opacity:1;}
|
||||||
}
|
}
|
||||||
|
|
||||||
#selectedShip.changing {
|
#selectedShip.changing, .ownBoardInfo.changing {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
animation: changingOut 1 0.2s ease;
|
animation: changingOut 1 0.2s ease;
|
||||||
}
|
}
|
||||||
@ -309,7 +310,7 @@ h1,h2,h3,h4,h5,h6 {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobileControls button {
|
.mobileControls button, .readyButton {
|
||||||
padding: 0.5rem 2rem;
|
padding: 0.5rem 2rem;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
background-color: black;
|
background-color: black;
|
||||||
@ -322,3 +323,30 @@ h1,h2,h3,h4,h5,h6 {
|
|||||||
|
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.readyButton:hover {
|
||||||
|
color: black;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lateBoardInfo {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ownBoardInfo #accuracy {
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ownBoardInfo #accuracy.animatingDown {
|
||||||
|
color: var(--ship-invalid);
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ownBoardInfo #accuracy.animatingUp {
|
||||||
|
color: var(--ship-valid);
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.shipnote {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
@ -125,16 +125,12 @@ $(".controlsOwnBoard").css("opacity", 1);
|
|||||||
|
|
||||||
function switchBoards() {
|
function switchBoards() {
|
||||||
if (postPrep) {
|
if (postPrep) {
|
||||||
if (ownBoardIsActive) { // Aktywna jest plansza użytkownika
|
if (ownBoardIsActive) { // Aktywna jest plansza przeciwnika
|
||||||
$("#secondaryBoard").removeClass("secondary");
|
$("#secondaryBoard").removeClass("secondary");
|
||||||
$("#board").addClass("secondary");
|
$("#board").addClass("secondary");
|
||||||
$(".ownBoardInfo").css("opacity", 0);
|
} else { // Aktywna jest plansza gracza
|
||||||
$(".controlsOwnBoard").css("opacity", 0.3);
|
|
||||||
} else { // Aktywna jest plansza przeciwnika
|
|
||||||
$("#board").removeClass("secondary");
|
$("#board").removeClass("secondary");
|
||||||
$("#secondaryBoard").addClass("secondary");
|
$("#secondaryBoard").addClass("secondary");
|
||||||
$(".ownBoardInfo").css("opacity", 1);
|
|
||||||
$(".controlsOwnBoard").css("opacity", 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ownBoardIsActive = !ownBoardIsActive;
|
ownBoardIsActive = !ownBoardIsActive;
|
||||||
|
@ -5,6 +5,11 @@ var timerDestination = null;
|
|||||||
var gamePhase = 'pregame';
|
var gamePhase = 'pregame';
|
||||||
var occupiedFields = [];
|
var occupiedFields = [];
|
||||||
|
|
||||||
|
var shipsSunk = [0, 0, 0, 0];
|
||||||
|
|
||||||
|
var hits = 0;
|
||||||
|
var misses = 0;
|
||||||
|
|
||||||
var lastTimeClick = 0;
|
var lastTimeClick = 0;
|
||||||
|
|
||||||
if ($(window).width() <= 820) {
|
if ($(window).width() <= 820) {
|
||||||
@ -48,8 +53,6 @@ $('#board .field').on('click', function () {
|
|||||||
if (new Date().getTime() / 1000 - lastTimeClick > 0.3) {
|
if (new Date().getTime() / 1000 - lastTimeClick > 0.3) {
|
||||||
if ($(window).width() > 820) {
|
if ($(window).width() > 820) {
|
||||||
socket.emit("place ship", selectedShip, $(this).data('pos-x'), $(this).data('pos-y'), shipRotation);
|
socket.emit("place ship", selectedShip, $(this).data('pos-x'), $(this).data('pos-y'), shipRotation);
|
||||||
|
|
||||||
navigator.vibrate(200);
|
|
||||||
lastTimeClick = new Date().getTime() / 1000;
|
lastTimeClick = new Date().getTime() / 1000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,8 +69,6 @@ $('#secondaryBoard .field').on('click', function () {
|
|||||||
if (new Date().getTime() / 1000 - lastTimeClick > 0.3) {
|
if (new Date().getTime() / 1000 - lastTimeClick > 0.3) {
|
||||||
if ($(window).width() > 820) {
|
if ($(window).width() > 820) {
|
||||||
socket.emit("shoot", $(this).data('pos-x'), $(this).data('pos-y'));
|
socket.emit("shoot", $(this).data('pos-x'), $(this).data('pos-y'));
|
||||||
|
|
||||||
navigator.vibrate(200);
|
|
||||||
lastTimeClick = new Date().getTime() / 1000;
|
lastTimeClick = new Date().getTime() / 1000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,6 +144,8 @@ socket.on("shot hit", (victimIdx, posX, posY) => {
|
|||||||
bsc.setField(posX, posY, "hit");
|
bsc.setField(posX, posY, "hit");
|
||||||
} else {
|
} else {
|
||||||
bsc.setFieldEnemy(posX, posY, "hit");
|
bsc.setFieldEnemy(posX, posY, "hit");
|
||||||
|
hits++;
|
||||||
|
updateAccuracy(getAccuracy());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -151,6 +154,8 @@ socket.on("shot missed", (victimIdx, posX, posY) => {
|
|||||||
bsc.setField(posX, posY, "miss");
|
bsc.setField(posX, posY, "miss");
|
||||||
} else {
|
} else {
|
||||||
bsc.setFieldEnemy(posX, posY, "miss");
|
bsc.setFieldEnemy(posX, posY, "miss");
|
||||||
|
misses++;
|
||||||
|
updateAccuracy(getAccuracy());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -186,6 +191,9 @@ socket.on("ship sunk", (victimIdx, ship) => {
|
|||||||
bsc.setFieldEnemy(ship.posX + multips[0] * i, ship.posY + multips[1] * i, "sunken");
|
bsc.setFieldEnemy(ship.posX + multips[0] * i, ship.posY + multips[1] * i, "sunken");
|
||||||
}, i * 150);
|
}, i * 150);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shipsSunk[ship.type]++;
|
||||||
|
updateShipsSunk();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -246,6 +254,17 @@ socket.on('turn update', (turnData) => {
|
|||||||
$("#whosTurn").html(window.locale["Preparation phase"]);
|
$("#whosTurn").html(window.locale["Preparation phase"]);
|
||||||
$(".boardSwitch").css("opacity", 0.3);
|
$(".boardSwitch").css("opacity", 0.3);
|
||||||
} else {
|
} else {
|
||||||
|
if (!postPrep) {
|
||||||
|
$(".controlsOwnBoard").css("opacity", 0.3);
|
||||||
|
|
||||||
|
$(".ownBoardInfo").addClass("changing");
|
||||||
|
setTimeout(() => {
|
||||||
|
$(".ownBoardInfo").html($(".lateBoardInfo").html());
|
||||||
|
|
||||||
|
$(".ownBoardInfo").removeClass("changing");
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
postPrep = true;
|
postPrep = true;
|
||||||
myTurn = turnData.turn === playerIdx;
|
myTurn = turnData.turn === playerIdx;
|
||||||
turnData.turn === playerIdx ? $("#whosTurn").html(window.locale["Your turn"]) : $("#whosTurn").html(window.locale["Opponents turn"]);
|
turnData.turn === playerIdx ? $("#whosTurn").html(window.locale["Your turn"]) : $("#whosTurn").html(window.locale["Opponents turn"]);
|
||||||
@ -256,6 +275,71 @@ socket.on('turn update', (turnData) => {
|
|||||||
gamePhase = turnData.phase;
|
gamePhase = turnData.phase;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function updateLateInfo() {
|
||||||
|
if (postPrep) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentAccuracy = 0;
|
||||||
|
|
||||||
|
function updateAccuracy(val) {
|
||||||
|
var obj = $(".ownBoardInfo #accuracy").get(0);
|
||||||
|
|
||||||
|
const start = currentAccuracy !== null ? currentAccuracy : val;
|
||||||
|
|
||||||
|
const range = val - start;
|
||||||
|
var minTimer = 50;
|
||||||
|
var stepTime = Math.abs(Math.floor(1000 / range));
|
||||||
|
|
||||||
|
stepTime = Math.max(stepTime, minTimer);
|
||||||
|
|
||||||
|
var startTime = new Date().getTime();
|
||||||
|
var endTime = startTime + 1000;
|
||||||
|
var timer;
|
||||||
|
|
||||||
|
if (val < currentAccuracy) {
|
||||||
|
$(".ownBoardInfo #accuracy").addClass("animatingDown");
|
||||||
|
} else {
|
||||||
|
$(".ownBoardInfo #accuracy").addClass("animatingUp");
|
||||||
|
}
|
||||||
|
|
||||||
|
currentAccuracy = val;
|
||||||
|
|
||||||
|
const run = () => {
|
||||||
|
var now = new Date().getTime();
|
||||||
|
var remaining = Math.max((endTime - now) / 1000, 0);
|
||||||
|
var value = Math.round(val - (remaining * range));
|
||||||
|
obj.innerHTML = value + "%";
|
||||||
|
if (value == val) {
|
||||||
|
obj.innerHTML = Math.round(value) + "%";
|
||||||
|
$(".ownBoardInfo #accuracy").removeClass("animatingDown animatingUp");
|
||||||
|
|
||||||
|
clearInterval(timer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
timer = setInterval(run, stepTime);
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAccuracy() {
|
||||||
|
return hits / (misses + hits) * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateShipsSunk() {
|
||||||
|
$("#singlemasted").html(shipsSunk[0]);
|
||||||
|
$("#twomasted").html(shipsSunk[1]);
|
||||||
|
$("#threemasted").html(shipsSunk[2]);
|
||||||
|
$("#fourmasted").html(shipsSunk[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function readyUp() {
|
||||||
|
socket.emit("ready", () => {
|
||||||
|
$(".readyButton").css({ pointerEvents: 'none', opacity: 0.3 });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
socket.on('player left', () => {
|
socket.on('player left', () => {
|
||||||
window.location.replace("/");
|
window.location.replace("/");
|
||||||
});
|
});
|
241
test.js
Normal file
241
test.js
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
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) {
|
||||||
|
console.log(x, y);
|
||||||
|
// console.log(x + len)
|
||||||
|
// console.log(x + len >= grid.length)
|
||||||
|
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) {
|
||||||
|
// console.log(y + len)
|
||||||
|
// console.log(y + len >= grid.length)
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
hostId: "123456",
|
||||||
|
state: "action",
|
||||||
|
boards: [
|
||||||
|
{
|
||||||
|
ships: [
|
||||||
|
{ type: 3, posX: 3, posY: 4, rot: 0, hits: [false, false, false] },
|
||||||
|
],
|
||||||
|
shots: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ships: [],
|
||||||
|
shots: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
nextPlayer: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkHit(data, 1, 0, 0);
|
||||||
|
|
||||||
|
// console.log(validateShipPosition(type, posX, posY, rot));
|
||||||
|
|
||||||
|
let boardRender = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
var array = [];
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
array.push(false);
|
||||||
|
}
|
||||||
|
boardRender.push(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
data.boards[0].ships.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++) {
|
||||||
|
boardRender[ship.posX + multips[0] * i][ship.posY + multips[1] * i] = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// const rot = 0;
|
||||||
|
const type = 3;
|
||||||
|
|
||||||
|
// let multips;
|
||||||
|
|
||||||
|
// switch (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;
|
||||||
|
// }
|
||||||
|
|
||||||
|
boardRender = [
|
||||||
|
[
|
||||||
|
true, true, true,
|
||||||
|
true, true, true,
|
||||||
|
true, false, true,
|
||||||
|
true
|
||||||
|
],
|
||||||
|
[
|
||||||
|
true, true, true,
|
||||||
|
true, true, true,
|
||||||
|
true, false, true,
|
||||||
|
true
|
||||||
|
],
|
||||||
|
[
|
||||||
|
false, true, true,
|
||||||
|
true, true, true,
|
||||||
|
true, true, true,
|
||||||
|
true
|
||||||
|
],
|
||||||
|
[
|
||||||
|
false, true, true,
|
||||||
|
true, false, false,
|
||||||
|
true, true, true,
|
||||||
|
false
|
||||||
|
],
|
||||||
|
[
|
||||||
|
false, false, false,
|
||||||
|
true, true, true,
|
||||||
|
true, true, true,
|
||||||
|
false
|
||||||
|
],
|
||||||
|
[
|
||||||
|
false, false, false,
|
||||||
|
true, true, true,
|
||||||
|
true, true, false,
|
||||||
|
false
|
||||||
|
],
|
||||||
|
[
|
||||||
|
true, true, true,
|
||||||
|
true, true, true,
|
||||||
|
true, true, true,
|
||||||
|
true
|
||||||
|
],
|
||||||
|
[
|
||||||
|
true, true, true,
|
||||||
|
true, false, false,
|
||||||
|
false, true, true,
|
||||||
|
true
|
||||||
|
],
|
||||||
|
[
|
||||||
|
true, true, true,
|
||||||
|
true, true, true,
|
||||||
|
true, true, true,
|
||||||
|
true
|
||||||
|
],
|
||||||
|
[
|
||||||
|
false, false, false,
|
||||||
|
true, true, true,
|
||||||
|
true, false, false,
|
||||||
|
false
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
let search = findEmptyFields(boardRender, 4);
|
||||||
|
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`;
|
||||||
|
}
|
||||||
|
console.log(row);
|
||||||
|
}
|
||||||
|
console.log(search);
|
||||||
|
|
||||||
|
const rPos = search[Math.floor(Math.random() * search.length)];
|
||||||
|
|
||||||
|
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 i = 0; i <= type; i++) {
|
||||||
|
console.log(`boardRender[${rPos.posX + multips[0] * i}][${rPos.posY + multips[1] * i}]`)
|
||||||
|
boardRender[rPos.posX + multips[0] * i][rPos.posY + multips[1] * i] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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`;
|
||||||
|
}
|
||||||
|
console.log(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log();
|
||||||
|
// console.log(findAllRowsOfXTrueValues(matrix, 3, 1));
|
||||||
|
// console.log(findAllRowsOfXTrueValues(matrix, 3, 2));
|
@ -5,8 +5,8 @@ export class GameInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async timer(tId, time, callback) {
|
async timer(tId, time, callback) {
|
||||||
await this.redis.set(`timer:${tId}`, new Date().getTime() / 1000);
|
await this.redis.json.set(`timer:${tId}`, '$', { lastUpdate: new Date().getTime() / 1000, end: new Date().getTime() / 1000 + time });
|
||||||
let localLastUpdate = await this.redis.get(`timer:${tId}`);
|
let localLastUpdate = await this.redis.json.get(`timer:${tId}`, { path: ".lastUpdate" });
|
||||||
|
|
||||||
let timeout = setTimeout(callback, time * 1000);
|
let timeout = setTimeout(callback, time * 1000);
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ export class GameInfo {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let lastUpdate = await this.redis.get(`timer:${tId}`);
|
let lastUpdate = await this.redis.json.get(`timer:${tId}`, { path: ".lastUpdate" });
|
||||||
if (localLastUpdate != lastUpdate) {
|
if (localLastUpdate != lastUpdate) {
|
||||||
// timer has been reset
|
// timer has been reset
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
@ -27,9 +27,15 @@ export class GameInfo {
|
|||||||
}, 200);
|
}, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async timerLeft(tId) {
|
||||||
|
let end = await this.redis.json.get(`timer:${tId}`, { path: ".end" });
|
||||||
|
let left = end - new Date().getTime() / 1000;
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
async resetTimer(tId) {
|
async resetTimer(tId) {
|
||||||
let lastUpdate = await this.redis.get(`timer:${tId}`);
|
let lastUpdate = await this.redis.json.get(`timer:${tId}`, { path: ".end" });
|
||||||
await this.redis.set(`timer:${tId}`, -lastUpdate);
|
await this.redis.json.set(`timer:${tId}`, '.lastUpdate', -lastUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
async isPlayerInGame(socket) {
|
async isPlayerInGame(socket) {
|
||||||
@ -159,12 +165,16 @@ export class GameInfo {
|
|||||||
let availableShipsOfType = availableShips[i];
|
let availableShipsOfType = availableShips[i];
|
||||||
for (let j = 0; j < availableShipsOfType; j++) {
|
for (let j = 0; j < availableShipsOfType; j++) {
|
||||||
playerShips = (await this.redis.json.get(key, { path: `.boards[${playerIdx}].ships` }));
|
playerShips = (await this.redis.json.get(key, { path: `.boards[${playerIdx}].ships` }));
|
||||||
|
|
||||||
|
let print = "";
|
||||||
for (let y = 0; y < 10; y++) {
|
for (let y = 0; y < 10; y++) {
|
||||||
let row = "";
|
let row = "";
|
||||||
for (let x = 0; x < 10; x++) {
|
for (let x = 0; x < 10; x++) {
|
||||||
row += `${boardRender[x][y] ? "\x1b[31m" : "\x1b[32m"}${boardRender[x][y]}\x1b[0m\t`;
|
row += `${boardRender[x][y] ? "\x1b[31m" : "\x1b[32m"}${boardRender[x][y]}\x1b[0m\t`;
|
||||||
}
|
}
|
||||||
|
print += row+"\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
const search = findEmptyFields(boardRender, i + 1);
|
const search = findEmptyFields(boardRender, i + 1);
|
||||||
|
|
||||||
const rPos = search[Math.floor(Math.random() * search.length)];
|
const rPos = search[Math.floor(Math.random() * search.length)];
|
||||||
@ -275,6 +285,16 @@ export class GameInfo {
|
|||||||
await this.redis.json.set(key, `.boards[${enemyIdx}]`, playerBoard);
|
await this.redis.json.set(key, `.boards[${enemyIdx}]`, playerBoard);
|
||||||
return { status: 1, ship: shotShip };
|
return { status: 1, ship: shotShip };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async setReady(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;
|
||||||
|
|
||||||
|
await this.redis.json.set(key, `.ready[${playerIdx}]`, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isPlayerInRoom(socket) {
|
export function isPlayerInRoom(socket) {
|
||||||
@ -423,16 +443,18 @@ export function checkTurn(data, playerId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function findEmptyFields(grid, len) {
|
function findEmptyFields(grid, len) {
|
||||||
const rowPlacements = [];
|
const shipPlacements = [];
|
||||||
|
|
||||||
// Helper function to check if a row can be placed horizontally at a given position
|
// Helper function to check if a row can be placed horizontally at a given position
|
||||||
function canPlaceHorizontally(x, y) {
|
function canPlaceHorizontally(x, y) {
|
||||||
if (x + len >= grid[0].length) {
|
// Check if the ship exceeds the board boundaries horizontally
|
||||||
return false; // Ship exceeds board boundaries
|
if (x + len > grid.length) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
for (let i = x; i <= x + len; i++) {
|
// Check if any field within the ship's length is already occupied
|
||||||
|
for (let i = x; i < x + len; i++) {
|
||||||
if (grid[i][y]) {
|
if (grid[i][y]) {
|
||||||
return false; // One of ship's fields is already occupied
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -440,32 +462,35 @@ function findEmptyFields(grid, len) {
|
|||||||
|
|
||||||
// Helper function to check if a row can be placed vertically at a given position
|
// Helper function to check if a row can be placed vertically at a given position
|
||||||
function canPlaceVertically(x, y) {
|
function canPlaceVertically(x, y) {
|
||||||
if (y + len >= grid.length) {
|
// Check if the ship exceeds the board boundaries vertically
|
||||||
return false; // Ship exceeds board boundaries
|
if (y + len > grid[0].length) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
for (let i = y; i <= y + len; i++) {
|
// Check if any field within the ship's length is already occupied
|
||||||
|
for (let i = y; i < y + len; i++) {
|
||||||
if (grid[x][i]) {
|
if (grid[x][i]) {
|
||||||
return false; // One of ship's fields is already occupied
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Loop through the grid to find empty places
|
||||||
for (let i = 0; i < grid.length; i++) {
|
for (let i = 0; i < grid.length; i++) {
|
||||||
for (let j = 0; j < grid[0].length; j++) {
|
for (let j = 0; j < grid[0].length; j++) {
|
||||||
if (grid[j][i] === false) {
|
if (!grid[i][j]) { // Check if the current position is empty
|
||||||
if (canPlaceHorizontally(j, i)) {
|
if (canPlaceHorizontally(i, j)) {
|
||||||
rowPlacements.push({ posX: j, posY: i, rot: 0 });
|
shipPlacements.push({ posX: i, posY: j, rot: 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canPlaceVertically(j, i)) {
|
if (canPlaceVertically(i, j)) {
|
||||||
rowPlacements.push({ posX: j, posY: i, rot: 1 });
|
shipPlacements.push({ posX: i, posY: j, rot: 1 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rowPlacements;
|
return shipPlacements;
|
||||||
}
|
}
|
||||||
|
|
||||||
function clamp(n, min, max) {
|
function clamp(n, min, max) {
|
||||||
|
@ -9,6 +9,8 @@ export class Lang {
|
|||||||
constructor(langs) {
|
constructor(langs) {
|
||||||
const languagesPath = path.join(__dirname, '../lang');
|
const languagesPath = path.join(__dirname, '../lang');
|
||||||
this.allText = null;
|
this.allText = null;
|
||||||
|
|
||||||
|
if (langs && langs.length > 0) {
|
||||||
for (let i = 0; i < langs.length; i++) {
|
for (let i = 0; i < langs.length; i++) {
|
||||||
const lang = langs[i];
|
const lang = langs[i];
|
||||||
|
|
||||||
@ -22,6 +24,7 @@ export class Lang {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.allText = JSON.parse(fs.readFileSync(path.join(languagesPath, 'en.json'), 'utf8'));
|
this.allText = JSON.parse(fs.readFileSync(path.join(languagesPath, 'en.json'), 'utf8'));
|
||||||
this.lang = 'en';
|
this.lang = 'en';
|
||||||
|
@ -17,6 +17,17 @@
|
|||||||
<h2 class="dynamic" id="selectedShip">{{ t 'board.Single-masted' }}</h2>
|
<h2 class="dynamic" id="selectedShip">{{ t 'board.Single-masted' }}</h2>
|
||||||
<h3>{{ t 'board.Available:' }} <span class="dynamic danger" id="shipsLeft">-</span></h3>
|
<h3>{{ t 'board.Available:' }} <span class="dynamic danger" id="shipsLeft">-</span></h3>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="lateBoardInfo">
|
||||||
|
<h3>{{ t 'board.Sunk ships' }}</h3>
|
||||||
|
<p>
|
||||||
|
{{ t 'board.Single-mastedPlu' }} <span class="dynamic shipnote" id="singlemasted">0</span><br>
|
||||||
|
{{ t 'board.Two-mastedPlu' }} <span class="dynamic shipnote" id="twomasted">0</span><br>
|
||||||
|
{{ t 'board.Three-mastedPlu' }} <span class="dynamic shipnote" id="threemasted">0</span><br>
|
||||||
|
{{ t 'board.Four-mastedPlu' }} <span class="dynamic shipnote" id="fourmasted">0</span><br>
|
||||||
|
</p>
|
||||||
|
<h3>{{ t 'board.Your accuracy' }}</h3>
|
||||||
|
<h2 id="accuracy">-</h2>
|
||||||
|
</div>
|
||||||
<span class="break"></span>
|
<span class="break"></span>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<h2>{{ t 'board.Controls' }}</h2>
|
<h2>{{ t 'board.Controls' }}</h2>
|
||||||
@ -29,6 +40,7 @@
|
|||||||
<button class="boardSwitch" onclick="switchBoards()">{{ t 'board.Change boards' }}</button>
|
<button class="boardSwitch" onclick="switchBoards()">{{ t 'board.Change boards' }}</button>
|
||||||
</div>
|
</div>
|
||||||
<span class="break"></span>
|
<span class="break"></span>
|
||||||
|
<button class="readyButton" onclick="readyUp()">{{ t 'board.Ready up' }}</button>
|
||||||
<h3><span class="dynamic" id="whosTurn"></span></h3>
|
<h3><span class="dynamic" id="whosTurn"></span></h3>
|
||||||
<h2 class="important" id="timer">∞</h2>
|
<h2 class="important" id="timer">∞</h2>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user