From dd1bff838e88b347d923b64ae1bc62ef16cebba2 Mon Sep 17 00:00:00 2001 From: Ido-Barnea Date: Fri, 26 Jan 2024 16:39:31 +0200 Subject: [PATCH 1/5] [#159] Implemented "Coup" rule logic --- development/code/Game.ts | 12 ++++++ development/code/LogicAdapter.ts | 15 +++++++ development/code/logic/Players.ts | 2 + development/code/logic/rules/BaseRule.ts | 6 +-- development/code/logic/rules/CoupRule.ts | 40 +++++++++++++++++++ .../code/logic/rules/EmptyPocketsRule.ts | 18 +++++---- .../code/logic/rules/ExperienceOnKillRule.ts | 3 +- .../code/logic/rules/FirstBloodRule.ts | 3 +- .../code/logic/rules/FriendlyFireRule.ts | 3 +- .../rules/PiecesCanFallOffTheBoardRule.ts | 3 +- development/code/logic/rules/RulesManager.ts | 2 + .../logic/rules/WithAgeComesWisdomRule.ts | 3 +- development/code/ui/BoardManager.ts | 11 +++++ development/code/ui/Screen.ts | 2 +- 14 files changed, 99 insertions(+), 24 deletions(-) create mode 100644 development/code/logic/rules/CoupRule.ts diff --git a/development/code/Game.ts b/development/code/Game.ts index 8739d51e..ddb74ebd 100644 --- a/development/code/Game.ts +++ b/development/code/Game.ts @@ -13,6 +13,7 @@ import { RulesManager } from './logic/rules/RulesManager'; let rulesManager: RulesManager; const whitePlayer = new Player(PlayerColors.WHITE); +whitePlayer.gold = -1; const blackPlayer = new Player(PlayerColors.BLACK); const players: Array = [whitePlayer, blackPlayer]; let pieces: Array = [ @@ -75,6 +76,7 @@ function endTurn() { if (turnCounter % players.length === 0) { turnCounter = 0; roundCounter++; + updatePlayerDetails(); } renderScreen(); @@ -95,6 +97,16 @@ function resetVariables() { }); } +function updatePlayerDetails() { + game.getPlayers().forEach(player => { + if (player.gold < 0) { + player.inDebtForTurns++; + } else { + player.inDebtForTurns = 0; + } + }); +} + function getCurrentPlayer() { return players[currentPlayerIndex]; } diff --git a/development/code/LogicAdapter.ts b/development/code/LogicAdapter.ts index 1e3ce814..8d5a1c54 100644 --- a/development/code/LogicAdapter.ts +++ b/development/code/LogicAdapter.ts @@ -1,5 +1,6 @@ import { game } from './Game'; import { isPlayerAllowedToAct, onPieceFellOffTheBoard, onPlayerAction } from './logic/PieceLogic'; +import { PlayerColors } from './logic/Players'; import { comparePositions, convertSquareIdToPosition } from './logic/Utilities'; import { Item } from './logic/items/Items'; import { Piece } from './logic/pieces/Pieces'; @@ -14,6 +15,7 @@ import { spawnItemElementOnBoard, spawnPieceElementOnBoard, highlightLastMove, + getPieceElementBySquareId, } from './ui/BoardManager'; import { renderPlayersInformation, renderNewRule } from './ui/Screen'; @@ -174,3 +176,16 @@ export function spawnItemOnBoard(item: Item) { spawnItemElementOnBoard(item, squareId); } + +export function changePieceToAnotherPlayer(piece: Piece) { + const squareId = piece.position.coordinates.join(','); + const boadrId = piece.position.boardId; + const pieceElement = getPieceElementBySquareId(squareId, boadrId); + if (pieceElement) { + pieceElement.classList.remove(piece.player.color.toLowerCase()); + const enemyPlayerColor = piece.player.color === PlayerColors.WHITE ? PlayerColors.BLACK : PlayerColors.WHITE; + pieceElement.classList.add(enemyPlayerColor.toLowerCase()); + } + + piece.player = game.getPlayers().filter(_player => _player !== piece.player)[0]; +} diff --git a/development/code/logic/Players.ts b/development/code/logic/Players.ts index 0c6a83b4..0e97600f 100644 --- a/development/code/logic/Players.ts +++ b/development/code/logic/Players.ts @@ -16,12 +16,14 @@ export class Player implements PlayerType { color: string; xp: number; gold: number; + inDebtForTurns: number; inventory: Inventory; constructor(color: string) { this.color = color; this.xp = 0; this.gold = 0; + this.inDebtForTurns = 0; this.inventory = new Inventory(); } } diff --git a/development/code/logic/rules/BaseRule.ts b/development/code/logic/rules/BaseRule.ts index 705df3a9..424a5622 100644 --- a/development/code/logic/rules/BaseRule.ts +++ b/development/code/logic/rules/BaseRule.ts @@ -2,7 +2,6 @@ import { game } from '../../Game'; import { renderRules } from '../../LogicAdapter'; import { Logger } from '../../ui/Logger'; export interface Rule { - id: number; description: string; isRevealed: boolean; condition: () => boolean; @@ -11,20 +10,17 @@ export interface Rule { } export class BaseRule implements Rule { - id: number; description: string; isRevealed: boolean; condition: () => boolean; onTrigger: () => void; constructor( - id: number, description: string, isRevealed: boolean, condition: () => boolean, onTrigger: () => void, ) { - this.id = id; this.description = description; this.isRevealed = isRevealed; this.condition = condition; @@ -44,4 +40,4 @@ export class BaseRule implements Rule { } } } -} \ No newline at end of file +} diff --git a/development/code/logic/rules/CoupRule.ts b/development/code/logic/rules/CoupRule.ts new file mode 100644 index 00000000..17ac6bcf --- /dev/null +++ b/development/code/logic/rules/CoupRule.ts @@ -0,0 +1,40 @@ +import { game } from '../../Game'; +import { changePieceToAnotherPlayer } from '../../LogicAdapter'; +import { Logger } from '../../ui/Logger'; +import { King } from '../pieces/King'; +import { BaseRule } from './BaseRule'; + +export class CoupRule extends BaseRule { + constructor(isRevealed = false) { + const description = 'Coup.'; + const condition = () => { + let result = false; + game.getPlayers().forEach((player) => { + if (player.inDebtForTurns >= 3) { + result = true; + } + }); + return result; + }; + const onTrigger = () => { + game.getPlayers().forEach((player) => { + if (player.inDebtForTurns >= 3) { + player.inDebtForTurns = 0; + const playerPieces = game.getPieces().filter(piece => piece.player === player); + const randomAmountOfPieces = Math.floor(Math.random() * (playerPieces.length - 1) / 2) + 1; + Logger.logRule(`${player.color} is deep in debt. ${randomAmountOfPieces} of their pieces desert.`); + + let desertedPiecesCounter = 0; + playerPieces.forEach(piece => { + if (desertedPiecesCounter < randomAmountOfPieces && !(piece instanceof King)) { + changePieceToAnotherPlayer(piece); + desertedPiecesCounter++; + } + }); + } + }); + }; + + super(description, isRevealed, condition, onTrigger); + } +} \ No newline at end of file diff --git a/development/code/logic/rules/EmptyPocketsRule.ts b/development/code/logic/rules/EmptyPocketsRule.ts index b66e8091..f46ba5e7 100644 --- a/development/code/logic/rules/EmptyPocketsRule.ts +++ b/development/code/logic/rules/EmptyPocketsRule.ts @@ -4,14 +4,16 @@ import { BaseRule } from './BaseRule'; export class EmptyPocketsRule extends BaseRule { constructor(isRevealed = false) { - const index = 5; const description = 'Empty pockets.'; - let condition = () => false; - game.getPlayers().forEach((player) => { - if (player === game.getCurrentPlayer() && player.gold < 0) { - condition = () => true; - } - }); + const condition = () => { + let result = false; + game.getPlayers().forEach((player) => { + if (player === game.getCurrentPlayer() && player.gold < 0) { + result = true; + } + }); + return result; + }; const onTrigger = () => { game.getPlayers().forEach((player) => { if (player === game.getCurrentPlayer() && player.gold < 0) { @@ -22,6 +24,6 @@ export class EmptyPocketsRule extends BaseRule { }); }; - super(index, description, isRevealed, condition, onTrigger); + super(description, isRevealed, condition, onTrigger); } } \ No newline at end of file diff --git a/development/code/logic/rules/ExperienceOnKillRule.ts b/development/code/logic/rules/ExperienceOnKillRule.ts index 83dc2def..59c64e6d 100644 --- a/development/code/logic/rules/ExperienceOnKillRule.ts +++ b/development/code/logic/rules/ExperienceOnKillRule.ts @@ -4,7 +4,6 @@ import { BaseRule } from './BaseRule'; export class ExperienceOnKillRule extends BaseRule { constructor(isRevealed = false) { - const index = 2; const description = 'Players gain XP on a kill.'; const condition = () => game.getIsPieceKilled(); const onTrigger = () => { @@ -13,6 +12,6 @@ export class ExperienceOnKillRule extends BaseRule { player.xp++; }; - super(index, description, isRevealed, condition, onTrigger); + super(description, isRevealed, condition, onTrigger); } } \ No newline at end of file diff --git a/development/code/logic/rules/FirstBloodRule.ts b/development/code/logic/rules/FirstBloodRule.ts index f9e0f8e0..c1842079 100644 --- a/development/code/logic/rules/FirstBloodRule.ts +++ b/development/code/logic/rules/FirstBloodRule.ts @@ -4,7 +4,6 @@ import { BaseRule } from './BaseRule'; export class FirstBloodRule extends BaseRule { constructor(isRevealed = false) { - const index = 1; const description = 'First Blood Bonus: The first to kill gets an extra XP.'; const condition = () => game.getDeathCounter() == 1 && game.getIsPieceKilled(); const onTrigger = () => { @@ -13,6 +12,6 @@ export class FirstBloodRule extends BaseRule { player.xp++; }; - super(index, description, isRevealed, condition, onTrigger); + super(description, isRevealed, condition, onTrigger); } } \ No newline at end of file diff --git a/development/code/logic/rules/FriendlyFireRule.ts b/development/code/logic/rules/FriendlyFireRule.ts index 3b2be53d..c790677f 100644 --- a/development/code/logic/rules/FriendlyFireRule.ts +++ b/development/code/logic/rules/FriendlyFireRule.ts @@ -4,7 +4,6 @@ import { BaseRule } from './BaseRule'; export class FriendlyFireRule extends BaseRule { constructor(isRevealed = false) { - const index = 3; const description = 'Friendly Fire! Players can attack their own pieces (for a price).'; const condition = () => game.getIsFriendlyFire(); const onTrigger = () => { @@ -13,6 +12,6 @@ export class FriendlyFireRule extends BaseRule { player.gold--; }; - super(index, description, isRevealed, condition, onTrigger); + super(description, isRevealed, condition, onTrigger); } } \ No newline at end of file diff --git a/development/code/logic/rules/PiecesCanFallOffTheBoardRule.ts b/development/code/logic/rules/PiecesCanFallOffTheBoardRule.ts index bf0381fc..2340fde0 100644 --- a/development/code/logic/rules/PiecesCanFallOffTheBoardRule.ts +++ b/development/code/logic/rules/PiecesCanFallOffTheBoardRule.ts @@ -4,7 +4,6 @@ import { BaseRule } from './BaseRule'; export class PiecesCanFallOffTheBoardRule extends BaseRule { constructor(isRevealed = false) { - const index = 0; const description = 'Pieces can fall off the board.'; const condition = () => !!game.getFellOffTheBoardPiece(); const onTrigger = () => { @@ -13,6 +12,6 @@ export class PiecesCanFallOffTheBoardRule extends BaseRule { `); }; - super(index, description, isRevealed, condition, onTrigger); + super(description, isRevealed, condition, onTrigger); } } \ No newline at end of file diff --git a/development/code/logic/rules/RulesManager.ts b/development/code/logic/rules/RulesManager.ts index e77e6c49..a2a012ad 100644 --- a/development/code/logic/rules/RulesManager.ts +++ b/development/code/logic/rules/RulesManager.ts @@ -1,4 +1,5 @@ import { BaseRule } from './BaseRule'; +import { CoupRule } from './CoupRule'; import { EmptyPocketsRule } from './EmptyPocketsRule'; import { ExperienceOnKillRule } from './ExperienceOnKillRule'; import { FirstBloodRule } from './FirstBloodRule'; @@ -19,6 +20,7 @@ export class RulesManager { new FriendlyFireRule(), new WithAgeComesWisdomRule(), new EmptyPocketsRule(), + new CoupRule(), ]; } } diff --git a/development/code/logic/rules/WithAgeComesWisdomRule.ts b/development/code/logic/rules/WithAgeComesWisdomRule.ts index 82a000d0..a3fbcc2f 100644 --- a/development/code/logic/rules/WithAgeComesWisdomRule.ts +++ b/development/code/logic/rules/WithAgeComesWisdomRule.ts @@ -4,7 +4,6 @@ import { BaseRule } from './BaseRule'; export class WithAgeComesWisdomRule extends BaseRule { constructor(isRevealed = false) { - const index = 4; const description = 'With age comes wisdom.'; const condition = () => game.getRoundCounter() === 20; const onTrigger = () => { @@ -15,6 +14,6 @@ export class WithAgeComesWisdomRule extends BaseRule { }); }; - super(index, description, isRevealed, condition, onTrigger); + super(description, isRevealed, condition, onTrigger); } } \ No newline at end of file diff --git a/development/code/ui/BoardManager.ts b/development/code/ui/BoardManager.ts index 18f7eab6..0df61f83 100644 --- a/development/code/ui/BoardManager.ts +++ b/development/code/ui/BoardManager.ts @@ -114,6 +114,17 @@ export function getSquareElementById( return board.boardElement.querySelector(`[square-id="${squareId}"]`) as HTMLElement; } +export function getPieceElementBySquareId( + squareId: string, + boardId: string, +): HTMLElement | undefined { + const squareElement = getSquareElementById(squareId, boardId); + const pieceElement = squareElement?.firstElementChild as HTMLElement; + if (pieceElement.classList.contains('piece')) { + return pieceElement; + } +} + export function moveElementOnBoard( boardId: string, originSquareId: string, diff --git a/development/code/ui/Screen.ts b/development/code/ui/Screen.ts index d47358b6..1be36c3d 100644 --- a/development/code/ui/Screen.ts +++ b/development/code/ui/Screen.ts @@ -36,6 +36,6 @@ export function renderPlayersInformation() { export function renderNewRule(rule: BaseRule) { const ruleElement = document.createElement('p'); - ruleElement.innerHTML = `${rule.id + 1}) ${rule.description}`; + ruleElement.innerHTML = `- ${rule.description}`; rulesContainer?.appendChild(ruleElement); } From 026b97fff8d9c89304d602f21013155e84342f3c Mon Sep 17 00:00:00 2001 From: Ido-Barnea Date: Fri, 26 Jan 2024 16:40:32 +0200 Subject: [PATCH 2/5] [trivial] Minor fix --- development/code/logic/rules/CoupRule.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/development/code/logic/rules/CoupRule.ts b/development/code/logic/rules/CoupRule.ts index 17ac6bcf..956e4de0 100644 --- a/development/code/logic/rules/CoupRule.ts +++ b/development/code/logic/rules/CoupRule.ts @@ -10,7 +10,7 @@ export class CoupRule extends BaseRule { const condition = () => { let result = false; game.getPlayers().forEach((player) => { - if (player.inDebtForTurns >= 3) { + if (player.inDebtForTurns === 3) { result = true; } }); @@ -18,7 +18,7 @@ export class CoupRule extends BaseRule { }; const onTrigger = () => { game.getPlayers().forEach((player) => { - if (player.inDebtForTurns >= 3) { + if (player.inDebtForTurns === 3) { player.inDebtForTurns = 0; const playerPieces = game.getPieces().filter(piece => piece.player === player); const randomAmountOfPieces = Math.floor(Math.random() * (playerPieces.length - 1) / 2) + 1; From 9da0ade1fa39fc0728a0cd4db2c3518955e4abd4 Mon Sep 17 00:00:00 2001 From: Ido-Barnea Date: Fri, 26 Jan 2024 16:49:12 +0200 Subject: [PATCH 3/5] [#159] Minor fix --- development/code/Game.ts | 12 +++++++----- development/code/logic/rules/CoupRule.ts | 6 +++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/development/code/Game.ts b/development/code/Game.ts index ddb74ebd..3401f3e1 100644 --- a/development/code/Game.ts +++ b/development/code/Game.ts @@ -70,13 +70,13 @@ function endTurn() { }); resetVariables(); + updatePlayerDetails(); currentPlayerIndex = currentPlayerIndex + 1 < players.length ? currentPlayerIndex + 1 : 0; turnCounter++; if (turnCounter % players.length === 0) { turnCounter = 0; roundCounter++; - updatePlayerDetails(); } renderScreen(); @@ -99,10 +99,12 @@ function resetVariables() { function updatePlayerDetails() { game.getPlayers().forEach(player => { - if (player.gold < 0) { - player.inDebtForTurns++; - } else { - player.inDebtForTurns = 0; + if (player === getCurrentPlayer()) { + if (player.gold < 0) { + player.inDebtForTurns++; + } else { + player.inDebtForTurns = 0; + } } }); } diff --git a/development/code/logic/rules/CoupRule.ts b/development/code/logic/rules/CoupRule.ts index 956e4de0..04e7b41b 100644 --- a/development/code/logic/rules/CoupRule.ts +++ b/development/code/logic/rules/CoupRule.ts @@ -10,7 +10,7 @@ export class CoupRule extends BaseRule { const condition = () => { let result = false; game.getPlayers().forEach((player) => { - if (player.inDebtForTurns === 3) { + if (player.inDebtForTurns === 2 && player === game.getCurrentPlayer()) { result = true; } }); @@ -18,8 +18,8 @@ export class CoupRule extends BaseRule { }; const onTrigger = () => { game.getPlayers().forEach((player) => { - if (player.inDebtForTurns === 3) { - player.inDebtForTurns = 0; + if (player.inDebtForTurns === 2 && player === game.getCurrentPlayer()) { + player.inDebtForTurns = -1; const playerPieces = game.getPieces().filter(piece => piece.player === player); const randomAmountOfPieces = Math.floor(Math.random() * (playerPieces.length - 1) / 2) + 1; Logger.logRule(`${player.color} is deep in debt. ${randomAmountOfPieces} of their pieces desert.`); From 8f0f99575181b7fd2ff72cc9a7d52892346d52fd Mon Sep 17 00:00:00 2001 From: Ido-Barnea Date: Fri, 26 Jan 2024 19:48:37 +0200 Subject: [PATCH 4/5] [#159] Picking random pieces to desert --- development/code/logic/rules/CoupRule.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/development/code/logic/rules/CoupRule.ts b/development/code/logic/rules/CoupRule.ts index 04e7b41b..7c74c3ca 100644 --- a/development/code/logic/rules/CoupRule.ts +++ b/development/code/logic/rules/CoupRule.ts @@ -16,21 +16,25 @@ export class CoupRule extends BaseRule { }); return result; }; + const onTrigger = () => { game.getPlayers().forEach((player) => { if (player.inDebtForTurns === 2 && player === game.getCurrentPlayer()) { player.inDebtForTurns = -1; const playerPieces = game.getPieces().filter(piece => piece.player === player); const randomAmountOfPieces = Math.floor(Math.random() * (playerPieces.length - 1) / 2) + 1; + Logger.logRule(`${player.color} is deep in debt. ${randomAmountOfPieces} of their pieces desert.`); let desertedPiecesCounter = 0; - playerPieces.forEach(piece => { - if (desertedPiecesCounter < randomAmountOfPieces && !(piece instanceof King)) { - changePieceToAnotherPlayer(piece); - desertedPiecesCounter++; - } - }); + while (desertedPiecesCounter < randomAmountOfPieces) { + const randomPieceIndex = Math.floor(Math.random() * (playerPieces.length - 1)) + 1; + const piece = playerPieces[randomPieceIndex]; + if (piece instanceof King) continue; + + changePieceToAnotherPlayer(piece); + desertedPiecesCounter++; + } } }); }; From 6fb6e78f7b750b3ba7ede140d9ce015f6f78aefc Mon Sep 17 00:00:00 2001 From: Ido-Barnea Date: Fri, 26 Jan 2024 19:49:16 +0200 Subject: [PATCH 5/5] [#159] Removed testing logic --- development/code/Game.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/development/code/Game.ts b/development/code/Game.ts index 3401f3e1..bc1d0415 100644 --- a/development/code/Game.ts +++ b/development/code/Game.ts @@ -13,7 +13,6 @@ import { RulesManager } from './logic/rules/RulesManager'; let rulesManager: RulesManager; const whitePlayer = new Player(PlayerColors.WHITE); -whitePlayer.gold = -1; const blackPlayer = new Player(PlayerColors.BLACK); const players: Array = [whitePlayer, blackPlayer]; let pieces: Array = [