Home > Software engineering >  What is wrong with my Rock Paper Scissors app?
What is wrong with my Rock Paper Scissors app?

Time:02-21

I've been trying to turn my old JavaScript learning projects into intractable web applications now that I am learning the DOM. It has been a while since I wrote a basic JavaScript script like this, so I am likely missing something obvious here, but my program outputs the last line in my game algorithm regardless of the user choice ('Rock beats scissors. You lose.'), and the computer score updates in increments of three. This is obviously not what I intended.

I believe it is fairly intuitive what the output should be, but I've included comments in my JavaScript file to highlight the desired output (game should follow the conventional rules of Rock Paper Scissors). Apologies if the interface looks jumbled, I designed it to spec for a 15.6" screen and haven't worked out cross-user functionality yet.

//HTML elements saved as JS variables
let rock = document.getElementById("rock");
let paper = document.getElementById("paper");
let scissors = document.getElementById("scissors");
let gameResults = document.getElementById("gameResults");
let scoreboard = document.getElementById("scoreboard")

/*Generates a random number between 0 and 2 to be substituted for rock, paper, or scissors, respectively.*/
const getComputerChoice = () => {
    // Rock is 0; Paper is 1; Scissors is 2.
    let choice = Math.floor(Math.random() * 3);
    return choice;
};

/*Player and computer scores which update the "scoreboard" element id; score should update in increments of one.*/
let playerScore = 0;
let computerScore = 0;

/*Game algorithm which should return a random choice from the computer and update the "gameResults" element id, according to the standard rules of Rock Paper Scissors, when interacted with through the event listeners at the bottom of the program.*/
const game = () => {
    let playerChoice;
    let computerChoice = getComputerChoice();

    if (playerChoice === computerChoice) {
        gameResults.innerHTML = 'You tied!';
        playerScore  ;
        computerScore  ;
    }

    if (playerChoice === rock && computerChoice === 2) {
        gameResults.innerHTML = 'Rock beats scissors. You win!'
        playerScore  ;
    } else {
        gameResults.innerHTML = 'Paper covers rock. You lose.'
        computerScore  ;
    }

    if (playerChoice === paper && computerChoice === 0) {
        gameResults.innerHTML = 'Paper covers rock. You win!'
        playerScore  ;
    } else {
        gameResults.innerHTML = 'Scissors cuts paper. You lose.'
        computerScore  ;
    }

    if (playerChoice === scissors && computerChoice === 1) {
        gameResults.innerHTML = 'Scissors cuts paper. You win!'
        playerScore  ;
    } else {
        gameResults.innerHTML = 'Rock beats scissors. You lose.'
        computerScore  ;
    }

    scoreboard.innerHTML = `Player: ${playerScore} | Computer: ${computerScore}`
};

//Event listeners
rock.addEventListener("click", game);
paper.addEventListener("click", game);
scissors.addEventListener("click", game);
body {
    background-image: url("pexels-pixabay-326311.jpg");
}

p {
    color: white;
    text-align: center;
}

#gameHeader {
    font-family: 'Shizuru', cursive, serif, sans-serif;
    font-size: 75px;
    border: 3px solid white;
    padding-bottom: 20px;
    margin-left: 350px;
    margin-right: 350px;
}

#gameResults {
    font-family: 'Rowdies', cursive, serif, sans-serif;
    font-size: 50px;
}

#scoreboard {
    font-family: 'Rowdies', cursive, serif, sans-serif;
    font-size: 20px;
    background-color: black;
    margin-left: 600px;
    margin-right: 600px;
    border: 2px solid white;
    border-radius: 50px;
    padding: 5px;
}

.results {
    position: relative;
    top: 100px;
}

label {
    font-family: 'Roboto Mono', sans-serif, serif;
    font-size: 25px;
    color: white;
}

.labels {
    display: inline-flexbox;
    margin-top: 20px;
}

#rockLabel {
    border: 2px solid white;
    border-radius: 10px;
    padding: 5px;
    position: fixed;
    left: 520px;
    background-color: black;
}

#paperLabel {
    border: 2px solid white;
    border-radius: 10px;
    padding: 5px;
    position: fixed;
    left: 722px;
    background-color: black;
}

#scissorsLabel {
    border: 2px solid white;
    border-radius: 10px;
    padding: 5px;
    position: fixed;
    left: 915px;
    background-color: black;
}


#rock {
    background-image: url("Rock.jpeg");
    background-color: white;
    background-position: center;
    background-size: contain;
    padding: 50px;
    border: 3px solid black;
    border-radius: 50px;
}

#paper {
    background-image: url("Papers.jpg");
    background-color: white;
    background-position: center;
    background-size: contain;
    padding: 50px;
    border: 3px solid black;
    border-radius: 50px;
    margin-left: 100px;
    margin-right: 100px;
}

#scissors {
    background-image: url("Scissors.jpg");
    background-position: center;
    background-size: contain;
    padding: 50px;
    border: 3px solid black;
    border-radius: 50px;
}
<!DOCTYPE html>
<html lang="en">

<head>

    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Rock Paper Scissors</title>
    <link rel="stylesheet" href="Rock-Paper-Scissors.css">
    <script src="Rock-Paper-Scissors.js" async></script>
    
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Marko One&family=Orbitron&family=Roboto Mono:wght@100&family=Rowdies:wght@300&family=Saira Condensed:wght@100&family=Shizuru&family=Supermercado One&display=swap" rel="stylesheet"> 

</head>

<body>

    <header>
        <p id="gameHeader">Rock Paper Scissors</p>
    </header>

    <div >
        <center>
            <button id="rock"></button>
            <button id="paper"></button>
            <button id="scissors"></button>
        </center>
    </div>

    <div >
        <label for="rock" id="rockLabel">Rock</label>
        <label for="paper" id="paperLabel">Paper</label>
        <label for="scissors" id="scissorsLabel">Scissors</label>
    </div>

    <div >
        <p id="gameResults">Try your luck!</p>
        <p id="scoreboard">Player: 0 | Computer: 0</p>
    </div>
    
</body>

</html>

CodePudding user response:

you need to add player choice.

in HTML code

<button data-choice="0" id="rock"></button>
<button data-choice="1" id="paper"></button>
<button data-choice="2" id="scissors"></button>

in game function

const game = (event) => {
let playerChoice = event.currentTarget.dataset.choice;

CodePudding user response:

The logic in your game() function is slightly off. Namely, if you want to use the else condition, it needs to be nested, otherwise it executes every time the primary condition is not met.

Also, for the case where the results are tied, it looks as though you are comparing an undefined value of playerChoice with an integer value of computerChoice. I have commented this line out and amended your event listeners to pass a pcValue (0, 1 or 2) to your method.

Have a look below.

const game = (playerChoice, pcValue) => {

    // let playerChoice;
    let computerChoice = getComputerChoice();

    if(pcValue === computerChoice) {
        gameResults.innerHTML = 'You tied!';
        playerScore  ;
        computerScore  ;
    } else {

        if(playerChoice === rock) {
            if(computerChoice === 2) {
                gameResults.innerHTML = 'Rock beats scissors. You win!'
                playerScore  ;
            } else {
                gameResults.innerHTML = 'Paper covers rock. You lose.'
                computerScore  ;
            }
        }

        if(playerChoice === paper) {
            if(computerChoice === 0) {
                gameResults.innerHTML = 'Paper covers rock. You win!'
                playerScore  ;
            } else {
                gameResults.innerHTML = 'Scissors cuts paper. You lose.'
                computerScore  ;
            }
        }

        if(playerChoice === scissors) {
            if(computerChoice === 1) {
                gameResults.innerHTML = 'Scissors cuts paper. You win!'
                playerScore  ;
            } else {
                gameResults.innerHTML = 'Rock beats scissors. You lose.'
                computerScore  ;
            }
        }
    }

    scoreboard.innerHTML = `Player: ${playerScore} | Computer: ${computerScore}`
};

I have also amended your event listeners so that your button clicks pass the element clicked on and a value to game function, which can then be used to track the score.

//Event listeners
rock.addEventListener("click", evt => game(rock, 0));
paper.addEventListener("click", evt => game(paper, 1));
scissors.addEventListener("click", evt => game(scissors, 2));

This should now work.

CodePudding user response:

Let's reduce a lot of the replicated logic and use a single event listener on the button group, then leverage event delegation.

Most importantly, assign a value to player choice

//HTML elements saved as JS variables
let rock = document.getElementById("rock");
let paper = document.getElementById("paper");
let scissors = document.getElementById("scissors");
let gameResults = document.getElementById("gameResults");
let scoreboard = document.getElementById("scoreboard");

/*Set up a matirx of results */
let gameMatrix = {
  "rock": {
    "defeats": "scissors",
    "action": "smashes"
  },
  "paper": {
    "defeats": "rock",
    "action": "covers"
  },
  "scissors": {
    "defeats": "paper",
    "action": "cuts"
  }
};

/*Computer options*/
let computerChoices = ["rock", "paper", "scissors"];

/*Generates a random number between 0 and 2 to be substituted for rock, paper, or scissors, respectively.*/
const getComputerChoice = () => {
  // Rock is 0; Paper is 1; Scissors is 2.
  let choice = Math.floor(Math.random() * 3);
  //Get actual name to use as a key
  return computerChoices[choice];
}

/*Player and computer scores which update the "scoreboard" element id; score should update in increments of one.*/
let playerScore = 0;
let computerScore = 0;

/*Game algorithm which should return a random choice from the computer and update the "gameResults" element id, according to the standard rules of Rock Paper Scissors, when interacted with through the event listeners at the bottom of the program.*/
/*Use event delegation from button group*/
const game = (event) => {
  //Check it's a button
  if (event.target.matches("button")) {
    //get player choince from id
    let playerChoice = event.target.id;
    let computerChoice = getComputerChoice();
    let result;
    console.log(`C: ${computerChoice}, P: ${playerChoice}`);

    //Check for a tie
    if (playerChoice === computerChoice) {
      result = 'You tied!';
      playerScore  ;
      computerScore  ;
      //From the matrix, check if player defets computer choice
    } else if (gameMatrix[playerChoice].defeats === computerChoice) {
      playerScore  ;
      //Set the result using the action from the matrix
      result = `You win, ${playerChoice} ${gameMatrix[playerChoice].action} ${computerChoice}`;
    } else {
      computerScore  ;
      //Set the result usig the action  from the matrix but using the computer choice instead
      result = `You lose, ${computerChoice} ${gameMatrix[computerChoice].action} ${playerChoice}`;
    }

    console.log(result);
    gameResults.innerHTML = result;
    scoreboard.innerHTML = `Player: ${playerScore} | Computer: ${computerScore}`
  }
};

//Event listeners- sust to the group holding the button
document.querySelector(".buttons").addEventListener("click", game);
body {
  background-image: url("pexels-pixabay-326311.jpg");
}

p {
  color: white;
  text-align: center;
}

#gameHeader {
  font-family: 'Shizuru', cursive, serif, sans-serif;
  font-size: 75px;
  border: 3px solid white;
  padding-bottom: 20px;
  margin-left: 350px;
  margin-right: 350px;
}

#gameResults {
  font-family: 'Rowdies', cursive, serif, sans-serif;
  font-size: 50px;
  background-color: #EEE;
}

#scoreboard {
  font-family: 'Rowdies', cursive, serif, sans-serif;
  font-size: 20px;
  background-color: black;
  margin-left: 600px;
  margin-right: 600px;
  border: 2px solid white;
  border-radius: 50px;
  padding: 5px;
}

.results {
  position: relative;
  top: 100px;
}

label {
  font-family: 'Roboto Mono', sans-serif, serif;
  font-size: 25px;
  color: white;
}

.labels {
  display: inline-flexbox;
  margin-top: 20px;
}

/*Set a standard class for the labels*/
.labels label{
border: 2px solid white;
  border-radius: 10px;
  padding: 5px;
  position: fixed;
  left: 520px;
  background-color: black;
}

/*Now just set what is needed*/
#rockLabel {
  left: 520px;
}

#paperLabel {
  left: 722px;
}

#scissorsLabel {
  left: 915px;
}

/*Set a standard class for the buttons*/
.buttons button{
  background-color: white;
  background-position: center;
  background-size: contain;
  padding: 50px;
  border: 3px solid black;
  border-radius: 50px;

}


/*Now just set what is needed*/
#rock {
  background-image: url("Rock.jpeg");
}

#paper {
  background-image: url("Papers.jpg");
  margin-left: 100px;
  margin-right: 100px;
}

#scissors {
  background-image: url("Scissors.jpg");
}
<!DOCTYPE html>
<html lang="en">

<head>

  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <title>Rock Paper Scissors</title>
  <link rel="stylesheet" href="Rock-Paper-Scissors.css">
  <script src="Rock-Paper-Scissors.js" async></script>

  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Marko One&family=Orbitron&family=Roboto Mono:wght@100&family=Rowdies:wght@300&family=Saira Condensed:wght@100&family=Shizuru&family=Supermercado One&display=swap" rel="stylesheet">

</head>

<body>

  <header>
    <p id="gameHeader">Rock Paper Scissors</p>
  </header>

  <div >
    <center>
      <button id="rock"></button>
      <button id="paper"></button>
      <button id="scissors"></button>
    </center>
  </div>

  <div >
    <label for="rock" id="rockLabel">Rock</label>
    <label for="paper" id="paperLabel">Paper</label>
    <label for="scissors" id="scissorsLabel">Scissors</label>
  </div>

  <div >
    <p id="gameResults">Try your luck!</p>
    <p id="scoreboard">Player: 0 | Computer: 0</p>
  </div>

</body>

</html>

  • Related