create-template-html-css 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/COMPONENTS-GALLERY.html +124 -11
- package/README.md +6 -2
- package/bin/cli.js +8 -2
- package/demo-games/guess-number/index.html +71 -0
- package/demo-games/guess-number/script.js +216 -0
- package/demo-games/guess-number/style.css +337 -0
- package/demo-games/memory-game/index.html +50 -0
- package/demo-games/memory-game/script.js +216 -0
- package/demo-games/memory-game/style.css +288 -0
- package/demo-games/snake-game/index.html +61 -0
- package/demo-games/snake-game/script.js +360 -0
- package/demo-games/snake-game/style.css +246 -0
- package/demo-games/tic-tac-toe/index.html +57 -0
- package/demo-games/tic-tac-toe/script.js +156 -0
- package/demo-games/tic-tac-toe/style.css +244 -0
- package/package.json +1 -1
- package/templates/guess-number/index.html +71 -0
- package/templates/guess-number/script.js +216 -0
- package/templates/guess-number/style.css +337 -0
- package/templates/memory-game/index.html +50 -0
- package/templates/memory-game/script.js +216 -0
- package/templates/memory-game/style.css +288 -0
- package/templates/snake-game/index.html +61 -0
- package/templates/snake-game/script.js +360 -0
- package/templates/snake-game/style.css +246 -0
- package/templates/tic-tac-toe/index.html +57 -0
- package/templates/tic-tac-toe/script.js +156 -0
- package/templates/tic-tac-toe/style.css +244 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
* {
|
|
2
|
+
margin: 0;
|
|
3
|
+
padding: 0;
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
body {
|
|
8
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
9
|
+
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
|
10
|
+
min-height: 100vh;
|
|
11
|
+
display: flex;
|
|
12
|
+
justify-content: center;
|
|
13
|
+
align-items: center;
|
|
14
|
+
padding: 20px;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.container {
|
|
18
|
+
width: 100%;
|
|
19
|
+
max-width: 500px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.game-card {
|
|
23
|
+
background: white;
|
|
24
|
+
border-radius: 16px;
|
|
25
|
+
padding: 30px;
|
|
26
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.game-card h1 {
|
|
30
|
+
text-align: center;
|
|
31
|
+
color: #333;
|
|
32
|
+
margin-bottom: 20px;
|
|
33
|
+
font-size: 2.2rem;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.game-info {
|
|
37
|
+
background: #f3f4f6;
|
|
38
|
+
border-radius: 12px;
|
|
39
|
+
padding: 15px;
|
|
40
|
+
margin-bottom: 20px;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.info-row {
|
|
44
|
+
display: flex;
|
|
45
|
+
justify-content: space-between;
|
|
46
|
+
margin-bottom: 10px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.info-row:last-child {
|
|
50
|
+
margin-bottom: 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.label {
|
|
54
|
+
color: #6b7280;
|
|
55
|
+
font-weight: 600;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.value {
|
|
59
|
+
color: #333;
|
|
60
|
+
font-weight: bold;
|
|
61
|
+
font-size: 1.1rem;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.hint-section {
|
|
65
|
+
margin-bottom: 20px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.hint-box {
|
|
69
|
+
background: #f9fafb;
|
|
70
|
+
border-radius: 12px;
|
|
71
|
+
padding: 20px;
|
|
72
|
+
text-align: center;
|
|
73
|
+
border: 3px solid #e5e7eb;
|
|
74
|
+
transition: all 0.3s ease;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.hint-box.hot {
|
|
78
|
+
background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
|
|
79
|
+
border-color: #f59e0b;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.hint-box.warm {
|
|
83
|
+
background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%);
|
|
84
|
+
border-color: #3b82f6;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.hint-box.cool {
|
|
88
|
+
background: linear-gradient(135deg, #e0e7ff 0%, #c7d2fe 100%);
|
|
89
|
+
border-color: #6366f1;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.hint-box.cold {
|
|
93
|
+
background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%);
|
|
94
|
+
border-color: #0ea5e9;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.hint-box.win {
|
|
98
|
+
background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);
|
|
99
|
+
border-color: #10b981;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.hint-box.give-up {
|
|
103
|
+
background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%);
|
|
104
|
+
border-color: #ef4444;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.hint-box.invalid,
|
|
108
|
+
.hint-box.duplicate {
|
|
109
|
+
background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
|
|
110
|
+
border-color: #f59e0b;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@keyframes bounceIn {
|
|
114
|
+
0% {
|
|
115
|
+
transform: scale(0.95);
|
|
116
|
+
opacity: 0.8;
|
|
117
|
+
}
|
|
118
|
+
50% {
|
|
119
|
+
transform: scale(1.05);
|
|
120
|
+
}
|
|
121
|
+
100% {
|
|
122
|
+
transform: scale(1);
|
|
123
|
+
opacity: 1;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
#hintText {
|
|
128
|
+
font-size: 1.3rem;
|
|
129
|
+
font-weight: bold;
|
|
130
|
+
color: #333;
|
|
131
|
+
margin-bottom: 8px;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
#hintDetails {
|
|
135
|
+
font-size: 1rem;
|
|
136
|
+
color: #555;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.input-section {
|
|
140
|
+
display: flex;
|
|
141
|
+
gap: 10px;
|
|
142
|
+
margin-bottom: 20px;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
#guessInput {
|
|
146
|
+
flex: 1;
|
|
147
|
+
padding: 12px 16px;
|
|
148
|
+
border: 2px solid #e5e7eb;
|
|
149
|
+
border-radius: 8px;
|
|
150
|
+
font-size: 1.1rem;
|
|
151
|
+
transition: all 0.3s ease;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
#guessInput:focus {
|
|
155
|
+
outline: none;
|
|
156
|
+
border-color: #667eea;
|
|
157
|
+
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
#guessInput:disabled {
|
|
161
|
+
background: #f3f4f6;
|
|
162
|
+
cursor: not-allowed;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.history-section {
|
|
166
|
+
margin-bottom: 20px;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.history-section h3 {
|
|
170
|
+
font-size: 1rem;
|
|
171
|
+
color: #6b7280;
|
|
172
|
+
margin-bottom: 10px;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.guess-history {
|
|
176
|
+
background: #f9fafb;
|
|
177
|
+
border-radius: 8px;
|
|
178
|
+
padding: 15px;
|
|
179
|
+
max-height: 150px;
|
|
180
|
+
overflow-y: auto;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.empty-state {
|
|
184
|
+
text-align: center;
|
|
185
|
+
color: #9ca3af;
|
|
186
|
+
font-style: italic;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.guess-item {
|
|
190
|
+
display: flex;
|
|
191
|
+
justify-content: space-between;
|
|
192
|
+
align-items: center;
|
|
193
|
+
background: white;
|
|
194
|
+
padding: 10px 15px;
|
|
195
|
+
border-radius: 6px;
|
|
196
|
+
margin-bottom: 8px;
|
|
197
|
+
animation: slideIn 0.3s ease;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.guess-item:last-child {
|
|
201
|
+
margin-bottom: 0;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.guess-item.correct {
|
|
205
|
+
background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);
|
|
206
|
+
border: 2px solid #10b981;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
@keyframes slideIn {
|
|
210
|
+
from {
|
|
211
|
+
transform: translateY(-10px);
|
|
212
|
+
opacity: 0;
|
|
213
|
+
}
|
|
214
|
+
to {
|
|
215
|
+
transform: translateY(0);
|
|
216
|
+
opacity: 1;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.guess-number {
|
|
221
|
+
font-size: 1.2rem;
|
|
222
|
+
font-weight: bold;
|
|
223
|
+
color: #333;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.guess-icon {
|
|
227
|
+
font-size: 1.3rem;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.difficulty-section {
|
|
231
|
+
margin-bottom: 20px;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.difficulty-section h3 {
|
|
235
|
+
font-size: 1rem;
|
|
236
|
+
color: #6b7280;
|
|
237
|
+
margin-bottom: 10px;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.difficulty-buttons {
|
|
241
|
+
display: flex;
|
|
242
|
+
gap: 8px;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.difficulty-btn {
|
|
246
|
+
flex: 1;
|
|
247
|
+
padding: 10px;
|
|
248
|
+
border: 2px solid #e5e7eb;
|
|
249
|
+
border-radius: 8px;
|
|
250
|
+
background: white;
|
|
251
|
+
font-size: 0.85rem;
|
|
252
|
+
font-weight: 600;
|
|
253
|
+
cursor: pointer;
|
|
254
|
+
transition: all 0.3s ease;
|
|
255
|
+
color: #333;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.difficulty-btn:hover {
|
|
259
|
+
border-color: #667eea;
|
|
260
|
+
background: #f3f4f6;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.difficulty-btn.active {
|
|
264
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
265
|
+
color: white;
|
|
266
|
+
border-color: #667eea;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.button-group {
|
|
270
|
+
display: flex;
|
|
271
|
+
gap: 10px;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.btn {
|
|
275
|
+
flex: 1;
|
|
276
|
+
padding: 12px 24px;
|
|
277
|
+
border: none;
|
|
278
|
+
border-radius: 8px;
|
|
279
|
+
font-size: 1rem;
|
|
280
|
+
font-weight: 600;
|
|
281
|
+
cursor: pointer;
|
|
282
|
+
transition: all 0.3s ease;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.btn:disabled {
|
|
286
|
+
opacity: 0.5;
|
|
287
|
+
cursor: not-allowed;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.btn-primary {
|
|
291
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
292
|
+
color: white;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.btn-primary:hover:not(:disabled) {
|
|
296
|
+
transform: translateY(-2px);
|
|
297
|
+
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.btn-success {
|
|
301
|
+
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
|
|
302
|
+
color: white;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.btn-success:hover {
|
|
306
|
+
transform: translateY(-2px);
|
|
307
|
+
box-shadow: 0 5px 15px rgba(16, 185, 129, 0.4);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.btn-secondary {
|
|
311
|
+
background: #6b7280;
|
|
312
|
+
color: white;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.btn-secondary:hover {
|
|
316
|
+
background: #4b5563;
|
|
317
|
+
transform: translateY(-2px);
|
|
318
|
+
box-shadow: 0 5px 15px rgba(107, 114, 128, 0.4);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
@media (max-width: 480px) {
|
|
322
|
+
.game-card {
|
|
323
|
+
padding: 20px;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.game-card h1 {
|
|
327
|
+
font-size: 1.8rem;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.difficulty-buttons {
|
|
331
|
+
flex-direction: column;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.button-group {
|
|
335
|
+
flex-direction: column;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>{{name}} - Memory Game</title>
|
|
7
|
+
<link rel="stylesheet" href="style.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div class="container">
|
|
11
|
+
<div class="game-card">
|
|
12
|
+
<h1>Memory Game</h1>
|
|
13
|
+
|
|
14
|
+
<div class="game-stats">
|
|
15
|
+
<div class="stat">
|
|
16
|
+
<span class="stat-label">Moves:</span>
|
|
17
|
+
<span id="moves" class="stat-value">0</span>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="stat">
|
|
20
|
+
<span class="stat-label">Time:</span>
|
|
21
|
+
<span id="timer" class="stat-value">0:00</span>
|
|
22
|
+
</div>
|
|
23
|
+
<div class="stat">
|
|
24
|
+
<span class="stat-label">Matches:</span>
|
|
25
|
+
<span id="matches" class="stat-value">0/8</span>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<div class="memory-board" id="memoryBoard"></div>
|
|
30
|
+
|
|
31
|
+
<div class="message" id="message"></div>
|
|
32
|
+
|
|
33
|
+
<div class="button-group">
|
|
34
|
+
<button id="resetBtn" class="btn btn-primary">New Game</button>
|
|
35
|
+
<button id="difficultyBtn" class="btn btn-secondary">Change Difficulty</button>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<div class="difficulty-selector" id="difficultySelector">
|
|
39
|
+
<h3>Select Difficulty</h3>
|
|
40
|
+
<div class="difficulty-options">
|
|
41
|
+
<button class="difficulty-btn active" data-difficulty="easy">Easy (4x4)</button>
|
|
42
|
+
<button class="difficulty-btn" data-difficulty="medium">Medium (4x5)</button>
|
|
43
|
+
<button class="difficulty-btn" data-difficulty="hard">Hard (4x6)</button>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
<script src="script.js"></script>
|
|
49
|
+
</body>
|
|
50
|
+
</html>
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
// Memory Game Logic
|
|
2
|
+
|
|
3
|
+
const memoryBoard = document.getElementById('memoryBoard');
|
|
4
|
+
const movesDisplay = document.getElementById('moves');
|
|
5
|
+
const timerDisplay = document.getElementById('timer');
|
|
6
|
+
const matchesDisplay = document.getElementById('matches');
|
|
7
|
+
const messageDisplay = document.getElementById('message');
|
|
8
|
+
const resetBtn = document.getElementById('resetBtn');
|
|
9
|
+
const difficultyBtn = document.getElementById('difficultyBtn');
|
|
10
|
+
const difficultySelector = document.getElementById('difficultySelector');
|
|
11
|
+
const difficultyBtns = document.querySelectorAll('.difficulty-btn');
|
|
12
|
+
|
|
13
|
+
// Game symbols
|
|
14
|
+
const symbols = ['🎮', '🎯', '🎨', '🎭', '🎪', '🎬', '🎸', '🎺', '⚽', '🏀', '🎾', '🏈'];
|
|
15
|
+
|
|
16
|
+
let difficulty = 'easy';
|
|
17
|
+
let cards = [];
|
|
18
|
+
let flippedCards = [];
|
|
19
|
+
let matchedPairs = 0;
|
|
20
|
+
let moves = 0;
|
|
21
|
+
let timer = 0;
|
|
22
|
+
let timerInterval = null;
|
|
23
|
+
let canFlip = true;
|
|
24
|
+
|
|
25
|
+
// Difficulty settings
|
|
26
|
+
const difficultySettings = {
|
|
27
|
+
easy: { pairs: 8, gridCols: 4 },
|
|
28
|
+
medium: { pairs: 10, gridCols: 5 },
|
|
29
|
+
hard: { pairs: 12, gridCols: 6 }
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Initialize game
|
|
33
|
+
function initGame() {
|
|
34
|
+
clearInterval(timerInterval);
|
|
35
|
+
const settings = difficultySettings[difficulty];
|
|
36
|
+
const pairsCount = settings.pairs;
|
|
37
|
+
|
|
38
|
+
// Reset stats
|
|
39
|
+
moves = 0;
|
|
40
|
+
matchedPairs = 0;
|
|
41
|
+
timer = 0;
|
|
42
|
+
flippedCards = [];
|
|
43
|
+
canFlip = true;
|
|
44
|
+
|
|
45
|
+
updateStats();
|
|
46
|
+
messageDisplay.textContent = '';
|
|
47
|
+
messageDisplay.className = 'message';
|
|
48
|
+
|
|
49
|
+
// Create card deck
|
|
50
|
+
const selectedSymbols = symbols.slice(0, pairsCount);
|
|
51
|
+
const cardSymbols = [...selectedSymbols, ...selectedSymbols];
|
|
52
|
+
shuffleArray(cardSymbols);
|
|
53
|
+
|
|
54
|
+
// Create board
|
|
55
|
+
memoryBoard.innerHTML = '';
|
|
56
|
+
memoryBoard.style.gridTemplateColumns = `repeat(${settings.gridCols}, 1fr)`;
|
|
57
|
+
|
|
58
|
+
cards = cardSymbols.map((symbol, index) => {
|
|
59
|
+
const card = document.createElement('div');
|
|
60
|
+
card.className = 'memory-card';
|
|
61
|
+
card.dataset.symbol = symbol;
|
|
62
|
+
card.dataset.index = index;
|
|
63
|
+
|
|
64
|
+
card.innerHTML = `
|
|
65
|
+
<div class="card-inner">
|
|
66
|
+
<div class="card-front">?</div>
|
|
67
|
+
<div class="card-back">${symbol}</div>
|
|
68
|
+
</div>
|
|
69
|
+
`;
|
|
70
|
+
|
|
71
|
+
card.addEventListener('click', () => handleCardClick(card));
|
|
72
|
+
memoryBoard.appendChild(card);
|
|
73
|
+
|
|
74
|
+
return card;
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Start timer on first click
|
|
78
|
+
let firstClick = true;
|
|
79
|
+
cards.forEach(card => {
|
|
80
|
+
card.addEventListener('click', () => {
|
|
81
|
+
if (firstClick) {
|
|
82
|
+
startTimer();
|
|
83
|
+
firstClick = false;
|
|
84
|
+
}
|
|
85
|
+
}, { once: true });
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Handle card click
|
|
90
|
+
function handleCardClick(card) {
|
|
91
|
+
if (!canFlip || card.classList.contains('flipped') || card.classList.contains('matched')) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Flip card
|
|
96
|
+
card.classList.add('flipped');
|
|
97
|
+
flippedCards.push(card);
|
|
98
|
+
|
|
99
|
+
// Check if two cards are flipped
|
|
100
|
+
if (flippedCards.length === 2) {
|
|
101
|
+
canFlip = false;
|
|
102
|
+
moves++;
|
|
103
|
+
updateStats();
|
|
104
|
+
|
|
105
|
+
setTimeout(() => checkMatch(), 800);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Check if cards match
|
|
110
|
+
function checkMatch() {
|
|
111
|
+
const [card1, card2] = flippedCards;
|
|
112
|
+
const symbol1 = card1.dataset.symbol;
|
|
113
|
+
const symbol2 = card2.dataset.symbol;
|
|
114
|
+
|
|
115
|
+
if (symbol1 === symbol2) {
|
|
116
|
+
// Match found
|
|
117
|
+
card1.classList.add('matched');
|
|
118
|
+
card2.classList.add('matched');
|
|
119
|
+
matchedPairs++;
|
|
120
|
+
updateStats();
|
|
121
|
+
|
|
122
|
+
// Check if game is won
|
|
123
|
+
if (matchedPairs === difficultySettings[difficulty].pairs) {
|
|
124
|
+
handleWin();
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
// No match - flip back
|
|
128
|
+
setTimeout(() => {
|
|
129
|
+
card1.classList.remove('flipped');
|
|
130
|
+
card2.classList.remove('flipped');
|
|
131
|
+
}, 400);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
flippedCards = [];
|
|
135
|
+
canFlip = true;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Handle win
|
|
139
|
+
function handleWin() {
|
|
140
|
+
clearInterval(timerInterval);
|
|
141
|
+
messageDisplay.textContent = `🎉 You Won! Time: ${formatTime(timer)}, Moves: ${moves}`;
|
|
142
|
+
messageDisplay.className = 'message show win';
|
|
143
|
+
|
|
144
|
+
// Celebration animation
|
|
145
|
+
cards.forEach((card, index) => {
|
|
146
|
+
setTimeout(() => {
|
|
147
|
+
card.style.animation = 'bounce 0.5s ease';
|
|
148
|
+
}, index * 50);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Start timer
|
|
153
|
+
function startTimer() {
|
|
154
|
+
timerInterval = setInterval(() => {
|
|
155
|
+
timer++;
|
|
156
|
+
updateStats();
|
|
157
|
+
}, 1000);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Update stats display
|
|
161
|
+
function updateStats() {
|
|
162
|
+
movesDisplay.textContent = moves;
|
|
163
|
+
timerDisplay.textContent = formatTime(timer);
|
|
164
|
+
matchesDisplay.textContent = `${matchedPairs}/${difficultySettings[difficulty].pairs}`;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Format time
|
|
168
|
+
function formatTime(seconds) {
|
|
169
|
+
const mins = Math.floor(seconds / 60);
|
|
170
|
+
const secs = seconds % 60;
|
|
171
|
+
return `${mins}:${secs.toString().padStart(2, '0')}`;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Shuffle array
|
|
175
|
+
function shuffleArray(array) {
|
|
176
|
+
for (let i = array.length - 1; i > 0; i--) {
|
|
177
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
178
|
+
[array[i], array[j]] = [array[j], array[i]];
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Toggle difficulty selector
|
|
183
|
+
function toggleDifficultySelector() {
|
|
184
|
+
difficultySelector.classList.toggle('show');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Change difficulty
|
|
188
|
+
function changeDifficulty(newDifficulty) {
|
|
189
|
+
difficulty = newDifficulty;
|
|
190
|
+
|
|
191
|
+
// Update active button
|
|
192
|
+
difficultyBtns.forEach(btn => {
|
|
193
|
+
btn.classList.toggle('active', btn.dataset.difficulty === difficulty);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
difficultySelector.classList.remove('show');
|
|
197
|
+
initGame();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Event listeners
|
|
201
|
+
resetBtn.addEventListener('click', initGame);
|
|
202
|
+
difficultyBtn.addEventListener('click', toggleDifficultySelector);
|
|
203
|
+
|
|
204
|
+
difficultyBtns.forEach(btn => {
|
|
205
|
+
btn.addEventListener('click', () => changeDifficulty(btn.dataset.difficulty));
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// Close difficulty selector when clicking outside
|
|
209
|
+
document.addEventListener('click', (e) => {
|
|
210
|
+
if (!e.target.closest('.difficulty-selector') && !e.target.closest('#difficultyBtn')) {
|
|
211
|
+
difficultySelector.classList.remove('show');
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// Initialize on load
|
|
216
|
+
initGame();
|