I can't seem to find what is wrong with my code. Here is what the project requires:
For this assignment, you’ll be building a memory game in the browser using HTML, CSS, and JavaScript. Your goal is to build a card-based memory game. Players will be shown a collection of cards, face down, and can click on a card to reveal what’s underneath. After clicking on two cards, the game should check to see whether they match. If they do, they will remain facing up. If not, the cards should remain displayed to the player for one second, and then flip back down.* The goal of the game is to match up all the pairs.*
When playing the game with my current code, the cards don't back over when they aren't matched with each other. I think the last "if else" statement in my code is the reason to this. I also think it could just be corrected by creating another if statement
[ if (flipCount === 2 & firstCard.style.classList !== secondCard.style.classList) ]
But wouldn't the current else statement suffice?
const gameContainer = document.getElementById("game");
let hasFlippedCard = false;
let firstCard, secondCard;
let noClicking = false;
const COLORS = [
"red",
"blue",
"green",
"orange",
"purple",
"red",
"blue",
"green",
"orange",
"purple"
];
// here is a helper function to shuffle an array
// it returns the same array with values shuffled
// it is based on an algorithm called Fisher Yates if you want ot research more
function shuffle(array) {
let counter = array.length;
// While there are elements in the array
while (counter > 0) {
// Pick a random index
let index = Math.floor(Math.random() * counter);
// Decrease counter by 1
counter--;
// And swap the last element with it
let temp = array[counter];
array[counter] = array[index];
array[index] = temp;
}
return array;
}
let shuffledColors = shuffle(COLORS);
// this function loops over the array of colors
// it creates a new div and gives it a class with the value of the color
// it also adds an event listener for a click for each card
function createDivsForColors(colorArray) {
for (let color of colorArray) {
// create a new div
const newDiv = document.createElement("div");
// give it a class attribute for the value we are looping over
newDiv.classList.add(color);
// call a function handleCardClick when a div is clicked on
newDiv.addEventListener("click", handleCardClick);
// append the div to the element with an id of game
gameContainer.append(newDiv);
}
}
// TODO: Implement this function!
function handleCardClick(event) {
// console.log(event.target);
if (noClicking) return;
// if the card has been flipped, nothing will happen
if (event.target.classList.contains("flip")) return;
//change background color of card to class name
let selectedColor = event.target.className;
event.target.style.backgroundColor = selectedColor;
// add class name of flip to 1st and 2nd clicked card's class
event.target.classList.add('flip');
//create variable holding the total number of cards flipped (with class name flip)
let flipCount = document.querySelectorAll('div .flip').length;
//define first card and second card variables
if (!hasFlippedCard) {
hasFlippedCard = true;
firstCard = this;
} else {
hasFlippedCard = false;
secondCard = this;
}
// console.log("eventtarget is"); console.dir(event.target);
// console.log("firstcard classname is", firstCard.className);
// console.log("secondcard classname is", secondCard.className)
// console.log("Card is flipped?", hasFlippedCard);
// console.log("First card is", firstCard);
// console.log("Second card is", secondCard);
// console.log("number of flips", flipCount);
// if two cards have flipped and the classes do not match.
// Make no change to new background color
if (flipCount <2) return;
if (flipCount === 2 & firstCard.classList === secondCard.classList) {
function matchedCards(){
firstCard.classList.remove('flip');
secondCard.classList.remove('flip');
}
matchedCards();
}
else {
noClicking = true;
function resetCards(){
firstCard.classList.remove('flip');
secondCard.classList.remove('flip');
firstCard.style.backgroundColor = "";
secondCard.style.backgroundColor = "";
noClicking = false;
}
setTimeout(resetCards, 1000)}
// run resetFlips function after one second
// console.dir(event.target);
}
// when the DOM loads
createDivsForColors(shuffledColors);
#game div {
border: 2px solid black;
width: 15%;
height: 200px;
margin: 10px;
display: inline-block;
background-color: white;
}
h1 {
text-align: center;
}
body {
margin: 0;
background-color: #c9e0e8;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Memory Game!</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<h1>Memory Game!</h1>
<div id="game">
</div>
<script src="script.js"></script>
</body>
</html>
The classList
property of an element returns a live DOMTokenList which in JavaScript is an object with methods to add, remove or check if a class exists in the list.
Now separate objects in JavaScript never compare as equal, even if they have the same properties. (Noting the value null
is not an object).
So the conparison expression
firstCard.classList === secondCard.classList
is always false
- the token lists are not the same.
You could compare the className
properties directly to see if the cards have the same class names in the same order but adding and removing classes risks changing the order of class names in the space separated className
string, so it may not work in this case.
You can store string values reliably on an element using their dataset
object property, or you could give each card an id
value to lookup a JavaScript object recording card details using card ids as property names. Amongst other possibilities you might like to devise to access card properties.
Good luck with the assignment.