diff options
| author | Armand Philippot <git@armandphilippot.com> | 2022-02-20 16:11:50 +0100 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2022-02-20 16:15:08 +0100 |
| commit | 73a5c7fae9ffbe9ada721148c8c454a643aceebe (patch) | |
| tree | c8fad013ed9b5dd589add87f8d45cf02bbfc6e91 /public/projects/js-small-apps/rock-paper-scissors/lib/class-rps-game.js | |
| parent | b01239fbdcc5bbc5921f73ec0e8fee7bedd5c8e8 (diff) | |
chore!: restructure repo
I separated public files from the config/dev files. It improves repo
readability.
I also moved dotenv helper to public/inc directory and extract the
Matomo tracker in the same directory.
Diffstat (limited to 'public/projects/js-small-apps/rock-paper-scissors/lib/class-rps-game.js')
| -rw-r--r-- | public/projects/js-small-apps/rock-paper-scissors/lib/class-rps-game.js | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/public/projects/js-small-apps/rock-paper-scissors/lib/class-rps-game.js b/public/projects/js-small-apps/rock-paper-scissors/lib/class-rps-game.js new file mode 100644 index 0000000..fe517db --- /dev/null +++ b/public/projects/js-small-apps/rock-paper-scissors/lib/class-rps-game.js @@ -0,0 +1,230 @@ +import Game from "./class-game.js"; + +/** + * RPSGame class. + */ +class RPSGame extends Game { + #choices = ["rock", "paper", "scissors"]; + #buttons = { rock: "", paper: "", scissors: "", newGame: "" }; + #p1Scoring = { name: "", value: "" }; + #p2Scoring = { name: "", value: "" }; + #messages = ""; + #messageIterator; + #timeoutId; + + /** + * Initialize a new RPSGame instance. + * @param {Object[]} players - An array of player object. + * @param {String} players[].username - The player username. + * @param {Boolean} players[].ia - True to set the player as an IA. + * @param {Object} buttons - The buttons HTMLElement. + * @param {HTMLElement} buttons.rock - Button Element for rock choice. + * @param {HTMLElement} buttons.paper - Button Element for paper choice. + * @param {HTMLElement} buttons.scissors - Button Element for scissors choice. + * @param {HTMLElement} buttons.newGame - Button Element to start new game. + * @param {Object} p1Scoring - The player 1 scoring display. + * @param {HTMLElement} p1Scoring.name - Element to display player 1 name. + * @param {HTMLElement} p1Scoring.value - Element to display player 1 score. + * @param {Object} p2Scoring - The player 2 scoring display. + * @param {HTMLElement} p2Scoring.name - Element to display player 2 name. + * @param {HTMLElement} p2Scoring.value - Element to display player 2 score. + * @param {HTMLElement} messages - Element to display turn/game results. + */ + constructor( + players, + buttons = { rock: "", paper: "", scissors: "", newGame: "" }, + p1Scoring = { name: "", value: "" }, + p2Scoring = { name: "", value: "" }, + messages + ) { + super("Rock Paper Scissors", players); + this.#buttons = buttons; + this.#p1Scoring = p1Scoring; + this.#p2Scoring = p2Scoring; + this.#messages = messages; + } + + get messages() { + return this.#messages; + } + + set messageIterator(generator) { + this.#messageIterator = generator; + } + + get messageIterator() { + return this.#messageIterator; + } + + #updatePlayers() { + this.#p1Scoring.name.textContent = this.getPlayer(1).username; + this.#p2Scoring.name.textContent = this.getPlayer(2).username; + } + + #updateScore() { + this.#p1Scoring.value.textContent = this.getPlayer(1).score; + this.#p2Scoring.value.textContent = this.getPlayer(2).score; + } + + async #createMessage(msg, delay = 0) { + return new Promise( + (resolve) => + (this.#timeoutId = setTimeout(() => { + resolve(msg); + }, delay)) + ); + } + + async *#generateMessages() { + let msg; + msg = yield await this.#createMessage("New game, let's play!"); + + while (this.state === "running") { + for (let index = 0; index < this.getPlayersNumber(); index++) { + if (this.getCurrentPlayer().ia) { + msg = yield this.#createMessage( + `${this.getCurrentPlayer().username} is playing...`, + this.isFirstTurn() ? 1200 : 200 + ); + } else { + msg = yield this.#createMessage( + `${this.getCurrentPlayer().username}'s turn...`, + this.isFirstTurn() ? 1200 : 900 + ); + } + } + msg = yield this.#createMessage( + msg, + this.getCurrentPlayer().ia ? 1000 : 500 + ); + if (!this.isGameOver()) { + msg = yield this.#createMessage("New round...", 1500); + } + } + const winnersList = this.gameWinners.map((winner) => winner.username); + const losersList = this.gameLosers.map((loser) => loser.username); + msg = yield this.#createMessage( + `Winner: ${winnersList.join(", ")} / Loser: ${losersList.join(", ")}` + ); + } + + async printNextMessage(msg = null) { + if (!this.messageIterator) { + this.messageIterator = this.#generateMessages(); + } + this.messages.textContent = await this.messageIterator + .next(msg) + .then((object) => object.value); + } + + async #setTurnIssue() { + const choices = `${this.getPlayer(1).choice}-${this.getPlayer(2).choice}`; + let turnWinner; + let turnLoser; + let even = false; + let msg; + + switch (choices) { + case "rock-paper": + case "paper-scissors": + case "scissors-rock": + turnWinner = this.getPlayer(2); + turnLoser = this.getPlayer(1); + break; + case "paper-rock": + case "rock-scissors": + case "scissors-paper": + turnWinner = this.getPlayer(1); + turnLoser = this.getPlayer(2); + break; + default: + even = true; + break; + } + + if (!even) { + this.turnWinners = [turnWinner]; + this.turnLosers = [turnLoser]; + turnWinner.score++; + msg = `${turnWinner.username} wins! ${turnWinner.choice} beats ${turnLoser.choice}.`; + } else { + msg = `No winner. ${this.getPlayer(1).choice} equals to ${ + this.getPlayer(2).choice + }.`; + } + await this.printNextMessage(msg); + this.#updateScore(); + await this.printNextMessage(); + } + + async #getIAAction() { + if (this.currentTurn % 2 === 0) { + await this.#setTurnIssue(); + this.turn.next(); + await this.printNextMessage(); + if (!this.isGameOver()) { + this.getCurrentPlayer().choice = this.getRandomChoice(this.#choices); + } + } else { + this.turn.next(); + await this.printNextMessage(); + this.getCurrentPlayer().choice = this.getRandomChoice(this.#choices); + await this.#setTurnIssue(); + } + this.turn.next(); + await this.printNextMessage(); + } + + async listen() { + for (const [name, element] of Object.entries(this.#buttons)) { + element.addEventListener("click", async (event) => { + event.preventDefault(); + switch (name) { + case "rock": + case "paper": + case "scissors": + if (this.state === "running") { + this.setPlayerChoice(name); + if (this.currentTurn % 2 === 0) { + await this.#setTurnIssue(); + } + if (this.getNextPlayer().ia) { + await this.#getIAAction(); + } else { + this.turn.next(); + await this.printNextMessage(); + } + } + break; + case "newGame": + this.messageIterator = null; + clearTimeout(this.#timeoutId); + await this.launch(); + default: + break; + } + }); + } + } + + async launch() { + super.launch(); + this.#updatePlayers(); + this.#updateScore(); + await this.printNextMessage(); + await this.printNextMessage(); + + if (this.getCurrentPlayer().ia) { + this.getCurrentPlayer().choice = this.getRandomChoice(this.#choices); + this.turn.next(); + await this.printNextMessage(); + } + } + + async init() { + await this.launch(); + this.listen(); + } +} + +export default RPSGame; |
