diff --git a/index.html b/index.html index 74f9da2a..1a52d70f 100644 --- a/index.html +++ b/index.html @@ -18,7 +18,7 @@ } #container { - background-color: pink; + background-color: rgb(252, 208, 126); margin: 40px auto; max-width: 800px; padding: 38px 31px; @@ -51,6 +51,11 @@

Basics: Beat That! 🚀

+

Hello! Welcome to Beat That! Click submit to start the game.

+

+ Create a two-digit number by selecting the order of your dice rolls. +

+

The player with the highest number wins! Good luck!

Input:


diff --git a/script.js b/script.js index bbe8a293..56e81b77 100644 --- a/script.js +++ b/script.js @@ -1,4 +1,585 @@ -var main = function (input) { - var myOutputValue = 'hello world'; +//global variables +//gameTypes +const SELECTION_MODE = `selectionMode`; +const BASE = `base`; +const VARIABLE_DICE_NUM = `variableDiceNum`; +const VARIABLE_PLAYER_NUM = `variablePlayerNum`; +const KNOCKOUT_MODE = `knockoutMode`; + +//modes in a gameType +const START_TURN = `startTurn`; +const SELECT_DICE_ORDER = `selectOrder`; +const END_GAME = `endGame`; +const WAITING_FOR_DICE_COUNT = `waitingForDiceCount`; +const SELECTING_KO_PLAYERS = `selectKoPlayers`; +const CHECK_BRACKET = `checkBracket`; +const END_KO_GAME = `endKoGame`; + +//brackets for knockout mode +const UPPER = `upper`; +const LOWER = `lower`; +let bracket = UPPER; + +//reused Msgs +const SUBMIT_TO_CONTINUE_MSG = `Press Submit to continue.`; +const INVALID_INPUT_MSG = `This is an invalid input. Please enter a number that is 2 or greater.`; +const INVALID_KO_MSG = `This is an invalid input. Please enter a number that is 4 or greater.`; + +//game settings +let mode = ``; +let gameType = ``; +let lowestCombinedMode = false; +let aiMode = false; +let currentPlayer = 1; +let numberOfPlayers; +let numberOfDice; +const playerProfiles = []; +const playersDiceRolls = []; + +//knockout game settings +let koPlayerOne; +let koPlayerTwo; +let prevPlayer; +let endKoGame = false; +const knockoutBrackets = [[], [], []]; + +//END of global variables +//functions + +//helper functions +function initPlayersData(numberOfPlayers) { + for ( + let playerCounter = 1; + playerCounter <= numberOfPlayers; + playerCounter += 1 + ) { + playerProfiles.push({ + id: playerCounter, + diceResult: 0, + score: 0, + }); + playersDiceRolls.push(0); + } +} + +//text for selecting gameTypes +function inquireGameType() { + return `Please select from the following game modes:

1: Default (Base Rules)
2: Lowest Combined (Lowest combined dice number wins instead)
3: Variable Number of Dice (Computer will automatically select dice order)
4: Variable Number of Players (Rules are same as Default otherwise)
5: Knockout Format (Multiple Players, computer will automatically select dice order)

Input 000 to toggle an option for the computer to automatically generate the optimal dice roll order`; +} + +function selectGameType(playerChoice) { + switch (playerChoice) { + case `1`: + gameType = BASE; + return `Initiating the base game! ${SUBMIT_TO_CONTINUE_MSG}`; + case `2`: + gameType = BASE; + lowestCombinedMode = !lowestCombinedMode; + return `Reminder that the smallest combined number wins! ${SUBMIT_TO_CONTINUE_MSG}`; + case `3`: + gameType = VARIABLE_DICE_NUM; + aiMode = true; + return `Input the number of dice the players would like to play with! ${SUBMIT_TO_CONTINUE_MSG}`; + case `4`: + gameType = VARIABLE_PLAYER_NUM; + return `Input the number of players joining the game! ${SUBMIT_TO_CONTINUE_MSG}`; + case `5`: + gameType = KNOCKOUT_MODE; + aiMode = true; + numberOfPlayers = 0; + return `Input the number of players entering the knockout tournament! ${SUBMIT_TO_CONTINUE_MSG}`; + case `000`: + aiMode = !aiMode; + let aiMsg; + gameType = ``; + if (aiMode == true) { + aiMsg = `AI mode is now ON. There is no need to select the dice order in this mode.`; + } else { + aiMsg = `AI mode is now OFF.`; + } + return `${aiMsg} ${SUBMIT_TO_CONTINUE_MSG}`; + default: + gameType = ``; + return `This is an invalid input. Please select between 1 to 5.`; + } +} + +function validateInput(playerChoice) { + if (gameType == KNOCKOUT_MODE && (isNaN(playerChoice) || playerChoice < 4)) { + return true; + } + if (isNaN(playerChoice) || playerChoice < 2) { + return true; + } +} + +function rollDice() { + return Math.floor(Math.random() * 6) + 1; +} + +function randomizeDiceRolls(numOfDice) { + const diceRolls = []; + let diceRollMsg = ``; + for (let diceCounter = 1; diceCounter <= numOfDice; diceCounter += 1) { + const diceRoll = rollDice(); + diceRolls.push(diceRoll); + diceRollMsg += `Dice ${diceCounter}: ${diceRoll}
`; + } + const playerIndex = currentPlayer - 1; + playersDiceRolls[playerIndex] = diceRolls; + if (aiMode) { + return `Welcome Player ${currentPlayer}. You rolled:

${diceRollMsg}
${SUBMIT_TO_CONTINUE_MSG}`; + } + return `Welcome Player ${currentPlayer}. You rolled:

${diceRollMsg}
Please choose the order of the dice by inputting 1 or 2.`; +} + +function compareByDescendingDiceResult(a, b) { + return b.diceResult - a.diceResult; +} + +function compareByAscendingDiceResult(a, b) { + return a.diceResult - b.diceResult; +} + +//helper function for checking winner / after all players roll +function checkForWinner() { + const checkResultsArray = playerProfiles.toSorted( + compareByDescendingDiceResult + ); + if (lowestCombinedMode) { + checkResultsArray.sort(compareByAscendingDiceResult); + } + const indexOneResult = checkResultsArray[0].diceResult; + const indexTwoResult = checkResultsArray[1].diceResult; + let diceResultsMsg = ``; + for ( + let playerCounter = 1; + playerCounter <= numberOfPlayers; + playerCounter += 1 + ) { + let playerIndex = playerCounter - 1; + diceResultsMsg += `Player ${playerCounter} chose ${playerProfiles[playerIndex].diceResult}.
`; + } + if (indexOneResult === indexTwoResult) { + return `${diceResultsMsg}
It's a draw!`; + } + return `${diceResultsMsg}
Player ${checkResultsArray[0].id} wins!`; +} + +//validate dice order input +function validateDiceOrderInput(playerChoice) { + if (playerChoice != 1 && playerChoice != 2) { + return true; + } +} + +//dice order selection - manual + 2 dice +function selectDiceOrderForTwo(playersDiceRolls, playerChoice) { + if (validateDiceOrderInput(playerChoice)) { + return `This is an invalid input. Please select 1 or 2.`; + } + const playerIndex = currentPlayer - 1; + const diceRolls = playersDiceRolls[playerIndex]; + const diceOne = Number(diceRolls[0]); + const diceTwo = Number(diceRolls[1]); + let diceResult; + if (playerChoice == 1) { + diceResult = diceOne * 10 + diceTwo; + } else if (playerChoice == 2) { + diceResult = diceTwo * 10 + diceOne; + } + playerProfiles[playerIndex].diceResult = diceResult; + playerProfiles[playerIndex].score += diceResult; + const diceResultMsg = `Player ${currentPlayer}, you chose Dice ${playerChoice} first.
Your number is ${diceResult}.
`; + currentPlayer = (currentPlayer % numberOfPlayers) + 1; + if (currentPlayer === 1) { + const endGame = checkForWinner(); + mode = END_GAME; + return `${diceResultMsg}
${endGame}`; + } + mode = START_TURN; + return `${diceResultMsg}
It is now Player ${currentPlayer}'s turn.`; +} + +//optimal dice choice if computer mode = true; +function automateDiceOrder(playersDiceRolls) { + const playerIndex = currentPlayer - 1; + const diceRolls = playersDiceRolls[playerIndex].toSorted(); + if (!lowestCombinedMode) { + diceRolls.reverse(); + } + const diceResultString = diceRolls.join(""); + const diceResult = Number(diceResultString); + playerProfiles[playerIndex].diceResult = diceResult; + playerProfiles[playerIndex].score += diceResult; + const diceResultMsg = `Player ${currentPlayer}, your number is ${diceResult}.
`; + currentPlayer = (currentPlayer % numberOfPlayers) + 1; + if (currentPlayer === 1) { + const endGame = checkForWinner(); + mode = END_GAME; + return `${diceResultMsg}
${endGame}`; + } + mode = START_TURN; + return `${diceResultMsg}
It is now Player ${currentPlayer}'s turn.`; +} + +//initializes setting for multi dice game +function initMultiDiceGame(playerChoice) { + numberOfPlayers = 2; + if (validateInput(playerChoice)) { + return `${INVALID_INPUT_MSG}`; + } + numberOfDice = playerChoice; + initPlayersData(numberOfPlayers); + mode = START_TURN; + return `The players have opted to roll ${numberOfDice} dices this round.`; +} + +function compareByDescendingScore(a, b) { + return b.score - a.score; +} + +function compareByAscendingScore(a, b) { + return a.score - b.score; +} + +function displayLeaderBoard() { + const leaderBoardArray = playerProfiles.toSorted(compareByAscendingScore); + if (!lowestCombinedMode) { + leaderBoardArray.sort(compareByDescendingScore); + } + const leadingPlayer = leaderBoardArray[0].id; + let leadPlayerMsg = `Player ${leadingPlayer} is leading! 😎

`; + if (leaderBoardArray[0].score == leaderBoardArray[1].score) { + leadPlayerMsg = `No one is in the lead at the moment. Try your best! ✌

`; + } + let leaderBoardMsg = ``; + for ( + let playerCounter = 0; + playerCounter < playerProfiles.length; + playerCounter += 1 + ) { + leaderBoardMsg += `Player ${leaderBoardArray[playerCounter].id}: ${leaderBoardArray[playerCounter].score}
`; + } + if (gameType == VARIABLE_DICE_NUM) { + mode = WAITING_FOR_DICE_COUNT; + return `${leadPlayerMsg} Leaderboard
${leaderBoardMsg}

Input the number of dice the players would like to play with next round. ${SUBMIT_TO_CONTINUE_MSG}`; + } + return `${leadPlayerMsg} Leaderboard
${leaderBoardMsg}

Press Submit to start a new round.`; +} + +//non KO gametypes logic +//play base, lowest combined or variable players +function playBaseGame(playerChoice) { + if (mode === ``) { + numberOfPlayers = 2; + numberOfDice = 2; + if (gameType == VARIABLE_PLAYER_NUM) { + if (validateInput(playerChoice)) { + return `${INVALID_INPUT_MSG}`; + } + numberOfPlayers = playerChoice; + } + initPlayersData(numberOfPlayers); + mode = START_TURN; + } + if (mode === START_TURN) { + const diceRollResult = randomizeDiceRolls(numberOfDice); + mode = SELECT_DICE_ORDER; + return `${diceRollResult}`; + } + if (mode === SELECT_DICE_ORDER) { + if (aiMode) { + const gameProgressMsg = automateDiceOrder(playersDiceRolls); + return gameProgressMsg; + } + const gameProgressMsg = selectDiceOrderForTwo( + playersDiceRolls, + playerChoice + ); + return gameProgressMsg; + } + if (mode === END_GAME) { + mode = START_TURN; + return displayLeaderBoard(); + } +} + +function playMultiDiceGame(playerChoice) { + if (mode == ``) { + return initMultiDiceGame(playerChoice); + } + if (mode === WAITING_FOR_DICE_COUNT) { + if (validateInput(playerChoice)) { + return `${INVALID_INPUT_MSG}`; + } + numberOfDice = playerChoice; + mode = START_TURN; + return `The players have opted to roll ${numberOfDice} dices this round.`; + } + if (mode == START_TURN) { + const diceRollResult = randomizeDiceRolls(numberOfDice); + mode = SELECT_DICE_ORDER; + return `${diceRollResult}`; + } + if (mode == SELECT_DICE_ORDER) { + const gameProgressMsg = automateDiceOrder(playersDiceRolls); + return gameProgressMsg; + } + if (mode === END_GAME) { + mode = START_TURN; + return displayLeaderBoard(); + } +} +//end non KO gametypes logic + +//KO game helper functions// + +//initializes each round of the KO game +function initKnockOutBracket(playerChoice) { + if (validateInput(playerChoice)) { + return `${INVALID_KO_MSG}`; + } + numberOfPlayers = playerChoice; + initPlayersData(numberOfPlayers); + const competitionArray = []; + const lowerBracket = []; + for ( + let playerCounter = 1; + playerCounter <= numberOfPlayers; + playerCounter += 1 + ) { + competitionArray.push(playerCounter); + } + for (let i = 0; i < numberOfPlayers / 2; i += 1) { + randomIndex = Math.random() * competitionArray.length; + const lowerBracketPlayers = competitionArray.splice(randomIndex, 1); + lowerBracket.push(lowerBracketPlayers[0]); + } + knockoutBrackets[0] = [...competitionArray]; + knockoutBrackets[1] = [...lowerBracket]; + return `${numberOfPlayers} players are taking part in this tournament 😎`; +} + +//random selection of players for KO game +function selectPlayersforBracket() { + if (knockoutBrackets[0].length == 1 && knockoutBrackets[1].length == 1) { + koPlayerOne = knockoutBrackets[0][0]; + koPlayerTwo = knockoutBrackets[1][0]; + currentPlayer = koPlayerOne; + return `Player ${koPlayerOne} and Player ${koPlayerTwo} are competing for the championship! ✌✌

Player ${koPlayerOne} will take the first turn.`; + } + let bracketIndex; + if (bracket == UPPER) { + bracketIndex = 0; + } else { + bracketIndex = 1; + } + const bracketPulls = knockoutBrackets[bracketIndex]; + const randomIndex = Math.random() * bracketPulls.length; + const koPlayerOneArr = bracketPulls.splice(randomIndex, 1); + koPlayerOne = koPlayerOneArr[0]; + const randomIndexTwo = Math.random() * bracketPulls.length; + const koPlayerTwoArr = bracketPulls.splice(randomIndexTwo, 1); + koPlayerTwo = koPlayerTwoArr[0]; + currentPlayer = koPlayerOne; + return `Player ${koPlayerOne} and Player ${koPlayerTwo} are up this time!

Player ${koPlayerOne} will take the first turn.`; +} + +//automates dice order for both players in each match for KO game, can be refactored alongside function ${automateDiceOrder} +function automateKoDiceOrder(playersDiceRolls) { + const playerIndex = currentPlayer - 1; + const diceRolls = playersDiceRolls[playerIndex].toSorted(); + if (!lowestCombinedMode) { + diceRolls.reverse(); + } + const diceResultString = diceRolls.join(""); + const diceResult = Number(diceResultString); + playerProfiles[playerIndex].diceResult = diceResult; + playerProfiles[playerIndex].score += diceResult; + const diceResultMsg = `Player ${currentPlayer}, your number is ${diceResult}.
`; + if (currentPlayer === koPlayerTwo) { + const endMatch = checkForKoWinner(); + return `${diceResultMsg}
${endMatch}`; + } + prevPlayer = koPlayerOne; + currentPlayer = koPlayerTwo; + mode = START_TURN; + return `${diceResultMsg}
It is now Player ${currentPlayer}'s turn.`; +} + +//inputs players who won into active player arrays +function insertWinningPlayers() { + let bracketIndex; + if (bracket == UPPER) { + bracketIndex = 0; + } else { + bracketIndex = 1; + } + const winningPlayers = knockoutBrackets[2].length; + for (let i = 0; i < winningPlayers; i += 1) { + const playerId = knockoutBrackets[2].shift(); + knockoutBrackets[bracketIndex].push(playerId); + } +} + +function displayRemainingPlayers() { + const upBracketPlayers = [...knockoutBrackets[0]].toSorted(); + const lowBracketPlayerCount = [...knockoutBrackets[1]].toSorted(); + return `- Championship Contenders -

Upper Bracket Players: ${upBracketPlayers}
Lower Bracket Players: ${lowBracketPlayerCount}`; +} + +//change brackets and manages byes/free wins -> need ideas to refactor +function checkBracketStatus() { + const upBracketCheck = knockoutBrackets[0].length; + const lowBracketCheck = knockoutBrackets[1].length; + const END_UP_BRACKET_MSG = `The upper bracket matches have ended. The lower bracket matches will now commence.`; + const END_LOW_BRACKET_MSG = `The lower bracket matches have ended. The upper bracket matches will now commence.`; + + if (bracket === LOWER) { + if (upBracketCheck == 1 && lowBracketCheck == 0) { + insertWinningPlayers(); + const playerCountMsg = displayRemainingPlayers(); + bracket = UPPER; + endKoGame = true; + return `And up next... our final contestants! 😍

${playerCountMsg}`; + } + if (upBracketCheck > 1 && lowBracketCheck == 1) { + const byePlayer = knockoutBrackets[1][0]; + insertWinningPlayers(); + const playerCountMsg = displayRemainingPlayers(); + bracket = UPPER; + return `Player ${byePlayer} has got a bye! ${END_LOW_BRACKET_MSG}

${playerCountMsg}`; + } + if (upBracketCheck > 1 && lowBracketCheck == 0) { + insertWinningPlayers(); + const playerCountMsg = displayRemainingPlayers(); + bracket = UPPER; + return `${END_LOW_BRACKET_MSG}

${playerCountMsg}`; + } + if (upBracketCheck == 1 && lowBracketCheck == 1) { + const byePlayer = knockoutBrackets[1][0]; + insertWinningPlayers(); + const playerCountMsg = displayRemainingPlayers(); + return `Player ${byePlayer} has got a bye! As the upper bracket has finished, the next match will be decisive for the lower bracket.

${playerCountMsg}`; + } + return `Onto the next match in the lower bracket 😁`; + } + if (upBracketCheck == 1 && lowBracketCheck > 1) { + const byePlayer = knockoutBrackets[0][0]; + insertWinningPlayers(); + const playerCountMsg = displayRemainingPlayers(); + bracket = LOWER; + return `Player ${byePlayer} has got a bye! ${END_UP_BRACKET_MSG}

${playerCountMsg}`; + } + if (upBracketCheck == 0 && lowBracketCheck > 1) { + insertWinningPlayers(); + const playerCountMsg = displayRemainingPlayers(); + bracket = LOWER; + return `${END_UP_BRACKET_MSG}

${playerCountMsg}`; + } + return `Onto the next match in the upper bracket 😁`; +} + +//checks for game results and pushes winner into holding area for winners +function checkForKoWinner() { + const prevPlayerIndex = prevPlayer - 1; + const playerIndex = currentPlayer - 1; + const indexOneResult = playerProfiles[prevPlayerIndex].diceResult; + const indexTwoResult = playerProfiles[playerIndex].diceResult; + let diceResultsMsg = `Player ${prevPlayer} chose ${indexOneResult}.
Player ${currentPlayer} chose ${indexTwoResult}. `; + if (indexOneResult === indexTwoResult) { + currentPlayer = prevPlayer; + mode = START_TURN; + return `${diceResultsMsg}
It's a draw! Time to roll again.

It is now Player ${prevPlayer}'s turn.`; + } + if (indexOneResult < indexTwoResult) { + if (endKoGame) { + mode = END_KO_GAME; + return `${diceResultsMsg}

Player ${prevPlayer} has been eliminated.
Player ${currentPlayer} is the final winner! 🏆🏆🏆`; + } + knockoutBrackets[2].push(currentPlayer); + mode = CHECK_BRACKET; + return `${diceResultsMsg}

Player ${prevPlayer} has been eliminated.
Player ${currentPlayer} advances to the next round!`; + } + if (endKoGame) { + mode = END_KO_GAME; + return `${diceResultsMsg}

Player ${currentPlayer} has been eliminated.
Player ${prevPlayer} is the final winner! 🏆🏆🏆`; + } + knockoutBrackets[2].push(prevPlayer); + mode = CHECK_BRACKET; + return `${diceResultsMsg}

Player ${currentPlayer} has been eliminated.
Player ${prevPlayer} advances to the next round!`; +} + +//resets all parameters of the KO game that can affect a new game +function resetKnockOutGame() { + mode = ``; + playerProfiles.splice(0); + playersDiceRolls.splice(0); + knockoutBrackets[0].splice(0); + knockoutBrackets[1].splice(0); + endKoGame = false; + numberOfPlayers = 0; + return `Game has been reset. To start a new game, input the number of players entering the knockout tournament! ${SUBMIT_TO_CONTINUE_MSG}`; +} + +//end KO game helper functions + +function playKnockoutGame(playerChoice) { + numberOfDice = 2; + if (mode == ``) { + mode = SELECTING_KO_PLAYERS; + return initKnockOutBracket(playerChoice); + } + + if (mode == SELECTING_KO_PLAYERS) { + if (numberOfPlayers != 0) { + mode = START_TURN; + return selectPlayersforBracket(); + } else { + return initKnockOutBracket(playerChoice); + } + } + + if (mode == START_TURN) { + const diceResult = randomizeDiceRolls(numberOfDice); + mode = SELECT_DICE_ORDER; + return `${diceResult}`; + } + if (mode == SELECT_DICE_ORDER) { + const gameProgressMsg = automateKoDiceOrder(playersDiceRolls); + return gameProgressMsg; + } + if (mode == CHECK_BRACKET) { + const bracketMsg = checkBracketStatus(); + mode = SELECTING_KO_PLAYERS; + return bracketMsg; + } + if (mode == END_KO_GAME) { + return resetKnockOutGame(); + } +} + +function main(input) { + let myOutputValue = ``; + if (gameType == ``) { + gameType = SELECTION_MODE; + return inquireGameType(); + } + if (gameType == SELECTION_MODE) { + return selectGameType(input); + } + if (gameType == BASE || gameType == VARIABLE_PLAYER_NUM) { + const baseGame = playBaseGame(input); + myOutputValue = baseGame; + } + if (gameType == VARIABLE_DICE_NUM) { + const multiDiceGame = playMultiDiceGame(input); + myOutputValue = multiDiceGame; + } + if (gameType == KNOCKOUT_MODE) { + const knockoutGame = playKnockoutGame(input); + myOutputValue = knockoutGame; + } return myOutputValue; -}; +}