KEXEL commited on
Commit
e0eccaf
·
verified ·
1 Parent(s): adc2328
Files changed (1) hide show
  1. VitaMahjong.html +600 -0
VitaMahjong.html ADDED
@@ -0,0 +1,600 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Vita Mahjong</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ @keyframes tileHover {
11
+ 0% { transform: translateY(0); }
12
+ 50% { transform: translateY(-5px); }
13
+ 100% { transform: translateY(0); }
14
+ }
15
+
16
+ .tile-hover:hover {
17
+ animation: tileHover 0.3s ease;
18
+ transform: translateY(-5px);
19
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2);
20
+ }
21
+
22
+ .tile-selected {
23
+ transform: translateY(-15px);
24
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.2);
25
+ z-index: 10;
26
+ }
27
+
28
+ .tile-matched {
29
+ animation: fadeOut 0.5s ease forwards;
30
+ }
31
+
32
+ @keyframes fadeOut {
33
+ to {
34
+ opacity: 0;
35
+ transform: scale(0.8);
36
+ }
37
+ }
38
+
39
+ .board-container {
40
+ perspective: 1000px;
41
+ }
42
+
43
+ .tile {
44
+ transition: all 0.3s ease;
45
+ transform-style: preserve-3d;
46
+ }
47
+
48
+ .tile-inner {
49
+ position: relative;
50
+ width: 100%;
51
+ height: 100%;
52
+ transform-style: preserve-3d;
53
+ }
54
+
55
+ .tile-front, .tile-back {
56
+ position: absolute;
57
+ width: 100%;
58
+ height: 100%;
59
+ backface-visibility: hidden;
60
+ border-radius: 8px;
61
+ display: flex;
62
+ align-items: center;
63
+ justify-content: center;
64
+ }
65
+
66
+ .tile-front {
67
+ background: linear-gradient(145deg, #f0f0f0, #ffffff);
68
+ transform: rotateY(180deg);
69
+ }
70
+
71
+ .tile-back {
72
+ background: linear-gradient(145deg, #4f46e5, #7c3aed);
73
+ color: white;
74
+ }
75
+
76
+ .flipped {
77
+ transform: rotateY(180deg);
78
+ }
79
+
80
+ .level-complete {
81
+ animation: pulse 2s infinite;
82
+ }
83
+
84
+ @keyframes pulse {
85
+ 0% { transform: scale(1); }
86
+ 50% { transform: scale(1.05); }
87
+ 100% { transform: scale(1); }
88
+ }
89
+ </style>
90
+ </head>
91
+ <body class="bg-gray-100 min-h-screen font-sans">
92
+ <div class="container mx-auto px-4 py-8">
93
+ <!-- Header -->
94
+ <header class="flex justify-between items-center mb-8">
95
+ <div class="flex items-center">
96
+ <i class="fas fa-dragon text-4xl text-purple-600 mr-3"></i>
97
+ <h1 class="text-3xl font-bold text-gray-800">Vita Mahjong</h1>
98
+ </div>
99
+ <div class="flex items-center space-x-4">
100
+ <div class="bg-white rounded-lg shadow p-3 flex items-center">
101
+ <i class="fas fa-clock text-purple-600 mr-2"></i>
102
+ <span id="timer" class="font-bold">00:00</span>
103
+ </div>
104
+ <div class="bg-white rounded-lg shadow p-3 flex items-center">
105
+ <i class="fas fa-layer-group text-purple-600 mr-2"></i>
106
+ <span id="level" class="font-bold">Level 1</span>
107
+ </div>
108
+ <div class="bg-white rounded-lg shadow p-3 flex items-center">
109
+ <i class="fas fa-star text-yellow-500 mr-2"></i>
110
+ <span id="score" class="font-bold">0</span>
111
+ </div>
112
+ </div>
113
+ </header>
114
+
115
+ <!-- Game Controls -->
116
+ <div class="flex justify-between mb-6">
117
+ <div class="flex space-x-3">
118
+ <button id="new-game" class="bg-purple-600 hover:bg-purple-700 text-white px-4 py-2 rounded-lg shadow flex items-center">
119
+ <i class="fas fa-plus-circle mr-2"></i> New Game
120
+ </button>
121
+ <button id="hint" class="bg-amber-500 hover:bg-amber-600 text-white px-4 py-2 rounded-lg shadow flex items-center">
122
+ <i class="fas fa-lightbulb mr-2"></i> Hint
123
+ </button>
124
+ </div>
125
+ <div>
126
+ <button id="sound-toggle" class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded-lg shadow flex items-center">
127
+ <i class="fas fa-volume-up mr-2"></i> Sound On
128
+ </button>
129
+ </div>
130
+ </div>
131
+
132
+ <!-- Game Board -->
133
+ <div class="board-container bg-white rounded-xl shadow-xl p-6 mb-6">
134
+ <div id="board" class="grid grid-cols-8 gap-3 mx-auto"></div>
135
+ </div>
136
+
137
+ <!-- Game Status -->
138
+ <div id="game-status" class="text-center mb-6 hidden">
139
+ <div class="inline-block bg-green-100 border-l-4 border-green-500 text-green-700 p-4 rounded-lg">
140
+ <p class="font-bold">Level Complete!</p>
141
+ </div>
142
+ </div>
143
+
144
+ <!-- Level Complete Modal -->
145
+ <div id="level-complete-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
146
+ <div class="bg-white rounded-xl shadow-2xl p-8 max-w-md w-full level-complete">
147
+ <div class="text-center">
148
+ <div class="text-6xl text-yellow-500 mb-4">
149
+ <i class="fas fa-trophy"></i>
150
+ </div>
151
+ <h2 class="text-3xl font-bold text-gray-800 mb-2">Level Complete!</h2>
152
+ <p class="text-gray-600 mb-6">Great job! Ready for the next challenge?</p>
153
+ <div class="grid grid-cols-2 gap-4 mb-6">
154
+ <div class="bg-purple-50 rounded-lg p-3">
155
+ <p class="text-sm text-purple-600">Time</p>
156
+ <p id="level-time" class="font-bold text-xl">00:45</p>
157
+ </div>
158
+ <div class="bg-purple-50 rounded-lg p-3">
159
+ <p class="text-sm text-purple-600">Score</p>
160
+ <p id="level-score" class="font-bold text-xl">+250</p>
161
+ </div>
162
+ </div>
163
+ <button id="next-level" class="w-full bg-purple-600 hover:bg-purple-700 text-white py-3 rounded-lg shadow-lg font-bold">
164
+ Next Level <i class="fas fa-arrow-right ml-2"></i>
165
+ </button>
166
+ </div>
167
+ </div>
168
+ </div>
169
+
170
+ <!-- Game Over Modal -->
171
+ <div id="game-over-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
172
+ <div class="bg-white rounded-xl shadow-2xl p-8 max-w-md w-full">
173
+ <div class="text-center">
174
+ <div class="text-6xl text-red-500 mb-4">
175
+ <i class="fas fa-gamepad"></i>
176
+ </div>
177
+ <h2 class="text-3xl font-bold text-gray-800 mb-2">Game Over</h2>
178
+ <p class="text-gray-600 mb-6">Better luck next time!</p>
179
+ <div class="grid grid-cols-2 gap-4 mb-6">
180
+ <div class="bg-purple-50 rounded-lg p-3">
181
+ <p class="text-sm text-purple-600">Level Reached</p>
182
+ <p id="final-level" class="font-bold text-xl">3</p>
183
+ </div>
184
+ <div class="bg-purple-50 rounded-lg p-3">
185
+ <p class="text-sm text-purple-600">Total Score</p>
186
+ <p id="final-score" class="font-bold text-xl">750</p>
187
+ </div>
188
+ </div>
189
+ <button id="play-again" class="w-full bg-purple-600 hover:bg-purple-700 text-white py-3 rounded-lg shadow-lg font-bold">
190
+ Play Again <i class="fas fa-redo ml-2"></i>
191
+ </button>
192
+ </div>
193
+ </div>
194
+ </div>
195
+ </div>
196
+
197
+ <script>
198
+ document.addEventListener('DOMContentLoaded', () => {
199
+ // Game state
200
+ const state = {
201
+ board: [],
202
+ level: 1,
203
+ score: 0,
204
+ time: 0,
205
+ timerInterval: null,
206
+ selectedTiles: [],
207
+ matchedPairs: 0,
208
+ totalPairs: 0,
209
+ soundEnabled: true,
210
+ gameActive: false
211
+ };
212
+
213
+ // DOM elements
214
+ const boardElement = document.getElementById('board');
215
+ const timerElement = document.getElementById('timer');
216
+ const levelElement = document.getElementById('level');
217
+ const scoreElement = document.getElementById('score');
218
+ const newGameButton = document.getElementById('new-game');
219
+ const hintButton = document.getElementById('hint');
220
+ const soundToggleButton = document.getElementById('sound-toggle');
221
+ const gameStatusElement = document.getElementById('game-status');
222
+ const levelCompleteModal = document.getElementById('level-complete-modal');
223
+ const gameOverModal = document.getElementById('game-over-modal');
224
+ const nextLevelButton = document.getElementById('next-level');
225
+ const playAgainButton = document.getElementById('play-again');
226
+ const levelTimeElement = document.getElementById('level-time');
227
+ const levelScoreElement = document.getElementById('level-score');
228
+ const finalLevelElement = document.getElementById('final-level');
229
+ const finalScoreElement = document.getElementById('final-score');
230
+
231
+ // Tile types (Vita Mahjong style)
232
+ const tileTypes = [
233
+ '1m', '2m', '3m', '4m', '5m', '6m', '7m', '8m', '9m', // Characters
234
+ '1s', '2s', '3s', '4s', '5s', '6s', '7s', '8s', '9s', // Bamboo
235
+ '1p', '2p', '3p', '4p', '5p', '6p', '7p', '8p', '9p', // Circles
236
+ 'ew', 'sw', 'ww', 'nw', // Winds
237
+ 'wd', 'gd', 'rd' // Dragons
238
+ ];
239
+
240
+ // Initialize game
241
+ function initGame() {
242
+ state.level = 1;
243
+ state.score = 0;
244
+ state.time = 0;
245
+ state.matchedPairs = 0;
246
+ state.gameActive = true;
247
+
248
+ clearInterval(state.timerInterval);
249
+ startTimer();
250
+
251
+ updateUI();
252
+ createBoard();
253
+ }
254
+
255
+ // Create game board based on current level
256
+ function createBoard() {
257
+ boardElement.innerHTML = '';
258
+ state.board = [];
259
+ state.selectedTiles = [];
260
+ state.matchedPairs = 0;
261
+
262
+ // Determine number of pairs based on level
263
+ const pairs = Math.min(4 + state.level, 32); // Max 32 pairs (64 tiles)
264
+ state.totalPairs = pairs;
265
+
266
+ // Create array of tile pairs
267
+ let tiles = [];
268
+ const availableTypes = [...tileTypes].sort(() => 0.5 - Math.random()).slice(0, pairs);
269
+
270
+ availableTypes.forEach(type => {
271
+ tiles.push(type, type);
272
+ });
273
+
274
+ // Shuffle tiles
275
+ tiles = shuffleArray(tiles);
276
+
277
+ // Create board matrix (8 columns, rows as needed)
278
+ const cols = 8;
279
+ const rows = Math.ceil(tiles.length / cols);
280
+
281
+ for (let i = 0; i < rows; i++) {
282
+ const row = [];
283
+ for (let j = 0; j < cols; j++) {
284
+ const index = i * cols + j;
285
+ if (index < tiles.length) {
286
+ row.push({
287
+ type: tiles[index],
288
+ flipped: false,
289
+ matched: false,
290
+ row: i,
291
+ col: j
292
+ });
293
+ } else {
294
+ row.push(null); // Empty slot for uneven boards
295
+ }
296
+ }
297
+ state.board.push(row);
298
+ }
299
+
300
+ // Render tiles
301
+ renderBoard();
302
+ }
303
+
304
+ // Render the game board
305
+ function renderBoard() {
306
+ boardElement.innerHTML = '';
307
+
308
+ // Calculate grid rows based on board rows
309
+ boardElement.className = `grid gap-3 mx-auto`;
310
+ boardElement.style.gridTemplateColumns = `repeat(8, minmax(0, 1fr))`;
311
+
312
+ state.board.forEach((row, rowIndex) => {
313
+ row.forEach((tile, colIndex) => {
314
+ if (!tile) return;
315
+
316
+ const tileElement = document.createElement('div');
317
+ tileElement.className = `tile aspect-square cursor-pointer transition-all duration-300 ${tile.matched ? 'opacity-0' : ''}`;
318
+
319
+ tileElement.innerHTML = `
320
+ <div class="tile-inner ${tile.flipped ? 'flipped' : ''}">
321
+ <div class="tile-back flex items-center justify-center">
322
+ <i class="fas fa-dragon text-2xl"></i>
323
+ </div>
324
+ <div class="tile-front">
325
+ <span class="text-3xl font-bold">${getTileSymbol(tile.type)}</span>
326
+ </div>
327
+ </div>
328
+ `;
329
+
330
+ tileElement.addEventListener('click', () => handleTileClick(tile));
331
+
332
+ if (!tile.matched) {
333
+ tileElement.classList.add('tile-hover');
334
+ }
335
+
336
+ boardElement.appendChild(tileElement);
337
+ });
338
+ });
339
+ }
340
+
341
+ // Handle tile click
342
+ function handleTileClick(tile) {
343
+ if (!state.gameActive || tile.matched || tile.flipped || state.selectedTiles.length >= 2) {
344
+ return;
345
+ }
346
+
347
+ // Flip the tile
348
+ tile.flipped = true;
349
+ state.selectedTiles.push(tile);
350
+
351
+ // Play sound
352
+ if (state.soundEnabled) {
353
+ playSound('flip');
354
+ }
355
+
356
+ renderBoard();
357
+
358
+ // Check for match if two tiles are selected
359
+ if (state.selectedTiles.length === 2) {
360
+ const [tile1, tile2] = state.selectedTiles;
361
+
362
+ if (tile1.type === tile2.type) {
363
+ // Match found
364
+ tile1.matched = true;
365
+ tile2.matched = true;
366
+ state.matchedPairs++;
367
+ state.score += 50 * state.level;
368
+
369
+ // Play success sound
370
+ if (state.soundEnabled) {
371
+ playSound('match');
372
+ }
373
+
374
+ // Check if level is complete
375
+ if (state.matchedPairs === state.totalPairs) {
376
+ levelComplete();
377
+ }
378
+
379
+ // Clear selection after delay
380
+ setTimeout(() => {
381
+ state.selectedTiles = [];
382
+ renderBoard();
383
+ }, 500);
384
+ } else {
385
+ // No match
386
+ setTimeout(() => {
387
+ tile1.flipped = false;
388
+ tile2.flipped = false;
389
+ state.selectedTiles = [];
390
+ renderBoard();
391
+
392
+ // Play mismatch sound
393
+ if (state.soundEnabled) {
394
+ playSound('mismatch');
395
+ }
396
+ }, 1000);
397
+ }
398
+ }
399
+
400
+ updateUI();
401
+ }
402
+
403
+ // Level complete
404
+ function levelComplete() {
405
+ state.gameActive = false;
406
+ clearInterval(state.timerInterval);
407
+
408
+ // Calculate bonus points based on time
409
+ const timeBonus = Math.max(0, 300 - state.time);
410
+ state.score += timeBonus;
411
+
412
+ // Show level complete modal
413
+ levelTimeElement.textContent = formatTime(state.time);
414
+ levelScoreElement.textContent = `+${timeBonus}`;
415
+ levelCompleteModal.classList.remove('hidden');
416
+
417
+ updateUI();
418
+ }
419
+
420
+ // Next level
421
+ function nextLevel() {
422
+ state.level++;
423
+ state.time = 0;
424
+ state.gameActive = true;
425
+
426
+ levelCompleteModal.classList.add('hidden');
427
+ startTimer();
428
+ createBoard();
429
+ updateUI();
430
+
431
+ // Show level up message
432
+ gameStatusElement.classList.remove('hidden');
433
+ gameStatusElement.querySelector('p').textContent = `Level ${state.level}!`;
434
+
435
+ setTimeout(() => {
436
+ gameStatusElement.classList.add('hidden');
437
+ }, 2000);
438
+ }
439
+
440
+ // Game over
441
+ function gameOver() {
442
+ state.gameActive = false;
443
+ clearInterval(state.timerInterval);
444
+
445
+ // Update final stats
446
+ finalLevelElement.textContent = state.level;
447
+ finalScoreElement.textContent = state.score;
448
+
449
+ // Show game over modal
450
+ gameOverModal.classList.remove('hidden');
451
+ }
452
+
453
+ // Start timer
454
+ function startTimer() {
455
+ state.time = 0;
456
+ updateTimerDisplay();
457
+
458
+ state.timerInterval = setInterval(() => {
459
+ state.time++;
460
+ updateTimerDisplay();
461
+
462
+ // Game over if time exceeds limit (5 minutes)
463
+ if (state.time >= 300) {
464
+ gameOver();
465
+ }
466
+ }, 1000);
467
+ }
468
+
469
+ // Update timer display
470
+ function updateTimerDisplay() {
471
+ timerElement.textContent = formatTime(state.time);
472
+ }
473
+
474
+ // Format time as MM:SS
475
+ function formatTime(seconds) {
476
+ const mins = Math.floor(seconds / 60).toString().padStart(2, '0');
477
+ const secs = (seconds % 60).toString().padStart(2, '0');
478
+ return `${mins}:${secs}`;
479
+ }
480
+
481
+ // Update UI elements
482
+ function updateUI() {
483
+ levelElement.textContent = `Level ${state.level}`;
484
+ scoreElement.textContent = state.score;
485
+ }
486
+
487
+ // Get tile symbol for display
488
+ function getTileSymbol(type) {
489
+ const symbols = {
490
+ '1m': '一', '2m': '二', '3m': '三', '4m': '四', '5m': '五',
491
+ '6m': '��', '7m': '七', '8m': '八', '9m': '九',
492
+ '1s': '1', '2s': '2', '3s': '3', '4s': '4', '5s': '5',
493
+ '6s': '6', '7s': '7', '8s': '8', '9s': '9',
494
+ '1p': '❶', '2p': '❷', '3p': '❸', '4p': '❹', '5p': '❺',
495
+ '6p': '❻', '7p': '❼', '8p': '❽', '9p': '❾',
496
+ 'ew': '東', 'sw': '南', 'ww': '西', 'nw': '北',
497
+ 'wd': '白', 'gd': '發', 'rd': '中'
498
+ };
499
+ return symbols[type] || type;
500
+ }
501
+
502
+ // Shuffle array
503
+ function shuffleArray(array) {
504
+ const newArray = [...array];
505
+ for (let i = newArray.length - 1; i > 0; i--) {
506
+ const j = Math.floor(Math.random() * (i + 1));
507
+ [newArray[i], newArray[j]] = [newArray[j], newArray[i]];
508
+ }
509
+ return newArray;
510
+ }
511
+
512
+ // Play sound
513
+ function playSound(type) {
514
+ // In a real implementation, you would play actual sound files
515
+ console.log(`Playing ${type} sound`);
516
+ }
517
+
518
+ // Provide hint
519
+ function provideHint() {
520
+ if (!state.gameActive || state.matchedPairs === state.totalPairs) {
521
+ return;
522
+ }
523
+
524
+ // Find all unflipped, unmatched tiles
525
+ const unflippedTiles = [];
526
+ state.board.forEach(row => {
527
+ row.forEach(tile => {
528
+ if (tile && !tile.flipped && !tile.matched) {
529
+ unflippedTiles.push(tile);
530
+ }
531
+ });
532
+ });
533
+
534
+ if (unflippedTiles.length < 2) return;
535
+
536
+ // Find a matching pair
537
+ const tileCount = {};
538
+ let hintTile1 = null;
539
+ let hintTile2 = null;
540
+
541
+ for (const tile of unflippedTiles) {
542
+ if (tileCount[tile.type]) {
543
+ hintTile1 = tileCount[tile.type];
544
+ hintTile2 = tile;
545
+ break;
546
+ }
547
+ tileCount[tile.type] = tile;
548
+ }
549
+
550
+ if (hintTile1 && hintTile2) {
551
+ // Highlight the hint tiles
552
+ const tileElements = boardElement.querySelectorAll('.tile');
553
+
554
+ tileElements.forEach((element, index) => {
555
+ const row = Math.floor(index / 8);
556
+ const col = index % 8;
557
+ const tile = state.board[row]?.[col];
558
+
559
+ if (tile === hintTile1 || tile === hintTile2) {
560
+ element.classList.add('ring-4', 'ring-yellow-400', 'ring-opacity-75');
561
+
562
+ // Remove highlight after delay
563
+ setTimeout(() => {
564
+ element.classList.remove('ring-4', 'ring-yellow-400', 'ring-opacity-75');
565
+ }, 2000);
566
+ }
567
+ });
568
+
569
+ // Deduct points for using hint
570
+ state.score = Math.max(0, state.score - 25);
571
+ updateUI();
572
+
573
+ // Play hint sound
574
+ if (state.soundEnabled) {
575
+ playSound('hint');
576
+ }
577
+ }
578
+ }
579
+
580
+ // Event listeners
581
+ newGameButton.addEventListener('click', initGame);
582
+ hintButton.addEventListener('click', provideHint);
583
+ soundToggleButton.addEventListener('click', () => {
584
+ state.soundEnabled = !state.soundEnabled;
585
+ soundToggleButton.innerHTML = state.soundEnabled
586
+ ? '<i class="fas fa-volume-up mr-2"></i> Sound On'
587
+ : '<i class="fas fa-volume-mute mr-2"></i> Sound Off';
588
+ });
589
+ nextLevelButton.addEventListener('click', nextLevel);
590
+ playAgainButton.addEventListener('click', () => {
591
+ gameOverModal.classList.add('hidden');
592
+ initGame();
593
+ });
594
+
595
+ // Initialize the game
596
+ initGame();
597
+ });
598
+ </script>
599
+ </body>
600
+ </html>