-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
281 lines (217 loc) · 8.9 KB
/
script.js
File metadata and controls
281 lines (217 loc) · 8.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
// Memory Game
// X 1. clicking a card changes the background color to the color of its class
// X 2. users can only change (see) two cards at a time
// X 3. cards with matching classes are a match and remain face up (probably no
// longer clickable / remove the event from the div)
// X 4. the 2 non-matching cards remain visible for at least 1 second before the
// color is removed (use a setTimeout so code executes after one second)
// X 5. Clicking the same card should not count as a match
// X 6. Make sure quick clicking of cards will not show more than 2 cards at a
// time
// X 7. Add a button that when clicked will start the game
// X 8. Add a button that when clicked will restart the game once it has ended
// X 9. For every guess made, increment a score variable that is displayed while
// the game is in play.
// X 10. Store the lowest number game in localStorage
// 11. Allow for any number of cards to appear.
// 12. Instead of hard-coding colors, try something different like random colors
// or images.
// X 13. Remove use of style.backgroundColor for setting color
// X 14. Place the index to shuffledColors as a div class, not the actual
// color name!
const gameContainer = document.getElementById("game");
const gameScore = document.getElementById("score-yours");
const gameButtons = document.getElementById("startOptions");
const COLORS = [
"red",
"blue",
"green",
"orange",
"purple",
"red",
"blue",
"green",
"orange",
"purple"
];
// hold the scores, first selection, selection lock, and cards (divs)
// with removed event handlers.
let divSelectedFirst = '';
let nbrOfMatches = 0;
let nbrScoreYours = 0;
let nbrScoreLow;
let gameUnlocked = true;
let divRemovedEvents = [];
function gameReset() {
// reset fields to prepare for a new game.
divSelectedFirst = '';
nbrScoreYours = 0;
nbrOfMatches = 0;
gameScore.innerText = nbrScoreYours;
gameUnlocked = true;
divRemovedEvents = [];
}
// 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) {
let i = 0;
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(i);
i++;
// 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);
}
}
function clearCardColor(inCard1, inCard2) {
// function removed the color from selected cards passed
// in via parameters inCard1, inCard2
// Class Assumption:
// 0 is the number index for the color assigned when the div is built
// 1 is the color assigned to show the selection
inCard1.classList.remove(inCard1.classList[1]);
inCard2.classList.remove(inCard2.classList[1]);
inCard1 = '';
inCard2 = '';
gameUnlocked = true;
}
function handleCardClick(inEvt) {
// 1. clicking a card changes the background color to the color of its class
// 2. users can only change (see) to cards at a time
// 3. cards with matching classes are a match and remain face up (probably no
// longer clickable / remove the event from the div)
// 4. the 2 non-matching cards remain visible for at least 1`second before the
// color is removed (use a setTimeout so code executes after one second)
// gameUnlocked is set to False when a match occurs. gameUnlockd is set back to
// true when the clearCardColor function runs after its 1 second timeout.
if (gameUnlocked) {
if (divSelectedFirst) {
// truthy true
// make sure card is not already selected by checking backGround color
if (!(inEvt.target.classList[1])) {
// if classList[1] is undefined, that is falsey, and !falsey is truthy
// background color is not set -- this card has not been selected
// for the current turn.
// we have 2 selections (one saved in divSelectedFirst) and the current
// one in inEvt
nbrScoreYours += 1;
gameScore.innerText = nbrScoreYours;
// Show the color of the second selection.
inEvt.target.classList.add(shuffledColors[inEvt.target.classList[0]]);
// tried to check for match via divsSelected[0].classList === inEvt.target.classList
// AND no and divsSelected[0].classList[0] === inEvt.target.classList[0] looked ugly
// The array approach was dropped because the overhead of an arry when only one element
// is stored is not needed.
// The assumption is that the first class will ONLY contain the number for the color.
if (shuffledColors[divSelectedFirst.classList[0]] === shuffledColors[inEvt.target.classList[0]]) {
// they match
// remove the click event from both divs to prevent them from
// use in the game.
divSelectedFirst.removeEventListener("click", handleCardClick);
inEvt.target.removeEventListener("click", handleCardClick);
divRemovedEvents.push(divSelectedFirst);
divRemovedEvents.push(inEvt.target);
nbrOfMatches += 1;
// Is the game over?
if (!(divRemovedEvents.length < COLORS.length)) {
// the game is over because the number of matches * 2 is equal to the
// number of colors.
if (nbrScoreLow) {
if (nbrScoreYours < nbrScoreLow) {
nbrScoreLow = nbrScoreYours
}
} else {
// falsey because nbrScoreLow is undefined.
// set it to the current score.
nbrScoreLow = nbrScoreYours;
}
localStorage.setItem("scoreLow", `${nbrScoreLow}`);
document.getElementById("score-low").innerText = nbrScoreLow;
}
} else {
// for now, no match, flip them back. We'll deal with delay later
// lock the board so a new selection cannot happen until the two
// cards just selected are cleared.
gameUnlocked = false;
// remove the color and reset gameUnlocked
setTimeout(clearCardColor, 1000, divSelectedFirst, inEvt.target);
}
// clear the first selected div
divSelectedFirst = '';
}
} else {
// This is the first selection
divSelectedFirst = inEvt.target;
// set the background color
inEvt.target.classList.add(shuffledColors[inEvt.target.classList[0]]);
}
}
}
// Restart Game button needs to clear any matches, add back in any removed
// event listeners to the div cards, and reset the score to 0
// Start New Game button shuffles the colors and resets
gameButtons.addEventListener("click", function (inEvt) {
if (inEvt.target.innerText === "Start New Game") {
shuffledColors = shuffle(COLORS);
// delete the current board
gameContainer.innerHTML = "";
createDivsForColors(shuffledColors);
gameReset();
} else {
if (inEvt.target.innerText === "Restart Game") {
// Restart of game
// cards with the click event listener removed were
// remembered in divRemovedEvents. Use it to add back
// in the listeners.
for (let divReset of divRemovedEvents) {
divReset.addEventListener("click", handleCardClick);
//divReset.style.backgroundColor = "";
divReset.classList.remove(divReset.classList[1]);
}
gameReset();
// The score starts at the number of colors.
// Why? So you can't get all but 2 of the matches,
// restart the game, then complete it easily since
// the card locations were remembered. Of course,
// nothing is stopping a glance at the elements in
// the developer tools.
nbrScoreYours = COLORS.length;
gameScore.innerText = nbrScoreYours;
}
}
})
// when the DOM loads
document.addEventListener("DOMContentLoaded", function (inEvt) {
createDivsForColors(shuffledColors);
gameReset();
let scoreLow = localStorage.getItem("scoreLow");
if (parseInt(scoreLow, 10)) {
// localStorage had scoreLow, and it is a number.
nbrScoreLow = parseInt(scoreLow, 10);
document.getElementById("score-low").innerText = nbrScoreLow;
}
});