diff options
| -rw-r--r-- | backend/ts/api/saveGameBoard.ts | 13 | ||||
| -rw-r--r-- | backend/ts/gameBoard.ts | 80 | ||||
| -rw-r--r-- | backend/ts/index.ts | 9 | ||||
| -rw-r--r-- | backend/ts/startGame.ts | 1 | ||||
| -rw-r--r-- | frontend/ts/gameBoard.ts | 81 | ||||
| -rw-r--r-- | frontend/ts/gameTable.ts | 22 | ||||
| -rw-r--r-- | frontend/ts/ghost.ts | 87 | ||||
| -rw-r--r-- | frontend/ts/logic.ts | 118 | ||||
| -rw-r--r-- | frontend/ts/startGame.ts | 345 | ||||
| -rw-r--r-- | frontend/ts/timer.ts | 51 | ||||
| -rw-r--r-- | helpers/helpers.ts | 7 | ||||
| -rw-r--r-- | helpers/helpersBack.ts | 2 | ||||
| -rw-r--r-- | public/css/fia.css | 6 |
13 files changed, 489 insertions, 333 deletions
diff --git a/backend/ts/api/saveGameBoard.ts b/backend/ts/api/saveGameBoard.ts index 551c185..da31bdf 100644 --- a/backend/ts/api/saveGameBoard.ts +++ b/backend/ts/api/saveGameBoard.ts @@ -1,16 +1,17 @@ import { Request, Response } from "express"; -import { API_RES, makeQuery } from "../../../helpers/helpersBack"; +import { API_RES, makeQuery, nextTurnEndsAt } from "../../../helpers/helpersBack"; export default async function saveGameBoard(req: Request, res: Response) { - if(req.session === undefined || req.body.gameBoard === undefined) { + if (req.session === undefined || req.body.gameBoard === undefined) { res.status(400); res.send(API_RES.failure); return; } - await makeQuery("UPDATE `fia` SET `gameBoard` = ? WHERE `id` = ? ", [ - req.body.gameBoard, req.session.gid - ]); + let query = "UPDATE `fia` SET `currentPlayer` = IF(`currentPlayer` + 1 = `playersCount`, 0, `currentPlayer` + 1), " + + "`gameBoard` = ?, `timeTillTurnEnd` = ? WHERE `id` = ?" + await makeQuery(query, [req.body.gameBoard, nextTurnEndsAt(), req.session.gid]); res.send(API_RES.success); -}
\ No newline at end of file +} +//UPDATE `fia` SET `currentPlayer` = IF( `currentPlayer` + 1 = `playersCount`, 0, `currentPlayer` + 1 ) WHERE `id` = 169
\ No newline at end of file diff --git a/backend/ts/gameBoard.ts b/backend/ts/gameBoard.ts index 89a8902..314c874 100644 --- a/backend/ts/gameBoard.ts +++ b/backend/ts/gameBoard.ts @@ -1,46 +1,46 @@ import { Color, GameBoard } from '../../helpers/helpersBack'; export const gameBoard: GameBoard = { map: [ - { y: 0, x: 4, chequers: [], start: Color.red }, - { y: 1, x: 4, chequers: [], start: -1 }, - { y: 2, x: 4, chequers: [], start: -1 }, - { y: 3, x: 4, chequers: [], start: -1 }, - { y: 4, x: 4, chequers: [], start: -1 }, - { y: 4, x: 3, chequers: [], start: -1 }, - { y: 4, x: 2, chequers: [], start: -1 }, - { y: 4, x: 1, chequers: [], start: -1 }, - { y: 4, x: 0, chequers: [], start: -1 }, - { y: 5, x: 0, chequers: [], start: -1 }, - { y: 6, x: 0, chequers: [], start: Color.blue }, - { y: 6, x: 1, chequers: [], start: -1 }, - { y: 6, x: 2, chequers: [], start: -1 }, - { y: 6, x: 3, chequers: [], start: -1 }, - { y: 6, x: 4, chequers: [], start: -1 }, - { y: 7, x: 4, chequers: [], start: -1 }, - { y: 8, x: 4, chequers: [], start: -1 }, - { y: 9, x: 4, chequers: [], start: -1 }, - { y: 10, x: 4, chequers: [], start: -1 }, - { y: 10, x: 5, chequers: [], start: -1 }, - { y: 10, x: 6, chequers: [], start: Color.green }, - { y: 9, x: 6, chequers: [], start: -1 }, - { y: 8, x: 6, chequers: [], start: -1 }, - { y: 7, x: 6, chequers: [], start: -1 }, - { y: 6, x: 6, chequers: [], start: -1 }, - { y: 6, x: 7, chequers: [], start: -1 }, - { y: 6, x: 8, chequers: [], start: -1 }, - { y: 6, x: 9, chequers: [], start: -1 }, - { y: 6, x: 10, chequers: [], start: -1 }, - { y: 5, x: 10, chequers: [], start: -1 }, - { y: 4, x: 10, chequers: [], start: Color.yellow }, - { y: 4, x: 9, chequers: [], start: -1 }, - { y: 4, x: 8, chequers: [], start: -1 }, - { y: 4, x: 7, chequers: [], start: -1 }, - { y: 4, x: 6, chequers: [], start: -1 }, - { y: 3, x: 6, chequers: [], start: -1 }, - { y: 2, x: 6, chequers: [], start: -1 }, - { y: 1, x: 6, chequers: [], start: -1 }, - { y: 0, x: 6, chequers: [], start: -1 }, - { y: 0, x: 5, chequers: [], start: -1 }, + { x: 0, y: 4, chequers: [], start: Color.red }, + { x: 1, y: 4, chequers: [], start: -1 }, + { x: 2, y: 4, chequers: [], start: -1 }, + { x: 3, y: 4, chequers: [], start: -1 }, + { x: 4, y: 4, chequers: [], start: -1 }, + { x: 4, y: 3, chequers: [], start: -1 }, + { x: 4, y: 2, chequers: [], start: -1 }, + { x: 4, y: 1, chequers: [], start: -1 }, + { x: 4, y: 0, chequers: [], start: -1 }, + { x: 5, y: 0, chequers: [], start: -1 }, + { x: 6, y: 0, chequers: [], start: Color.blue }, + { x: 6, y: 1, chequers: [], start: -1 }, + { x: 6, y: 2, chequers: [], start: -1 }, + { x: 6, y: 3, chequers: [], start: -1 }, + { x: 6, y: 4, chequers: [], start: -1 }, + { x: 7, y: 4, chequers: [], start: -1 }, + { x: 8, y: 4, chequers: [], start: -1 }, + { x: 9, y: 4, chequers: [], start: -1 }, + { x: 10, y: 4, chequers: [], start: -1 }, + { x: 10, y: 5, chequers: [], start: -1 }, + { x: 10, y: 6, chequers: [], start: Color.green }, + { x: 9, y: 6, chequers: [], start: -1 }, + { x: 8, y: 6, chequers: [], start: -1 }, + { x: 7, y: 6, chequers: [], start: -1 }, + { x: 6, y: 6, chequers: [], start: -1 }, + { x: 6, y: 7, chequers: [], start: -1 }, + { x: 6, y: 8, chequers: [], start: -1 }, + { x: 6, y: 9, chequers: [], start: -1 }, + { x: 6, y: 10, chequers: [], start: -1 }, + { x: 5, y: 10, chequers: [], start: -1 }, + { x: 4, y: 10, chequers: [], start: Color.yellow }, + { x: 4, y: 9, chequers: [], start: -1 }, + { x: 4, y: 8, chequers: [], start: -1 }, + { x: 4, y: 7, chequers: [], start: -1 }, + { x: 4, y: 6, chequers: [], start: -1 }, + { x: 3, y: 6, chequers: [], start: -1 }, + { x: 2, y: 6, chequers: [], start: -1 }, + { x: 1, y: 6, chequers: [], start: -1 }, + { x: 0, y: 6, chequers: [], start: -1 }, + { x: 0, y: 5, chequers: [], start: -1 }, ], // @ts-ignore bases: { diff --git a/backend/ts/index.ts b/backend/ts/index.ts index e4ec5ee..32ac644 100644 --- a/backend/ts/index.ts +++ b/backend/ts/index.ts @@ -17,7 +17,14 @@ const PORT = 8000; if (!process.env.SESSION_KEY) throw Error("SESSION_KEY is undefined"); -app.use(session({ secret: process.env.SESSION_KEY, cookie: { maxAge: 60000 } })); +app.use(session({ + secret: process.env.SESSION_KEY, + saveUninitialized: true, + resave: true, + cookie: { + expires: new Date(Date.now() + 3600000), + } +})); app.use(express.json()); app.use("/", express.static("./public")); diff --git a/backend/ts/startGame.ts b/backend/ts/startGame.ts index eb19bc0..c4d7131 100644 --- a/backend/ts/startGame.ts +++ b/backend/ts/startGame.ts @@ -6,6 +6,7 @@ export default async function startGame(gid: number) { (await makeQuery("SELECT `gameBoard`, `data` FROM `fia` WHERE `id` = ?", [gid]))[0]; for (let player of dbRes.data) { + player.ready = true; for(let square of dbRes.gameBoard.bases[player.color as keyof HomesOrBases]) { square.chequer = player.color; } diff --git a/frontend/ts/gameBoard.ts b/frontend/ts/gameBoard.ts new file mode 100644 index 0000000..da5e8d6 --- /dev/null +++ b/frontend/ts/gameBoard.ts @@ -0,0 +1,81 @@ +import { Coordinates, GameBoard, HomesOrBases, tColors } from "../../helpers/helpersBack"; +import gameTable from "./gameTable.js"; +import StartGame from "./startGame.js"; + +export default class gameBoardClass { + static drawGameBoard(gameBoard: GameBoard, drawChequer: Function): void { + gameBoardClass.removeGameBoard(gameBoard); + for (let square of gameBoard.map) { + if (square.chequers.length !== 0) { + for (let chequer of square.chequers) + drawChequer({ x: square.x, y: square.y }, chequer.color, chequer); + } + } + for (let baseOfColor in gameBoard.bases) { + for (let square of gameBoard.bases[baseOfColor as unknown as keyof HomesOrBases]) { + if (square.chequer > -1) + drawChequer({ x: square.x, y: square.y }, square.chequer, square); + } + } + for (let baseOfColor in gameBoard.homes) { + for (let square of gameBoard.homes[baseOfColor as unknown as keyof HomesOrBases]) { + if (square.chequer > -1) + drawChequer({ x: square.x, y: square.y }, square.chequer, square); + } + } + } + static removeGameBoard(gameBoard: GameBoard): void { + for (let square of gameBoard.map) { + gameBoardClass.removeChequer({ x: square.x, y: square.y }, true); + } + for (let baseOfColor in gameBoard.bases) { + for (let square of gameBoard.bases[baseOfColor as unknown as keyof HomesOrBases]) { + gameBoardClass.removeChequer({ x: square.x, y: square.y }, true); + } + } + for (let baseOfColor in gameBoard.homes) { + for (let square of gameBoard.homes[baseOfColor as unknown as keyof HomesOrBases]) { + gameBoardClass.removeChequer({ x: square.x, y: square.y }, true); + } + } + } + static removeChequer(coords: Coordinates, all: boolean) { + let td = gameTable.getTd(coords); + gameBoardClass.hideChequer(coords); + td.onmouseenter = () => null; + td.onmouseleave = () => null; + td.onclick = () => null; + } + + static showChequer(coords: Coordinates, color: tColors): void { + let td = gameTable.getTd(coords); + if (td.dataset.count === undefined) + throw new Error("td.dataset.count is undefined!!!") + + if (td.dataset.count === '0') { + td.classList.add("chequer-" + StartGame.colors[color]); + td.dataset.count = '1'; + td.innerHTML = ''; + } else { + td.dataset.count = (parseInt(td.dataset.count) + 1).toString(); + td.innerHTML = 'x' + td.dataset.count; + } + } + static hideChequer(coords: Coordinates, all = false) { + let td = gameTable.getTd(coords); + + if (td.dataset.count === '0') + return; + if (td.dataset.count === undefined) + throw new Error("td.dataset.count is undefined!!!") + + if (td.dataset.count === '1' || all === true) { + td.className = td.className.replace(/chequer-.*/, ''); + td.dataset.count = '0'; + td.innerHTML = ''; + } else { + td.dataset.count = (parseInt(td.dataset.count) - 1).toString(); + td.innerHTML = 'x' + td.dataset.count; + } + } +}
\ No newline at end of file diff --git a/frontend/ts/gameTable.ts b/frontend/ts/gameTable.ts new file mode 100644 index 0000000..c95ddb2 --- /dev/null +++ b/frontend/ts/gameTable.ts @@ -0,0 +1,22 @@ +import { Coordinates } from "../../helpers/helpersBack"; + +export default class gameTable { + static numberOfSquaresOnGameBoard = 11; + static gameTable: HTMLTableElement; + + static drawGameTable(): void { + for (let i = 0; i < gameTable.numberOfSquaresOnGameBoard; i++) { + let tr = document.createElement("tr"); + for (let j = 0; j < gameTable.numberOfSquaresOnGameBoard; j++) { + let td = document.createElement("td"); + td.classList.add("chequer"); + td.dataset.count = '0'; + tr.appendChild(td); + } + gameTable.gameTable.appendChild(tr); + } + } + static getTd(coords: Coordinates): HTMLElement { + return gameTable.gameTable.children[coords.y].children[coords.x] as HTMLElement; + } +}
\ No newline at end of file diff --git a/frontend/ts/ghost.ts b/frontend/ts/ghost.ts new file mode 100644 index 0000000..e7b4cb0 --- /dev/null +++ b/frontend/ts/ghost.ts @@ -0,0 +1,87 @@ +import { Chequer, GameBoard, HoBSquare, HomesOrBases, Square, tColors } from "../../helpers/helpersBack"; +import gameBoardClass from "./gameBoard.js"; +import gameTable from "./gameTable.js"; + +export default class ghost { + static ghostsTds: Array<{ td: HTMLElement, class: string }> = []; + static interval: any; + static hide = true; + static showGhost(chequer: Chequer | HoBSquare, color: tColors) { + if (chequer.ghost === undefined || chequer.ghost.coords === undefined) { + chequer.ghost?.coords === undefined ? console.log("showShost::chequer.ghost.coords === undefined", chequer.ghost?.coords === undefined) : ''; + return; + } + gameBoardClass.showChequer(chequer.ghost.coords, color) + } + static hideGhost(chequer: Chequer | HoBSquare): void { + if (chequer.ghost === undefined || chequer.ghost.coords === undefined) { + chequer.ghost?.coords === undefined ? console.log("hideGhost::chequer.ghost.coords === undefined", chequer.ghost?.coords === undefined) : ''; + return; + } + gameBoardClass.hideChequer(chequer.ghost.coords); + } + static removeGhosts(gameBoard: GameBoard, color: tColors): void { + for (let square of gameBoard.map) { + for (let chequer of square.chequers) { + chequer.ghost = undefined; + } + } + for (let chequer of gameBoard.bases[color as keyof HomesOrBases]) { + chequer.ghost = undefined; + } + for (let chequer of gameBoard.homes[color as keyof HomesOrBases]) { + chequer.ghost = undefined; + } + } + static anyGhosts(gameBoard: GameBoard, color: tColors): boolean { + for (let square of gameBoard.map) { + for (let chequer of square.chequers) { + if (chequer.ghost !== undefined) + return true; + } + } + for (let chequer of gameBoard.bases[color as keyof HomesOrBases]) { + if (chequer.ghost !== undefined) + return true; + } + for (let chequer of gameBoard.homes[color as keyof HomesOrBases]) { + if (chequer.ghost !== undefined) + return true; + } + return false; + } + static allBlink(gameBoard: GameBoard, color: tColors) { + for (let square of gameBoard.map) { + if (square.chequers.some(el => el.ghost !== undefined)) + ghost.blink(square); + } + for (let chequer of gameBoard.bases[color as keyof HomesOrBases]) { + if (chequer.ghost !== undefined) + ghost.blink(chequer); + } + for (let chequer of gameBoard.homes[color as keyof HomesOrBases]) { + if (chequer.ghost !== undefined) + ghost.blink(chequer); + } + } + static blink(chequer: Square | HoBSquare) { + if (ghost.interval === undefined) + ghost.interval = setInterval(ghost.blinking, 1000); + let td = gameTable.getTd({ x: chequer.x, y: chequer.y }); + ghost.ghostsTds.push({ td, class: td.className }); + } + static blinking() { + for (let td of ghost.ghostsTds) { + td.td.className = ghost.hide === true ? '' : td.class; + } + ghost.hide = !ghost.hide; + } + static allStopBlink() { + clearInterval(ghost.interval); + ghost.hide = true; + for (let td of ghost.ghostsTds) { + td.td.className = td.class; + } + ghost.ghostsTds = []; + } +}
\ No newline at end of file diff --git a/frontend/ts/logic.ts b/frontend/ts/logic.ts new file mode 100644 index 0000000..b677307 --- /dev/null +++ b/frontend/ts/logic.ts @@ -0,0 +1,118 @@ +import { Coordinates, GameBoard, HomesOrBases, Square, tColors } from "../../helpers/helpersBack"; + +export default class Logic { + static moveFromBase(gameBoard: GameBoard, color: tColors,) { + let start: Square, i: number; + + gameBoard.map.forEach((square, j) => { + if (square.start === color) { + start = square; + i = j; + } + }) + + gameBoard.bases[color as keyof HomesOrBases].forEach((chequer, j) => { + if (chequer.chequer > -1) { + chequer.ghost = { + where: { + from: "base", oldIndex: j, + to: "map", newIndex: i + }, + color: color, + coords: { x: start.x, y: start.y } + }; + } + }) + + return gameBoard; + } + static moveInMap(gameBoard: GameBoard, color: tColors, number: number) { + gameBoard.map.forEach((square, i) => { + if (square.chequers.length > 0 && square.chequers[0].color === color) { + + for (let chequer of square.chequers) { + let x: number | undefined, y: number | undefined, coords: Coordinates | undefined, inMap: boolean, + homeIndex: number | undefined, befStart: number | undefined; + + gameBoard.map.forEach((square, i) => { + if (square.start === color) + befStart = i - 1; + }); + if (befStart === undefined) + throw new Error("before start doesnt exist"); + + let range = (start: number, end: number) => Array.from(Array(end + 1).keys()).slice(start); + // if(i >= befStart && i + number <= befStart) { + if (range(i, i + number).includes(befStart)) { + // homeIndex = gameBoard.map.length - i - 1 - number - 1; + homeIndex = number - befStart + i; + inMap = false; + + if (homeIndex < gameBoard.homes[0].length) { + x = gameBoard.homes[color as keyof HomesOrBases][homeIndex].x; + y = gameBoard.homes[color as keyof HomesOrBases][homeIndex].y; + } + else { + x = y = undefined; + } + } else { + if(i + number >= gameBoard.map.length) + number += i - gameBoard.map.length - 1 - number; //* -$number 'cause adding $number on 62 && 63 + // i += number - gameBoard.map.length - 1 - number; //* -$number 'cause adding $number on 62 && 63 + console.log("newIndex: ", i + number) + x = gameBoard.map[i + number].x; + y = gameBoard.map[i + number].y; + inMap = true; + } + + if (x === undefined || y === undefined) + coords = undefined; + else + coords = { x, y }; + + chequer.ghost = { + where: { + from: "map", oldIndex: i, + to: (inMap === true ? "map" : "home"), newIndex: homeIndex || i + number + }, + color: color, + coords, + } + } + } + }) + + return gameBoard; + } + static moveInHome(gameBoard: GameBoard, color: tColors, number: number) { + let home = gameBoard.homes[color as keyof HomesOrBases]; + + home.forEach((chequer, i) => { + if (chequer.chequer > -1) { + let x: number | undefined, y: number | undefined, coords: Coordinates | undefined; + if (home[i + number] !== undefined) { + x = home[i + number].x; + y = home[i + number].y; + } else { + x = y = undefined; + } + + if (x === undefined || y === undefined) + coords = undefined; + else + coords = { x, y }; + + chequer.ghost = { + where: { + from: "home", oldIndex: i, + to: "home", newIndex: i + number + }, + color: color, + coords, + }; + } + }); + + return gameBoard; + } +}
\ No newline at end of file diff --git a/frontend/ts/startGame.ts b/frontend/ts/startGame.ts index 71a9abf..0afbb7d 100644 --- a/frontend/ts/startGame.ts +++ b/frontend/ts/startGame.ts @@ -2,27 +2,30 @@ import { Data, Coordinates, tColors, HomesOrBases, Square, HoBSquare, Ghost, mFe import Helpers from "../../helpers/helpers.js"; import { Chequer, GameBoard } from "../../helpers/helpersBack.js"; import Timer from "./timer.js"; +import Logic from "./logic.js"; +import gameTable from "./gameTable.js"; +import ghost from "./ghost.js"; +import gameBoardClass from "./gameBoard.js"; export default class StartGame { bgColors = ["primary", "danger", "success", "warning"]; - colors = ["blue", "red", "green", "yellow"]; + static colors = ["blue", "red", "green", "yellow"]; + colors = StartGame.colors; radius = 20; - numberOfSquaresOnGameBoard = 11; startInterval = () => { this.getData(); this.interval = setInterval(() => this.getData(), 2000); } uid!: string; color!: tColors; data!: Data; - timeTillTurnEnd!: number; gameBoard!: GameBoard; index!: number; oldIndex!: number; interval!: any; timer!: Timer; + gameWasStopped!: boolean; - btnStateToggle!: HTMLInputElement; - gameTable!: HTMLTableElement; + inpStateToggle!: HTMLInputElement; btnRollDice!: HTMLButtonElement; divDice!: HTMLDivElement; @@ -42,18 +45,17 @@ export default class StartGame { this.index = data.data.filter(el => el.id === this.uid)[0].index; this.color = data.data.filter(el => el.id === this.uid)[0].color; - this.setOpponents(data.data, true); - - this.gameTable = document.getElementsByTagName("table")[1]; - this.btnStateToggle = document.getElementsByTagName("input")[0]; + this.inpStateToggle = document.getElementsByTagName("input")[0]; this.btnRollDice = document.getElementsByTagName("button")[0]; this.divDice = document.getElementById("dice") as HTMLDivElement; + gameTable.gameTable = document.getElementsByTagName("table")[1]; this.timer = new Timer(); - this.btnStateToggle.onclick = this.readyStateToggle; + this.inpStateToggle.onclick = this.readyStateToggle; this.btnRollDice.onclick = this.rollDice; - this.drawGameTable(); + this.setOpponents(data.data, true); + gameTable.drawGameTable(); this.startInterval(); } @@ -65,10 +67,10 @@ export default class StartGame { for (let player of data) { tds[i].className = tds[i].className.replace(/\bbg-.*\b/, ''); - if (player.ready === true) { + if (player.ready === true || this.gameStarted === true) { tds[i].classList.add("bg-" + this.bgColors[player.color]); if (this.uid === player.id) - document.getElementsByTagName("input")[0].checked = true; + this.inpStateToggle.checked = true; } else tds[i].classList.add("bg-secondary"); @@ -86,12 +88,12 @@ export default class StartGame { readyStateToggle = async (e: MouseEvent): Promise<void> => { if (this.toggleStop) { - this.btnStateToggle.checked = true; + this.inpStateToggle.checked = true; return; } this.toggleStop = true; let res = await Helpers.mFetch("/readyStateToggle", { - state: this.btnStateToggle.checked + state: this.inpStateToggle.checked }); if (res.started === true) this.toggleStop = true; @@ -104,6 +106,7 @@ export default class StartGame { rollDice = async (e: MouseEvent): Promise<void> => { let number = Helpers.getRandomInt(1, 7); + this.diceHash; this.divDice.classList.add(`dice-${number}`); this.btnRollDice.style.display = "none"; this.calcMoves(number); @@ -111,131 +114,20 @@ export default class StartGame { calcMoves(number: number) { if ([1, 6].includes(number)) - this.moveFromBase(); + Logic.moveFromBase(this.gameBoard, this.color); - this.moveInMap(number); - this.moveInHome(number); + Logic.moveInMap(this.gameBoard, this.color, number); + Logic.moveInHome(this.gameBoard, this.color, number); - this.drawGameBoard(); - console.log("checking for ghosts"); - if (this.anyGhosts() === false) - this.sendGameBoard(); + gameBoardClass.drawGameBoard(this.gameBoard, this.drawChequer); + if (ghost.anyGhosts(this.gameBoard, this.color) === false) + this.sendGameBoard(true); else - console.log("ghost were created"); - } - moveFromBase() { - let start: Square, i: number; - - this.gameBoard.map.forEach((square, j) => { - if (square.start === this.color) { - start = square; - i = j; - } - }) - - this.gameBoard.bases[this.color as keyof HomesOrBases].forEach((chequer, j) => { - if (chequer.chequer > -1) { - chequer.ghost = { - where: { - from: "base", oldIndex: j, - to: "map", newIndex: i - }, - color: this.color, - coords: { x: start.x, y: start.y } - }; - } - }) + ghost.allBlink(this.gameBoard, this.color); } - moveInMap(number: number) { - this.gameBoard.map.forEach((square, i) => { - if (square.chequers.length > 0 && square.chequers[0].color === this.color) { - - for (let chequer of square.chequers) { - let x: number | undefined, y: number | undefined, coords: Coordinates | undefined, inMap: boolean, - homeIndex: number | undefined; - - if (i + number < this.gameBoard.map.length) { - x = this.gameBoard.map[i + number].x; - y = this.gameBoard.map[i + number].y; - inMap = true; - } - else { - homeIndex = this.gameBoard.map.length - i - 1 - number - 1; - inMap = true; - - if (homeIndex < this.gameBoard.homes[0].length) { - x = this.gameBoard.homes[this.color as keyof HomesOrBases][homeIndex].x; - y = this.gameBoard.homes[this.color as keyof HomesOrBases][homeIndex].y; - } - else { - x = y = undefined; - } - } - if (x === undefined || y === undefined) - coords = undefined; - else - coords = { x, y }; - - chequer.ghost = { - where: { - from: "map", oldIndex: i, - to: (inMap === true ? "map" : "home"), newIndex: homeIndex || i + number - }, - color: this.color, - coords, - } - } - } - }) - } - moveInHome(number: number) { - let home = this.gameBoard.homes[this.color as keyof HomesOrBases]; - - home.forEach((chequer, i) => { - if (chequer.chequer > -1) { - let x: number | undefined, y: number | undefined, coords: Coordinates | undefined; - if (home[i + number] !== undefined) { - x = home[i + number].x; - y = home[i + number].y; - } else { - x = y = undefined; - } - - if (x === undefined || y === undefined) - coords = undefined; - else - coords = { x, y }; - - chequer.ghost = { - where: { - from: "home", oldIndex: i, - to: "home", newIndex: i + number - }, - color: this.color, - coords, - }; - } - }); - } - - showGhost(chequer: Chequer | HoBSquare) { + doTurn(chequer: Chequer | HoBSquare, redraw = true): void { if (chequer.ghost === undefined || chequer.ghost.coords === undefined) { - console.log("showChequer::chequer.ghost.coords === undefined", chequer.ghost?.coords === undefined); - return; - } - this.showChequer(chequer.ghost.coords, this.color) - } - hideGhost(chequer: Chequer | HoBSquare): void { - if (chequer.ghost === undefined || chequer.ghost.coords === undefined) { - console.log("hideChequer::chequer.ghost.coords === undefined", chequer.ghost?.coords === undefined); - return; - } - this.hideChequer(chequer.ghost.coords); - } - doTurn(chequer: Chequer | HoBSquare): void { - if (chequer.ghost === undefined || chequer.ghost.coords === undefined) { - console.log("hideChequer::chequer.ghost.coords === undefined", chequer.ghost?.coords === undefined); return; } this.mineTurn = false; @@ -250,169 +142,108 @@ export default class StartGame { } if (where.to === "map") { - this.gameBoard.map[where.newIndex].chequers.push({ color: this.color }); + let mapIndex = this.gameBoard.map[where.newIndex], + enemyColor = mapIndex.chequers[0]?.color; + if (enemyColor !== this.color && enemyColor !== undefined) { + let enemyBase = this.gameBoard.bases[enemyColor as keyof HomesOrBases]; + for (let chequer of mapIndex.chequers) { + let i = 0; + for (let c of enemyBase) { + if (c.chequer < 0) break; + i++; + } + chequer.ghost = { + color: enemyColor, coords: { x: mapIndex.x, y: mapIndex.y }, + where: { + from: "map", oldIndex: where.newIndex, + to: "base", newIndex: i + } + } + this.doTurn(chequer, true); + } + mapIndex.chequers = []; + } + + mapIndex.chequers.push({ color: this.color }); } else if (where.to === "base") { this.gameBoard.bases[this.color as keyof HomesOrBases][where.newIndex].chequer = this.color; } else { this.gameBoard.homes[this.color as keyof HomesOrBases][where.newIndex].chequer = this.color; } - this.sendGameBoard(); - } - removeGhosts(): void { - for (let square of this.gameBoard.map) { - for (let chequer of square.chequers) { - chequer.ghost = undefined; - } - } - for (let chequer of this.gameBoard.bases[this.color as keyof HomesOrBases]) { - chequer.ghost = undefined; + if (redraw === true) { + gameBoardClass.drawGameBoard(this.gameBoard, this.drawChequer); + this.sendGameBoard(false); } - for (let chequer of this.gameBoard.homes[this.color as keyof HomesOrBases]) { - chequer.ghost = undefined; - } - } - anyGhosts(): boolean { - for (let square of this.gameBoard.map) { - for (let chequer of square.chequers) { - if (chequer.ghost !== undefined) - return true; - } - } - for (let chequer of this.gameBoard.bases[this.color as keyof HomesOrBases]) { - if (chequer.ghost !== undefined) - return true; - } - for (let chequer of this.gameBoard.homes[this.color as keyof HomesOrBases]) { - if (chequer.ghost !== undefined) - return true; - } - return false; } - drawGameBoard(): void { - - for (let square of this.gameBoard.map) { - if (square.chequers.length !== 0) { - for (let chequer of square.chequers) - this.drawChequer({ x: square.x, y: square.y }, chequer.color, chequer); - } - } - for (let baseOfColor in this.gameBoard.bases) { - for (let square of this.gameBoard.bases[baseOfColor as unknown as keyof HomesOrBases]) { - if (square.chequer > -1) - this.drawChequer({ x: square.x, y: square.y }, square.chequer, square); - } - } - for (let baseOfColor in this.gameBoard.homes) { - for (let square of this.gameBoard.homes[baseOfColor as unknown as keyof HomesOrBases]) { - if (square.chequer > -1) - this.drawChequer({ x: square.x, y: square.y }, square.chequer, square); - } - } - } - - drawGameTable(): void { - for (let i = 0; i < this.numberOfSquaresOnGameBoard; i++) { - let tr = document.createElement("tr"); - for (let j = 0; j < this.numberOfSquaresOnGameBoard; j++) { - let td = document.createElement("td"); - td.classList.add("chequer"); - td.dataset.count = '0'; - tr.appendChild(td); - } - this.gameTable.appendChild(tr); - } + async hideDice(wait: boolean) { + let diceHash = this._diceHash; + wait === true ? await Helpers.sleep(5000) : ''; + if (diceHash === this.diceHash) + this.divDice.className = this.divDice.className.replace(/dice.*/, ''); } - async sendGameBoard() { - this.divDice.className.replace(/dice.*/, ''); - this.removeGhosts(); + async sendGameBoard(diceWait: boolean) { + ghost.allStopBlink(); + ghost.removeGhosts(this.gameBoard, this.color); + this.timer.stop(); + this.gameWasStopped = true; + this.hideDice(diceWait); await Helpers.mFetch("/saveGameBoard", { gameBoard: this.gameBoard }); } - getTd(coords: Coordinates): HTMLElement { - return this.gameTable.children[coords.y].children[coords.x] as HTMLElement; - } - showChequer(coords: Coordinates, color: tColors): void { - let td = this.getTd(coords); - if (td.dataset.count === undefined) - throw new Error("td.dataset.count is undefined!!!") - - if (td.dataset.count === '0') { - td.classList.add("chequer-" + this.colors[color]); - td.dataset.count = "1"; - } else { - td.dataset.count = (parseInt(td.dataset.count) + 1).toString(); - td.innerHTML = 'x' + td.dataset.count; - } - } - hideChequer(coords: Coordinates, all = false) { - let td = this.getTd(coords); - if (td.dataset.count === undefined) - throw new Error("td.dataset.count is undefined!!!") - - if (td.dataset.count === '0') - throw new Error("Cannot remove from empty td!!!"); - - if (td.dataset.count === '1' || all === true) { - td.className = td.className.replace(/chequer-.*/, ''); - td.innerHTML = 'x' + td.dataset.count; - } else { - td.dataset.count = (parseInt(td.dataset.count) - 1).toString(); - td.innerHTML = 'x' + td.dataset.count; - } - } - - drawChequer(coords: Coordinates, color: tColors, chequer: Chequer | HoBSquare): void { - let td = this.getTd(coords); - this.showChequer(coords, color); + drawChequer = (coords: Coordinates, color: tColors, chequer: Chequer | HoBSquare): void => { + let td = gameTable.getTd(coords); + gameBoardClass.showChequer(coords, color); if (this.mineTurn === true && chequer.ghost !== undefined) { - td.onmouseenter = () => { console.log("mouseenter"); this.showGhost(chequer); } - td.onmouseleave = () => { console.log("mouseleave"); this.hideGhost(chequer); } - td.onclick = () => { console.log("mouseclick"); this.doTurn(chequer); } + td.onmouseenter = () => ghost.showGhost(chequer, this.color); + td.onmouseleave = () => ghost.hideGhost(chequer); + td.onclick = () => this.doTurn(chequer); } } - removeChequer(coords: Coordinates) { - let td = this.getTd(coords); - this.hideChequer(coords, true); - td.onmouseenter = () => null; - td.onmouseleave = () => null; - td.onclick = () => null; + + async startTimer(currentPlayer: number, timeTillTurnEnd: number) { + await this.timer.start(currentPlayer, timeTillTurnEnd); + if (this.gameWasStopped !== true) + this.sendGameBoard(false); } + _diceHash = 0; + get diceHash(): number { + if (this._diceHash >= Number.MAX_SAFE_INTEGER) + this._diceHash = 0; - async startTimer(currentPlayer: number) { - await this.timer.start(currentPlayer, this.timeTillTurnEnd); - this.sendGameBoard(); + return this._diceHash++; } async getData() { let data: { gameBoard: GameBoard, currentPlayer: number, started: number, data: Data, timeTillTurnEnd: number } = await Helpers.mFetch("/getCurrentGameState", {}); if (data.started === 1) { + this.gameStarted = true; if (this.oldIndex !== data.currentPlayer) { this.oldIndex = data.currentPlayer; - if (data.currentPlayer === this.index && this.mineTurn === false) { + if (data.currentPlayer === this.index/* && this.mineTurn === false */) { this.mineTurn = true; + this.gameWasStopped = false; this.btnRollDice.style.display = "block"; }// else if (JSON.stringify(data.gameBoard) !== JSON.stringify(this.gameBoard)) { this.gameBoard = data.gameBoard; - this.drawGameBoard(); + gameBoardClass.drawGameBoard(this.gameBoard, this.drawChequer); // } - this.timeTillTurnEnd = data.timeTillTurnEnd; - this.startTimer(data.currentPlayer); + this.startTimer(data.currentPlayer, data.timeTillTurnEnd); } } if (JSON.stringify(data.data) !== JSON.stringify(this.data)) { - console.log("startGame::getData::data", data.data); this.data = data.data; this.setOpponents(this.data, false); } - // TODO: Animation: blinking of chequers with ghosts + // TODO: Going to home + // TODO: Check stacking + // TODO: Check zbijanie + // TODO: Going from [40] -> [0] // TODO: Ending turn - // TODO: Ghost not working - // TODO: Moving not working } } diff --git a/frontend/ts/timer.ts b/frontend/ts/timer.ts index f8dab25..db70356 100644 --- a/frontend/ts/timer.ts +++ b/frontend/ts/timer.ts @@ -1,30 +1,33 @@ export default class Timer { - divTimer!: HTMLElement; + divTimer!: HTMLElement; - interval!: any; - async start(playerIndex: number, finishTime: number): Promise<void> { - return new Promise(resolve => { - let divTimer = document.getElementById(`${playerIndex}-player-time`); - if (divTimer === null) - throw new Error("divTimer doesn't Exist"); - else - this.divTimer = divTimer; + interval!: any; + async start(playerIndex: number, finishTime: number): Promise<void> { + return new Promise(resolve => { + if (this.interval !== undefined) + this.stop(); - this.interval = setInterval(() => { - this.updateDisplay(finishTime - Date.now(), resolve); - }, 1000); - }) - } + this.divTimer = document.getElementById(`${playerIndex}-player-time`) as HTMLElement; - updateDisplay(time: number, resolve: Function): void { - let secondsElapsed = Math.floor(time / 1000); - this.divTimer.innerHTML = secondsElapsed.toString(); - if (secondsElapsed === 0) { - resolve(); - clearInterval(this.interval); - } - } - stop(): void { - clearInterval(this.interval); + this.interval = setInterval(() => { + this.updateDisplay(finishTime - Date.now(), resolve); + }, 1000); + }) + } + + updateDisplay(time: number, resolve: Function): void { + let secondsElapsed = Math.floor(time / 1000); + if (secondsElapsed <= 0) { + resolve(); + clearInterval(this.interval); + this.divTimer.innerHTML = '0'; + } else { + this.divTimer.innerHTML = secondsElapsed.toString(); } + } + stop(): void { + this.divTimer.innerHTML = ''; + clearInterval(this.interval); + this.interval = undefined; + } }
\ No newline at end of file diff --git a/helpers/helpers.ts b/helpers/helpers.ts index 80fb5ab..3800040 100644 --- a/helpers/helpers.ts +++ b/helpers/helpers.ts @@ -66,15 +66,18 @@ export default class Helpers { return res; else throw new Error("API Error!");; - } - static getRandomInt(min: number, max: number) { + static getRandomInt(min: number, max: number): number { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min) + min); //The maximum is exclusive and the minimum is inclusive } + static async sleep(ms: number): Promise<void> { + return new Promise(resolve => setTimeout(resolve, ms)); + } + static Color: Colors = { blue: 0, red: 1, diff --git a/helpers/helpersBack.ts b/helpers/helpersBack.ts index 5aaae77..6a3dfd7 100644 --- a/helpers/helpersBack.ts +++ b/helpers/helpersBack.ts @@ -72,7 +72,7 @@ export async function sleep(ms: number) { } export async function waitForQueue(): Promise<void> { while(global.stop === true) { - await sleep(200); + await sleep(50); } } diff --git a/public/css/fia.css b/public/css/fia.css index fc660aa..0bb0749 100644 --- a/public/css/fia.css +++ b/public/css/fia.css @@ -7,6 +7,7 @@ border-collapse: separate; padding: 0; border-spacing: 0; + opacity: 1; } .game-table tr { padding: 0; @@ -53,11 +54,12 @@ .player-name :nth-child(even) { float: right; } - .chequer { background-size: contain; border-radius: 50%; - color: palevioletred; + font-size: 30px; + color: black; + -webkit-text-stroke: 5px black; } .chequer-red { background-image: url("https://jopek.eu/maks/szkola/apkKli/fiaFiles/chequer-red.png"); |
