Rock, Paper, Scissors game using Javascript - javascript

I'm attempting a Rock, Paper, Scissors game using Javascript. I'm new to Javascript, so I don't know much. Each time I click a button I can get the values both for playerSelection and computerSelection but when I try to run the function playRound() it seems like it can't "reach" the values returned by clicking the buttons. What am I doing wrong?
const selectionButtons = document.querySelectorAll('[data-selection]')
const options = ['rock', 'paper', 'scissors']
function computerPlay() {
const random = options[Math.floor(Math.random() * options.length)];
console.log(random)
return random
}
function playerSelection() {
selectionButtons.forEach(selectionButton => {
selectionButton.addEventListener('click', e => {
const selected = selectionButton.dataset.selection
console.log(selected)
return selected
})
})
}
function computerSelection() {
selectionButtons.forEach(selectionButton => {
selectionButton.addEventListener('click', e => {
computerPlay()
})
})
}
const playerSelected = playerSelection()
const computerSelected = computerSelection()
function playRound() {
if (playerSelected == 'rock' && computerSelected == 'rock' ||
playerSelected == 'paper' && computerSelected == 'paper' ||
playerSelected == 'scissors' && computerSelected == 'scissors') {
console.log('tie')
}
else if (playerSelected == 'rock' && computerSelected == 'scissors' ||
playerSelected == 'paper' && computerSelected == 'rock' ||
playerSelected == 'scissors' && computerSelected == 'paper') {
console.log('player won')
}
else {
console.log('player lose')
}
}
playRound()
* {
font-style: arial;
background-color: lightblue;
margin:0;
padding:0;
}
.scores {
display:grid;
grid-template-columns: repeat(2, 1fr);
justify-items: center;
justify-content: center;
align-items: center;
margin-top: 2rem;
}
.selection {
cursor: pointer;
background-color: red;
font-size: 1rem;
transition:500ms;
}
.selection:hover {
transform: scale(1.3)
}
.header {
text-align: center;
margin-top:0;
font-size: 2rem;
}
.selections {
display: flex;
justify-content: space-around;
margin-top: 5rem;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="styles.css">
<script src="script.js" defer></script>
</head>
<body>
<div class="header">
Choose your option:
</div>
<div class="selections">
<button class="selection" data-selection="rock">Rock</button>
<button class="selection" data-selection="paper">Paper</button>
<button class="selection" data-selection="scissors">Scissors</button>
</div>
<div class="scores">
<div>
Player Score
<span>0</span>
</div>
<div>
Computer Score
<span>0</span>
</div>
</body>
</html>

There are a couple issues here. First off, you are calling the playRound() function before any buttons are pressed. It's called on load of the script and then never again. What you'd need to do is to call playRound() inside your click handler because that is the event which you need to test if the user won, lost, or tied.
Secondly, you are trying to return values from a click handler inside a .forEach, neither of which by definition return a value to their caller.
I think your best bet to solve this is to do a couple things:
Move your computerPlay() into your click handler
Move your playRound() into your click handler
Here's an example of what it would look like:
const selectionButtons = document.querySelectorAll('[data-selection]')
const options = ['rock', 'paper', 'scissors']
function computerPlay() {
const random = options[Math.floor(Math.random() * options.length)];
return random
}
selectionButtons.forEach(selectionButton => {
selectionButton.addEventListener('click', e => {
const selected = selectionButton.dataset.selection;
const computerSelected = computerPlay();
console.log("Player Selection: " + selected);
console.log("Computer Selection: " + computerSelected);
playRound(selected, computerSelected);
})
})
function playRound(playerSelected, computerSelected) {
if (playerSelected == 'rock' && computerSelected == 'rock' ||
playerSelected == 'paper' && computerSelected == 'paper' ||
playerSelected == 'scissors' && computerSelected == 'scissors') {
console.log('tie')
}
else if (playerSelected == 'rock' && computerSelected == 'scissors' ||
playerSelected == 'paper' && computerSelected == 'rock' ||
playerSelected == 'scissors' && computerSelected == 'paper') {
console.log('player won')
}
else {
console.log('player lose')
}
}
* {
font-style: arial;
background-color: lightblue;
margin:0;
padding:0;
}
.scores {
display:grid;
grid-template-columns: repeat(2, 1fr);
justify-items: center;
justify-content: center;
align-items: center;
margin-top: 2rem;
}
.selection {
cursor: pointer;
background-color: red;
font-size: 1rem;
transition:500ms;
}
.selection:hover {
transform: scale(1.3)
}
.header {
text-align: center;
margin-top:0;
font-size: 2rem;
}
.selections {
display: flex;
justify-content: space-around;
margin-top: 5rem;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="styles.css">
<script src="script.js" defer></script>
</head>
<body>
<div class="header">
Choose your option:
</div>
<div class="selections">
<button class="selection" data-selection="rock">Rock</button>
<button class="selection" data-selection="paper">Paper</button>
<button class="selection" data-selection="scissors">Scissors</button>
</div>
<div class="scores">
<div>
Player Score
<span>0</span>
</div>
<div>
Computer Score
<span>0</span>
</div>
</body>
</html>

Related

Why is my rock paper scissors not working on the first click, the game works fine but the first click does nothing

As explained in the title, for some reason the first time you click it doesn't work but the second click goes through and the game works fine onwards, can anyone explain why? can't figure it out with my noob brain:
The game logic works perfectly fine, I know I've gone about it in a roundabout way but forgive me I'm still a noob and plan to keep iterating on this to make it more efficient.
Am I applying the styling to display the results in the wrong place or can you point me to why its not instantly starting the game?
const pickIcon = document.getElementsByClassName('icons');
const pickWord = document.getElementsByClassName('word-choice');
const rockWord = document.getElementById('rock-word');
const paperWord = document.getElementById('paper-word');
const scissorsWord = document.getElementById('scissors-word');
// const resultContainer = document.getElementById('result');
let picksDisplay = document.getElementById('picks');
let resultDisplay = document.getElementById('winner-result');
let resultShow = document.getElementById('result-game');
let userPickIcon = ''
let userPick = ''
let compPick = ''
function playGame() {
//player pick
for (let i = 0; i < pickIcon.length; i++) {
pickIcon[i].addEventListener('click', function() {
document.getElementById('result').style.display = 'block';
if (pickIcon[i] === pickIcon[0] || pickIcon[i] === pickIcon[3]) {
userPickIcon = 'rock'
picksDisplay.innerText = `Player picked ${userPickIcon}`
} else if (pickIcon[i] === pickIcon[1] || pickIcon[i] === pickIcon[4]) {
userPickIcon = 'paper'
picksDisplay.innerText = `Player picked ${userPickIcon}`
} else if (pickIcon[i] === pickIcon[2] || pickIcon[i] === pickIcon[5]) {
userPickIcon = 'scissors'
picksDisplay.innerText = `Player picked ${userPickIcon}`
}
})
}
// computer randomised pick
let computerChoice = Math.floor(Math.random() * 3);
if (computerChoice === 0) {
compPick = 'rock'
resultDisplay.innerText = `Computer picked ${compPick}`
} else if (computerChoice === 1) {
compPick = 'paper'
resultDisplay.innerText = `Computer picked ${compPick}`
} else if (computerChoice === 2) {
compPick = 'scissors'
resultDisplay.innerText = `Computer picked ${compPick}`
}
//gamelogic
if (userPickIcon === compPick) {
resultShow.innerText = `The game is a tie!!!`
} else {
if (userPickIcon === 'rock') {
if (compPick === 'paper') {
resultShow.innerText = `Computer is the winner, Sorry :(`
} else {
resultShow.innerText = `The Player is the winner, Congratulations!!`
}
};
if (userPickIcon === 'paper') {
if (compPick === 'scissors') {
resultShow.innerText = `Computer is the winner, Sorry :(`
} else {
resultShow.innerText = `The Player is the winner, Congratulations!!`
}
};
if (userPickIcon === 'scissors') {
if (compPick === 'rock') {
resultShow.innerText = `Computer is the winner, Sorry :(`
} else {
resultShow.innerText = `The Player is the winner, Congratulations!!`
}
}
}
}
document.addEventListener('click', playGame);
#import url('https://fonts.googleapis.com/css2?family=Montserrat:wght#400;500&family=Roboto+Mono&display=swap');
body {
background-color: #16213E;
font-family: 'Montserrat', sans-serif;
text-align: center;
}
.container {
background-color: #fff;
margin: 40px auto;
width: 500px;
color: #16213E;
}
.icons-div {
display: flex;
align-items: center;
justify-content: center;
}
i {
padding: 25px;
font-size: 70px;
color: #277BC0;
}
i:hover {
color: #1CD6CE;
cursor: pointer;
}
.word-choice:hover {
color: #1CD6CE;
cursor: pointer;
}
.title-div {
background-color: #277BC0;
padding: 10px 0;
color: #fff;
}
.results {
background-color: #fff;
width: 500px;
margin: 40px auto;
height: 200px;
display: none;
}
.result-items {
padding-top: 20px;
color: #16213E;
}
#result-game {
color: #495C83;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css" integrity="sha512-xh6O/CkQoPOWDdYTDqeRdPCVd1SpvCA9XXcUnZS2FmJNp1coAFzvtCN9BmamE+4aHK8yyUHUSCcJHgXloTyT2A==" crossorigin="anonymous" referrerpolicy="no-referrer"
/>
<div class="container">
<div class="title-div">
<h2>Rock, Paper, Scissors</h2>
</div>
<div class="choices-title">
<h2>Make your choice</h2>
</div>
<div class="icons-div">
<table>
<tr>
<td><i class="fa-solid fa-hand-back-fist icons" id="rock-btn"></i></td>
<td><i class="fa-solid fa-hand icons" id="paper-btn"></i></td>
<td><i class="fa-solid fa-hand-scissors icons" id="scissors-btn"></i></td>
</tr>
<tr>
<td>
<h3 id="rock-word" class="word-choice icons">Rock</h3>
</td>
<td>
<h3 id="paper-word" class="word-choice icons">Paper</h3>
</td>
<td>
<h3 id="scissors-word" class="word-choice icons">Scissors</h3>
</td>
</tr>
</table>
</div>
</div>
<div class="results" id="result">
<div class="result-items">
<h3 id="picks"></h3>
<h3 id="winner-result"></h3>
<h2 id="result-game"></h2>
</div>
</div>
You added an eventListener to the whole document: document.addEventListener('click', playGame);
Which then calls the function playGame if anything is clicked. playGame function adds the eventListeners to your rock, paper and scissors only after you made your first click that called playGame.
As I stated already in the comments, there are a lot of issues. I not going to fix every issue such as semantics and accessibility issues as this would blow the proportion of an answer (take it as a hint to read into it and work on it in the future).
You had a text and an icon that could be clicked. This means while you still have only 3 choices to make you had 6 elements that you could click on. This overcomplicated the necessary logic. In other words, you had twice as many elements to check than necessary. I change it now that the eventListener listen to the container that contains an icon and the text.
You selected all the elements to check for the eventListener by using getElementsByClassName. This unfortunately returns an HTML Collection Object. As such you had to iterate through that object with a for-loop. This is highly inefficient and overcomplicated the issue as well. The smart and clean solution is to use querySelectorAll which will return a Node-List. The NodeList can be iterated with forEach which works faster and is shorter than a for-loop.
You nested a lot of if/else-statements. This is inefficient which a switch-statement and/or a ternary conditional operator can fix.
Now to the actual issue:
You have the entire logic running in a function. The eventListener is inside the function. So you have to click in your document first to run the function that then will start listing to the click events of the choices. That's why you need the extra click at the start.
If you programmed clean as described above you have the EventListener at the front and start the function when one of the choices is clicked on. That's what I meant in the comments, if you fix your major issues with your script performance-wise, the actual issue will resolve itself.
document.querySelectorAll('button').forEach(el =>
el.addEventListener('click', function(e) {
let playerChoice = e.currentTarget.id;
let userPick = '';
let computerPick = '';
// Get User Pick
switch (playerChoice) {
case 'rock-btn':
userPick = 'Rock';
break;
case 'paper-btn':
userPick = 'Paper';
break;
case 'scissors-btn':
userPick = 'Scissors';
break;
};
document.querySelector('#picks').textContent = `Player picked ${userPick}`;
// computer randomised pick
let computerChoice = Math.floor(Math.random() * 3);
switch (computerChoice) {
case 0:
computerPick = 'Rock';
break;
case 1:
computerPick = 'Paper';
break;
case 2:
computerPick = 'Scissors';
break;
};
document.querySelector('#winner-result').textContent = `Computer picked ${computerPick}`;
// game logic to check who wins;
let result = '';
if (userPick === computerPick) {
result = 'draw';
} else {
switch (userPick) {
case 'Rock':
result = (computerPick === 'Scissors') ? 'win' : 'lose';
break;
case 'Paper':
result = (computerPick === 'Rock') ? 'win' : 'lose';
break;
case 'Scissors':
result = (computerPick === 'Paper') ? 'win' : 'lose';
break;
};
};
// output for winner
let resultText = '';
switch (result) {
case 'draw':
resultText = 'The game is a tie!!!';
break;
case 'win':
resultText = 'The Player is the winner, Congratulations!!';
break;
case 'lose':
resultText = 'The Computer is the winner, Sorry :(';
break;
};
document.querySelector('#result-game').textContent = resultText;
// makes the result box visible
document.querySelector('#result').classList.remove('d-none');
})
)
#import url('https://fonts.googleapis.com/css2?family=Montserrat:wght#400;500&family=Roboto+Mono&display=swap');
body {
background-color: #16213E;
font-family: 'Montserrat', sans-serif;
text-align: center;
}
.container {
background-color: #fff;
margin: 40px auto;
width: 500px;
color: #16213E;
}
.icons-div {
display: flex;
align-items: center;
justify-content: center;
}
i {
padding: 25px;
font-size: 70px;
color: #277BC0;
}
button {
border: none;
background: transparent;
}
.icons-div > button:hover,
.icons-div > button:hover i,
.icons-div > button:hover h3 {
color: #1CD6CE;
cursor: pointer;
}
.title-div {
background-color: #277BC0;
padding: 10px 0;
color: #fff;
}
.results {
background-color: #fff;
width: 500px;
margin: 40px auto;
height: 200px;
}
.result-items {
padding-top: 20px;
color: #16213E;
}
.d-none {
display: none;
}
#result-game {
color: #495C83;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css" integrity="sha512-xh6O/CkQoPOWDdYTDqeRdPCVd1SpvCA9XXcUnZS2FmJNp1coAFzvtCN9BmamE+4aHK8yyUHUSCcJHgXloTyT2A==" crossorigin="anonymous" referrerpolicy="no-referrer"
/>
<div class="container">
<div class="title-div">
<h2>Rock, Paper, Scissors</h2>
</div>
<div class="choices-title">
<h2>Make your choice</h2>
</div>
<div class="icons-div">
<button id="rock-btn">
<i class="fa-solid fa-hand-back-fist icons"></i>
<h3 class="word-choice icons">Rock</h3>
</button>
<button id="paper-btn">
<i class="fa-solid fa-hand icons"></i>
<h3 class="word-choice icons">Paper</h3>
</button>
<button id="scissors-btn">
<i class="fa-solid fa-hand-scissors icons"></i>
<h3 class="word-choice icons">Scissors</h3>
</button>
</div>
</div>
<div class="results d-none" id="result">
<div class="result-items">
<h3 id="picks"></h3>
<h3 id="winner-result"></h3>
<h2 id="result-game"></h2>
</div>
</div>

How to get keyboard/key selection to work in JavaScript

I am trying to build a simple sound machine with various sounds only using JavaScript, specifically, Zelda Ocarina of Time sounds. Yes, I know it's basic stuff, but I am still learning and can't for the life of me figure this out.
Now, I can get the left and right arrow keys to cycle through the choices, but when I use the keys: A,S,D,F,G, or H I can't get them to make a selection. No matter how many avenues I have tried.
Any help, tips, pointers, or ANYTHING constructive would be appreciated.
Sound Machine in browser
CODE:
const regions = Array.from(document.querySelectorAll('section[role="region"]'));
const keys = Array.from(document.querySelectorAll('#keys button'))
const keyTypes = keys.map(op => op.innerHTML);
const moveFocus = (region, item) => {
region[item].focus();
}
const handleArrowEvent = (event, items, currentRegion) => {
let currentItem =0;
if(
event.code === 'ArrowLeft' ||
event.code === 'ArrowRight' ||
event.code === 'KeyA' ||
event.code === 'KeyS' ||
event.code === 'KeyD' ||
event.code === 'KeyF' ||
event.code === 'KeyG' ||
event.code === 'KeyH'
) {
event.preventDefault();
event.stopPropagation();
console.log(event.target);
const regionItems = Array.from(currentRegion.children);
regionItems.forEach(child => {
items.push(child)
})
currentItem = items.indexOf(event.target);
const lastItem = items.length - 1;
const isFirst = currentItem === 0;
const isLast = currentItem === lastItem;
if(event.code === 'ArrowRight') {
currentItem = isLast ? 0 : currentItem + 1;
} else if (event.code === 'ArrowLeft') {
currentItem = isFirst ? lastItem : currentItem - 1;
}
moveFocus(regionItems, currentItem)
}
}
const handleClick = event => {
registerInput(event.target.innerHTML)
}
const handleKeyEvent = event => {
const items = [];
const currentRegion = event.target.closest('section[role="region"]')
if (
event.code === 'ArrowLeft' ||
event.code === 'ArrowRight' ||
event.code === 'KeyA' ||
event.code === 'KeyS' ||
event.code === 'KeyD' ||
event.code === 'KeyF' ||
event.code === 'KeyG' ||
event.code === 'KeyH'
) { handleArrowEvent(event, items, currentRegion) }
}
const registerInput = input => {
console.log(input)
}
#import url('https://fonts.googleapis.com/css2?family=Bangers&family=Heebo:wght#300&family=Press+Start+2P&display=swap');
html {
font-size: 10px;
background-image: url(../assets/img/lofz_ocTime.jpg);
background-size: cover;
}
body , html {
margin: 0;
padding: 0;
font-family: 'Bangers', cursive;
font-size: 12px;
}
#keys {
display: flex;
flex: 1;
min-height: 80vh;
align-items: center;
justify-content: center;
}
button {
border: .4rem solid rgb(255, 5, 5);
border-radius: .5rem;
margin: 1rem;
font-size: 1.5rem;
padding: 1rem .5rem;
transition: all 0.07s ease;
width: 10rem;
text-align: center;
color: rgb(31, 240, 3);
background: rgba(8, 7, 94, 0.753);
font-weight: bold;
text-shadow: 0 0 .5rem black;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./css/stylesheet.css">
<link rel="stylesheet" href="./css/normalize.css">
<title>Zelda: Ocarina of Time Sounds</title>
</head>
<body>
<section id="keys" aria-label="Zelda Sounds" role="region">
<button data-key="65" class="sound" class="key" aria-label="Key A">A<aside>Hey! Over Here!</aside></button>
<button data-key="83" class="sound" class="key" aria-label="Key S">S<aside>Link, Listen!</aside></button>
<button data-key="68" class="sound" class="key" aria-label="Key D">D<aside>Gold Skulltula</aside></button>
<button data-key="70" class="sound" class="key" aria-label="Key F">F<aside>Item Found!</aside></button>
<button data-key="71" class="sound" class="key" aria-label="Key G">G<aside>Silver Rupee</aside></button>
<button data-key="72" class="sound" class="key" aria-label="Key H">H<aside>Found a Heart!</aside></button>
</section>
<script src="js/main.js" type="module" defer></script>
</body>
</html>
you should try listening to keyboard input using 'keydown' event
document.addEventListener('keydown', function(e) {
if(e.code == "KeyA") {
console.log('A was pressed');
}
});
You can find the code for the key you want to listen using this website with the event.code value :
https://www.toptal.com/developers/keycode
Hope it helps !

My switch statement prints default everytime - It's a simple rock,paper,scissors game

This is my code - can anyone see, what I am executing wrong. If i use the 'win();' within function 'main' then the score updates, same with 'lose();' I am a beginner, only 3 months of practice so I can't see where I am going wrong. Can someone point the way. I have enclosed HTML, CSS and Javascript so you can see what each function should be doing.
let playerScore = 0;
let computerScore = 0;
let playerScore_span = document.getElementById("user-score");
let computerScore_span = document.getElementById("computer-score");
const scoreplace_div = document.querySelector(".score-place");
const rock_div = document.getElementById("ro");
const paper_div = document.getElementById("pa");
const scissors_div = document.getElementById("sc");
function win(player, computer) {
playerScore++;
playerScore_span.innerHTML = playerScore;
computerScore_span.innerHTML = computerScore;
}
function lose(computer, player) {
computerScore++;
computerScore_span.innerHTML = computerScore;
playerScore_span.innerHTML = playerScore;
}
function draw() {
console.log("draw");
}
let playerSelection;
let computerSelection;
function compChoice() {
let computerMove;
const words = ["ro", "pa", "sc"];
computerMove = words[Math.floor(Math.random() * 3)];
return computerMove;
}
function game(playerSelection, computerSelection) {
let computerMove = compChoice();
switch (playerSelection + computerSelection) {
case "paro":
case "rosc":
case "scpa":
win();
break;
case "ropa":
case "pasc":
case "scro":
lose();
break;
case "roro":
case "papa":
case "scsc":
draw();
break;
default:
console.log("it's fudged mate");
}
}
function main() {
rock_div.addEventListener('click', function(playerSelection, computerSelection) {
game("ro");
})
paper_div.addEventListener('click', function(playerSelection, computerSelection) {
game("pa");
})
scissors_div.addEventListener('click', function(playerSelection, computerSelection) {
game("sc");
})
}
main();
compChoice();
game(playerSelection, computerSelection);
win(playerScore, computerScore);
lose(computerScore, playerScore);
body {
align-items: center;
background: black;
}
.container {
color: red;
display: flex;
justify-content: space-between;
align-items: center;
}
.container-2 {
color: red;
display: flex;
justify-content: center;
}
span {
color: white;
display: flex;
justify-content: center;
}
.game-hands {
display: flex;
justify-content: space-around;
}
img {
width: 200px;
border: solid;
border-color: black;
border-radius: 100px;
}
h1 {
display: flex;
justify-content: center;
color: white;
border: solid;
border-color: black;
border-radius: 70px;
p {
border: solid;
border-color: black;
}
.option-hover {
cursor: pointer;
background: white;
}
<title>Rock-Paper-Scissors</title>
<meta charset="UTF-8" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<link rel="stylesheet" href="styles.css">
<header>
<h1>Rock, Paper, Scissors!</h1>
</header>
<div class="score-place">
<div id="user-label" class="badge">User</div>
<div id="computer-label" class="badge">Computer</div>
<span id="user-score">0</span>:<span id="computer-score">0</span>
</div>
<section>
<div class="container-2">
<h1>Let's Play!</h1>
</div>
<div class="game-hands">
<div class="option" id="ro">
<img src="images/rock.jpg" alt="Rock">
</div>
<div class="option" id="pa">
<img src="images/paper.jpg" alt="Paper">
</div>
<div class="option" id="sc">
<img src="images/scissors.jpg" alt="Scissors">
</div>
</div>
</section>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<script src="javascript.js">
charset = "utf-8" >
</script>
As far as your problem is concerned
You used the parameter computerSelection that was not passed into the method, it will output the default string, which is normal, because there is no string that meets the conditions
According to the original conditions, the actual conditions will only have the following strings:
roundefined
paundefined
scundefined
But I see that your method has a computerMove parameter,
Combine my estimated logic and the internal logic of the program, the program should be adjusted as follows:
Replace switch (playerSelection + computerSelection) with switch (playerSelection + computerMove )

Onclick, the button moves down, why can that due to?

Whenever I click a button and the value is inputted, the values in the box goes down. I've tried changing some CSS but it doesn't work as I intend it to.
const game = (() => {
const createPlayer = (name, marker, turn) => {
return { name, marker, turn }
}
player1 = createPlayer('Player 1', "x", true)
player2 = createPlayer('Player 2', "o", false)
const gameBoard = () => {
var gameBoard = []
const movement = (e) => {
if (player1.turn === true && e.target.textContent === "") {
gameBoard[e.target.id] = player1.marker
e.target.textContent = player1.marker
player1.turn = false
} else if (player1.turn === false && e.target.textContent === "") {
gameBoard[e.target.id] = player2.marker
e.target.textContent = player2.marker
player1.turn = true
}
if (gameBoard["button-1"] === "x" && gameBoard["button-2"] === "x" && gameBoard["button-3"] === "x") {
alert("perfect")
} else if (gameBoard["button-4"] === "x" && gameBoard["button-5"] === "x" && gameBoard["button-6"] === "x") {
alert("you win")
} else if (gameBoard["button-7"] === "x" && gameBoard["button-8"] === "x" && gameBoard["button-9"] === "x") {
alert("you win")
} else if (gameBoard["button-1"] === "x" && gameBoard["button-4"] === "x" && gameBoard["button-7"] === "x") {
alert("you win")
} else if (gameBoard["button-2"] === "x" && gameBoard["button-5"] === "x" && gameBoard["button-8"] === "x") {
alert("you win")
} else if (gameBoard["button-3"] === "x" && gameBoard["button-6"] === "x" && gameBoard["button-9"] === "x") {
alert("you win")
} else if (gameBoard["button-1"] === "o" && gameBoard["button-2"] === "o" && gameBoard["button-3"] === "o") {
alert("perfect")
} else if (gameBoard["button-4"] === "o" && gameBoard["button-5"] === "o" && gameBoard["button-6"] === "o") {
alert("you win")
} else if (gameBoard["button-7"] === "o" && gameBoard["button-8"] === "o" && gameBoard["button-9"] === "o") {
alert("you win")
} else if (gameBoard["button-1"] === "o" && gameBoard["button-4"] === "o" && gameBoard["button-7"] === "o") {
alert("you win")
} else if (gameBoard["button-2"] === "o" && gameBoard["button-5"] === "o" && gameBoard["button-8"] === "o") {
alert("you win")
} else if (gameBoard["button-3"] === "o" && gameBoard["button-6"] === "o" && gameBoard["button-9"] === "o") {
alert("you win")
} else if (gameBoard["button-1"] === "o" && gameBoard["button-5"] === "o" && gameBoard["button-9"] === "o") {
alert("you win")
} else if (gameBoard["button-3"] === "o" && gameBoard["button-5"] === "o" && gameBoard["button-7"] === "o") {
alert("you win")
} else if (gameBoard["button-1"] === "x" && gameBoard["button-5"] === "x" && gameBoard["button-9"] === "x") {
alert("you win")
} else if (gameBoard["button-3"] === "x" && gameBoard["button-5"] === "x" && gameBoard["button-7"] === "x") {
alert("you win")
}
}
const board = document.querySelector('.item-board').addEventListener('click', movement)
}
gameBoard()
})
game()
.header {
background-color: red;
background-size: cover;
width: 100%;
height: 100%;
}
.item-board {
margin-left: 200px;
display: inline-block;
}
.TicTac {
background-size: cover;
width: 100%;
height: 100%;
}
.btn-1 {
width: 100px;
height: 100px;
border: 2px solid;
margin: -2px;
font-size: 4rem;
padding: 0px;
}
p {
font-size: 200px;
}
<header class="header">
<h1 class="TicTac">Tic-Tac-Toe</h1>
</header>
<div class="item-board">
<div class="item-board">
<button type="button" name="button" id="button-1" class="btn-1"></button>
<button type="button" name="button" id="button-2" class="btn-1"></button>
<button type="button" name="button" id="button-3" class="btn-1"></button>
</div>
<div class="item-board">
<button type="button" name="button" id="button-4" class="btn-1"></button>
<button type="button" name="button" id="button-5" class="btn-1"></button>
<button type="button" name="button" id="button-6" class="btn-1"></button>
</div>
<div class="item-board">
<button type="button" name="button" id="button-7" class="btn-1"></button>
<button type="button" name="button" id="button-8" class="btn-1"></button>
<button type="button" name="button" id="button-9" class="btn-1"></button>
</div>
</div>
I've tried changing some CSS but can't figure out how to make it so that it doesn't go down on each click.
Your .btn-1 styling is aligning the elements based on their text content, this can be solved by applying vertical-align: top; to that class.
Another small change that's worth making would be to change .item-board from inline-block to display: block, as that will prevent the width of the screen affecting whether the rows wrap.
const game = (() => {
const createPlayer = (name, marker, turn) => {
return { name, marker, turn }
}
player1 = createPlayer('Player 1', "x", true)
player2 = createPlayer('Player 2', "o", false)
const gameBoard = () => {
var gameBoard = []
const movement = (e) => {
if (player1.turn === true && e.target.textContent === "") {
gameBoard[e.target.id] = player1.marker
e.target.textContent = player1.marker
player1.turn = false
} else if (player1.turn === false && e.target.textContent === "") {
gameBoard[e.target.id] = player2.marker
e.target.textContent = player2.marker
player1.turn = true
}
if (gameBoard["button-1"] === "x" && gameBoard["button-2"] === "x" && gameBoard["button-3"] === "x") {
alert("perfect")
} else if (gameBoard["button-4"] === "x" && gameBoard["button-5"] === "x" && gameBoard["button-6"] === "x") {
alert("you win")
} else if (gameBoard["button-7"] === "x" && gameBoard["button-8"] === "x" && gameBoard["button-9"] === "x") {
alert("you win")
} else if (gameBoard["button-1"] === "x" && gameBoard["button-4"] === "x" && gameBoard["button-7"] === "x") {
alert("you win")
} else if (gameBoard["button-2"] === "x" && gameBoard["button-5"] === "x" && gameBoard["button-8"] === "x") {
alert("you win")
} else if (gameBoard["button-3"] === "x" && gameBoard["button-6"] === "x" && gameBoard["button-9"] === "x") {
alert("you win")
} else if (gameBoard["button-1"] === "o" && gameBoard["button-2"] === "o" && gameBoard["button-3"] === "o") {
alert("perfect")
} else if (gameBoard["button-4"] === "o" && gameBoard["button-5"] === "o" && gameBoard["button-6"] === "o") {
alert("you win")
} else if (gameBoard["button-7"] === "o" && gameBoard["button-8"] === "o" && gameBoard["button-9"] === "o") {
alert("you win")
} else if (gameBoard["button-1"] === "o" && gameBoard["button-4"] === "o" && gameBoard["button-7"] === "o") {
alert("you win")
} else if (gameBoard["button-2"] === "o" && gameBoard["button-5"] === "o" && gameBoard["button-8"] === "o") {
alert("you win")
} else if (gameBoard["button-3"] === "o" && gameBoard["button-6"] === "o" && gameBoard["button-9"] === "o") {
alert("you win")
} else if (gameBoard["button-1"] === "o" && gameBoard["button-5"] === "o" && gameBoard["button-9"] === "o") {
alert("you win")
} else if (gameBoard["button-3"] === "o" && gameBoard["button-5"] === "o" && gameBoard["button-7"] === "o") {
alert("you win")
} else if (gameBoard["button-1"] === "x" && gameBoard["button-5"] === "x" && gameBoard["button-9"] === "x") {
alert("you win")
} else if (gameBoard["button-3"] === "x" && gameBoard["button-5"] === "x" && gameBoard["button-7"] === "x") {
alert("you win")
}
}
const board = document.querySelector('.item-board').addEventListener('click', movement)
}
gameBoard()
})
game()
.header {
background-color: red;
background-size: cover;
width: 100%;
height: 100%;
}
.item-board {
margin-left: 50px;
display: block; /* This prevents the rows appearing on the same line on wide screens */
}
.TicTac {
background-size: cover;
width: 100%;
height: 100%;
}
.btn-1 {
width: 100px;
height: 100px;
border: 2px solid;
margin: -2px;
font-size: 4rem;
padding: 0px;
vertical-align: top; /* Top will fix the alignment issue when text content is added to the button */
}
p {
font-size: 200px;
}
<header class="header">
<h1 class="TicTac">Tic-Tac-Toe</h1>
</header>
<div class="item-board">
<div class="item-board">
<button type="button" name="button" id="button-1" class="btn-1"></button>
<button type="button" name="button" id="button-2" class="btn-1"></button>
<button type="button" name="button" id="button-3" class="btn-1"></button>
</div>
<div class="item-board">
<button type="button" name="button" id="button-4" class="btn-1"></button>
<button type="button" name="button" id="button-5" class="btn-1"></button>
<button type="button" name="button" id="button-6" class="btn-1"></button>
</div>
<div class="item-board">
<button type="button" name="button" id="button-7" class="btn-1"></button>
<button type="button" name="button" id="button-8" class="btn-1"></button>
<button type="button" name="button" id="button-9" class="btn-1"></button>
</div>
</div>
Try using a grid layout for your board.
I cleaned-up the CSS so that it is easier to follow. I also made the players an array and added a turn counter.
The board element is now passed to the function.
Cell lookup is easier when using indicies.
Cells are now regular <div> elements.
The cell dataset (attributes) holds the marker reference.
The cell occupied check is also easier now.
Cell clicks are delegated by the board.
Hopefully this is much easier to understand. I tried to keep the general structure of your functions.
const game = ((el) => {
const createPlayer = (name, marker) =>
({ name, marker });
let turn = 0;
const players = [
createPlayer('Player 1', 'X'),
createPlayer('Player 2', 'O')
];
const gameBoard = () => {
var gameBoard = [];
const getCell = index => el.querySelector(`.cell:nth-child(${index + 1})`);
const getCells = (...indicies) => indicies.map(getCell);
const allOccupied = (marker, ...indicies) =>
getCells(...indicies).every(cell => cell.dataset.marker === marker);
const checkWin = ({ marker }) =>
allOccupied(marker, 0, 1, 2) /* horiz / top */
|| allOccupied(marker, 3, 4, 5) /* horiz / middle */
|| allOccupied(marker, 5, 7, 8) /* horiz / bottom */
|| allOccupied(marker, 0, 3, 6) /* vert / left */
|| allOccupied(marker, 1, 4, 7) /* vert / middle */
|| allOccupied(marker, 2, 5, 8) /* vert / right */
|| allOccupied(marker, 0, 4, 8) /* diag / negative */
|| allOccupied(marker, 2, 4, 6); /* diag / positive */
const delagateClick = (e) => {
if (e.target.classList.contains('cell')) {
handleMovement(e.target);
}
};
const handleMovement = (cell) => {
const player = players[turn % players.length];
if (!cell.dataset.marker) {
cell.dataset.marker = player.marker;
cell.textContent = player.marker;
if (checkWin(player)) {
setTimeout(() => {
alert(`${player.name} ("${player.marker}") wins`);
}, 100);
}
turn++;
}
};
el.addEventListener('click', delagateClick);
}
gameBoard()
})
game(document.querySelector('.board'));
html, body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
body {
display: flex;
flex-direction: column;
align-items: center;
font-family: Arial;
background: #000;
color: #EEE;
}
header {
display: flex;
justify-content: center;
align-items: center;
background-color: #C33;
background-size: cover;
width: 100%;
height: 4em;
}
header > div {
font-size: 2em;
font-weight: bold;
}
main {
display: flex;
flex: 1;
align-items: center;
justify-content: center;
background: #222;
width: 100%;
}
.board {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 0.25em;
border: thin solid grey;
background: #444;
padding: 0.25em;
}
.cell {
display: flex;
width: 2em;
height: 2em;
border: thin solid grey;
font-size: 2em;
align-items: center;
justify-content: center;
background: #666;
cursor: pointer;
}
.cell:not([data-marker]):hover {
background: #888;
}
.cell[data-marker] {
cursor: not-allowed;
}
<header>
<div>Tic-Tac-Toe</div>
</header>
<main>
<div class="board">
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
<div class="cell"></div>
</div>
</main>

How do I use a for loop to manage increments of an object property in JavaScript?

I’m doing a rockPaperScissors project. Here’s the published link: https://george-swift.github.io/rockPaperScissors/. I want to add a first to 5 feature to put an end score to the game. If either the player or computer reaches 5, I'll have a message declare a winner (I know how to manipulate the message). Attached is a snippet for clarity.
//computer will randomly pick from this array
const RPS = ['rock','paper','scissors']
//object defines the rules of the game for each player selection
const rulesRPS = {
rock: {
beats: "scissors"
},
paper: {
beats: "rock"
},
scissors: {
beats: "paper"
}
};
//cached elements for scores
const pScore = document.getElementById("player-score");
const tScore = document.getElementById("tie-score");
const cScore = document.getElementById("computer-score");
//declared variables for helper functions
let winner, results, scores;
//for event listeners
document.getElementById("rock-btn").addEventListener('click', pSelectedR);
document.getElementById("paper-btn").addEventListener("click", pSelectedP);
document.getElementById("scissors-btn").addEventListener("click", pSelectedS);
// updates the scores after each game round
function render() {
pScore.innerHTML = scores.player;
tScore.innerHTML = scores.tie;
cScore.innerHTML = scores.computer;
}
function pickRandom () {
const selection = RPS[Math.floor(Math.random() * 3)];
return selection;
}
//handle results after player selection
function manageResults () {
results.computer = pickRandom();
winner = findWinner();
scores[winner]++;
render();
}
//player selections and subsequent action
function pSelectedR () {
results.player = "rock";
manageResults();
}
function pSelectedP () {
results.player = "paper";
manageResults();
}
function pSelectedS () {
results.player = "scissors";
manageResults();
}
//compare selections to find winner
function findWinner() {
results.computer = pickRandom();
if (results.player === results.computer) {
return 'tie';
}
if (rulesRPS[results.player].beats === results.computer) {
return 'player';
}
return 'computer';
}
//instantiates the state of the game
function init() {
scores = {
player: 0,
tie: 0,
computer: 0,
};
results = {
player: 'rock',
computer: 'rock'
};
winner = null;
}
init();
* {
box-sizing: border-box;
}
body {
font-family: 'Judson', serif;
text-align: center;
height: 100vh;
margin: 40px 0px;
}
h1, h2 {
font-family: 'Archivo Black', sans-serif;
}
body,
main,
aside {
display: flex;
justify-content: space-evenly;
align-items: center;
}
body,
main {
flex-direction: column;
}
table {
width: 100%;
}
td {
width: 33.3%;
font-size: 2.5rem;
}
img {
width: 50vh;
height: 50vh;
}
aside {
width: 75vw;
padding: 0.5em 0 0 0;
}
button {
width: 30vw;
margin: 2vw;
background-color: rgb(38,39,39);
color: whitesmoke;
border: rgb(113, 125, 126) solid 2px;
border-radius: 3px;
padding: 5px;
cursor: pointer;
}
button:hover {
background-color: rgb(112, 123, 124);
color: black;
transition: 0.5s;
}
button,
#link {
font-size: 20px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Rock Paper Scissors</title>
<link rel="stylesheet" href="styles.css">
<link href="https://fonts.googleapis.com/css?family=Archivo+Black|Judson:400,700" rel="stylesheet">
<script defer src="main.js"></script>
</head>
<body>
<header>
<h1>ROCK PAPER SCISSORS- FOR PASTIME</h1>
</header>
<main>
<table>
<caption>
<h2>Scores</h2>
<p>Best of 5?</p>
</caption>
<tbody>
<tr>
<th>Player</th>
<th>Tie</th>
<th>Computer</th>
</tr>
<tr>
<td id="player-score">0</td>
<td id="tie-score">0</td>
<td id="computer-score">0</td>
</tr>
</tbody>
</table>
<figure>
<img src="https://res.cloudinary.com/george-swift/image/upload/v1603381143/9d966b99b233a6768b6981b83e43e0f0_hobh0x.jpg"
alt="rock paper scissors illustrated"/>
</figure>
</main>
<aside>
<button id="rock-btn">Rock</button>
<button id="paper-btn">Paper</button>
<button id="scissors-btn">Scissors</button>
</aside>
<nav>
GitHub
</nav>
</body>
</html>
From what I see, the incrementing is working as expected. You only need to put in a condition to check for 5 after the winner score has been incremented.
And then add the check to your current code.
function manageResults () {
results.computer = pickRandom();
winner = findWinner();
scores[winner]++;
render();
if (scores[winner] === 5) {
renderEndGame();
init(); // To reset the scores to 0 for a new game.
}
}
Then you can add the extra function to the js file:
function renderEndGame () {
// Display end game message and score
// maybe an alert message
}

Categories