offerpk3 commited on
Commit
fecfabc
Β·
verified Β·
1 Parent(s): 1928bb4

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +791 -19
index.html CHANGED
@@ -1,19 +1,791 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Ocean Match-3 Adventure</title>
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ }
13
+
14
+ body {
15
+ font-family: 'Arial', sans-serif;
16
+ background: linear-gradient(135deg, #001f3f 0%, #003366 50%, #006699 100%);
17
+ min-height: 100vh;
18
+ display: flex;
19
+ justify-content: center;
20
+ align-items: center;
21
+ color: white;
22
+ overflow: hidden;
23
+ }
24
+
25
+ .game-container {
26
+ text-align: center;
27
+ background: rgba(255, 255, 255, 0.1);
28
+ backdrop-filter: blur(10px);
29
+ border-radius: 20px;
30
+ padding: 30px;
31
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
32
+ position: relative;
33
+ }
34
+
35
+ h1 {
36
+ font-size: 2.5em;
37
+ margin-bottom: 10px;
38
+ text-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
39
+ background: linear-gradient(45deg, #00d4ff, #90e0ef);
40
+ -webkit-background-clip: text;
41
+ -webkit-text-fill-color: transparent;
42
+ }
43
+
44
+ .game-stats {
45
+ display: grid;
46
+ grid-template-columns: repeat(4, 1fr);
47
+ gap: 15px;
48
+ margin-bottom: 20px;
49
+ font-size: 1em;
50
+ font-weight: bold;
51
+ }
52
+
53
+ .stat-box {
54
+ background: rgba(255, 255, 255, 0.1);
55
+ border-radius: 10px;
56
+ padding: 10px;
57
+ border: 2px solid rgba(0, 212, 255, 0.3);
58
+ }
59
+
60
+ .stat-label {
61
+ font-size: 0.8em;
62
+ opacity: 0.8;
63
+ margin-bottom: 5px;
64
+ }
65
+
66
+ .stat-value {
67
+ font-size: 1.2em;
68
+ color: #00d4ff;
69
+ }
70
+
71
+ .timer {
72
+ color: #ff6b6b !important;
73
+ }
74
+
75
+ .timer.warning {
76
+ animation: timerPulse 1s infinite;
77
+ }
78
+
79
+ @keyframes timerPulse {
80
+ 0%, 100% { transform: scale(1); }
81
+ 50% { transform: scale(1.1); color: #ff4757; }
82
+ }
83
+
84
+ .level-progress {
85
+ margin-bottom: 15px;
86
+ }
87
+
88
+ .progress-bar {
89
+ width: 100%;
90
+ height: 8px;
91
+ background: rgba(255, 255, 255, 0.2);
92
+ border-radius: 4px;
93
+ overflow: hidden;
94
+ }
95
+
96
+ .progress-fill {
97
+ height: 100%;
98
+ background: linear-gradient(90deg, #00d4ff, #90e0ef);
99
+ border-radius: 4px;
100
+ transition: width 0.3s ease;
101
+ width: 0%;
102
+ }
103
+
104
+ .game-board {
105
+ display: grid;
106
+ grid-template-columns: repeat(8, 60px);
107
+ grid-template-rows: repeat(8, 60px);
108
+ gap: 2px;
109
+ background: rgba(0, 50, 100, 0.5);
110
+ padding: 10px;
111
+ border-radius: 15px;
112
+ margin: 0 auto;
113
+ border: 3px solid rgba(255, 255, 255, 0.2);
114
+ position: relative;
115
+ }
116
+
117
+ .tile {
118
+ width: 60px;
119
+ height: 60px;
120
+ display: flex;
121
+ align-items: center;
122
+ justify-content: center;
123
+ font-size: 2em;
124
+ background: linear-gradient(135deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.05));
125
+ border-radius: 10px;
126
+ cursor: pointer;
127
+ transition: all 0.3s ease;
128
+ border: 2px solid transparent;
129
+ position: relative;
130
+ overflow: hidden;
131
+ }
132
+
133
+ .tile:hover {
134
+ transform: scale(1.05);
135
+ box-shadow: 0 5px 15px rgba(0, 212, 255, 0.4);
136
+ }
137
+
138
+ .tile.selected {
139
+ border-color: #00d4ff;
140
+ box-shadow: 0 0 20px rgba(0, 212, 255, 0.8);
141
+ transform: scale(1.1);
142
+ }
143
+
144
+ .tile.matching {
145
+ animation: matchPulse 0.6s ease-in-out;
146
+ background: linear-gradient(135deg, rgba(255, 215, 0, 0.9), rgba(255, 165, 0, 0.9));
147
+ z-index: 10;
148
+ }
149
+
150
+ @keyframes matchPulse {
151
+ 0% { transform: scale(1); }
152
+ 50% { transform: scale(1.3); box-shadow: 0 0 30px rgba(255, 215, 0, 0.8); }
153
+ 100% { transform: scale(1); }
154
+ }
155
+
156
+ @keyframes fall {
157
+ from { transform: translateY(-60px); opacity: 0; }
158
+ to { transform: translateY(0); opacity: 1; }
159
+ }
160
+
161
+ .tile.falling {
162
+ animation: fall 0.4s ease-out;
163
+ }
164
+
165
+ /* Floating animation for matched tiles */
166
+ .floating-tile {
167
+ position: absolute;
168
+ font-size: 2em;
169
+ pointer-events: none;
170
+ z-index: 1000;
171
+ animation: floatDown 2s ease-in forwards;
172
+ }
173
+
174
+ @keyframes floatDown {
175
+ 0% {
176
+ transform: translateY(0) rotate(0deg);
177
+ opacity: 1;
178
+ }
179
+ 100% {
180
+ transform: translateY(600px) rotate(360deg);
181
+ opacity: 0;
182
+ }
183
+ }
184
+
185
+ .controls {
186
+ margin-top: 20px;
187
+ display: flex;
188
+ gap: 15px;
189
+ justify-content: center;
190
+ }
191
+
192
+ button {
193
+ padding: 12px 24px;
194
+ font-size: 1em;
195
+ font-weight: bold;
196
+ border: none;
197
+ border-radius: 25px;
198
+ cursor: pointer;
199
+ background: linear-gradient(135deg, #00d4ff, #0099cc);
200
+ color: white;
201
+ transition: all 0.3s ease;
202
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
203
+ }
204
+
205
+ button:hover {
206
+ transform: translateY(-2px);
207
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3);
208
+ }
209
+
210
+ button:disabled {
211
+ opacity: 0.5;
212
+ cursor: not-allowed;
213
+ transform: none;
214
+ }
215
+
216
+ .hint-text {
217
+ margin-top: 15px;
218
+ font-size: 0.9em;
219
+ opacity: 0.8;
220
+ color: #90e0ef;
221
+ }
222
+
223
+ .level-complete {
224
+ position: fixed;
225
+ top: 50%;
226
+ left: 50%;
227
+ transform: translate(-50%, -50%);
228
+ background: linear-gradient(135deg, #00d4ff, #0099cc);
229
+ padding: 40px;
230
+ border-radius: 20px;
231
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);
232
+ z-index: 2000;
233
+ animation: levelCompleteAnimation 0.5s ease-out;
234
+ }
235
+
236
+ @keyframes levelCompleteAnimation {
237
+ from { transform: translate(-50%, -50%) scale(0); }
238
+ to { transform: translate(-50%, -50%) scale(1); }
239
+ }
240
+
241
+ .game-over {
242
+ position: fixed;
243
+ top: 50%;
244
+ left: 50%;
245
+ transform: translate(-50%, -50%);
246
+ background: linear-gradient(135deg, #ff6b6b, #ff4757);
247
+ padding: 40px;
248
+ border-radius: 20px;
249
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);
250
+ z-index: 2000;
251
+ animation: gameOverAnimation 0.5s ease-out;
252
+ }
253
+
254
+ @keyframes gameOverAnimation {
255
+ from { transform: translate(-50%, -50%) scale(0) rotate(180deg); }
256
+ to { transform: translate(-50%, -50%) scale(1) rotate(0deg); }
257
+ }
258
+
259
+ .sound-toggle {
260
+ position: absolute;
261
+ top: 10px;
262
+ right: 10px;
263
+ background: rgba(255, 255, 255, 0.2);
264
+ border: none;
265
+ border-radius: 50%;
266
+ width: 40px;
267
+ height: 40px;
268
+ cursor: pointer;
269
+ font-size: 1.2em;
270
+ color: white;
271
+ }
272
+ </style>
273
+ </head>
274
+ <body>
275
+ <div class="game-container">
276
+ <button class="sound-toggle" onclick="toggleSound()" id="soundToggle">πŸ”Š</button>
277
+
278
+ <h1>🌊 Ocean Match-3 🌊</h1>
279
+
280
+ <div class="game-stats">
281
+ <div class="stat-box">
282
+ <div class="stat-label">Level</div>
283
+ <div class="stat-value" id="level">1</div>
284
+ </div>
285
+ <div class="stat-box">
286
+ <div class="stat-label">Score</div>
287
+ <div class="stat-value" id="score">0</div>
288
+ </div>
289
+ <div class="stat-box">
290
+ <div class="stat-label">Moves</div>
291
+ <div class="stat-value" id="moves">30</div>
292
+ </div>
293
+ <div class="stat-box">
294
+ <div class="stat-label">Time</div>
295
+ <div class="stat-value timer" id="timer">5:00</div>
296
+ </div>
297
+ </div>
298
+
299
+ <div class="level-progress">
300
+ <div class="stat-label">Level Progress</div>
301
+ <div class="progress-bar">
302
+ <div class="progress-fill" id="progressFill"></div>
303
+ </div>
304
+ <div style="margin-top: 5px; font-size: 0.9em;">
305
+ <span id="matchesLeft">20</span> matches needed
306
+ </div>
307
+ </div>
308
+
309
+ <div class="game-board" id="gameBoard"></div>
310
+
311
+ <div class="controls">
312
+ <button onclick="newGame()">New Game</button>
313
+ <button onclick="findHint()">Hint</button>
314
+ <button onclick="pauseGame()" id="pauseBtn">Pause</button>
315
+ </div>
316
+
317
+ <div class="hint-text">
318
+ Swap adjacent tiles to match 3 or more of the same sea creatures!
319
+ </div>
320
+ </div>
321
+
322
+ <script>
323
+ const BOARD_SIZE = 8;
324
+ const TILE_TYPES = ['🐠', '🐟', '🐑', 'πŸ¦€', 'πŸ™', 'πŸ¦‘'];
325
+
326
+ let board = [];
327
+ let selectedTile = null;
328
+ let score = 0;
329
+ let moves = 30;
330
+ let level = 1;
331
+ let gameActive = true;
332
+ let gamePaused = false;
333
+ let soundEnabled = true;
334
+ let timeLeft = 300; // 5 minutes in seconds
335
+ let gameTimer = null;
336
+ let matchesNeeded = 20;
337
+ let matchesMade = 0;
338
+
339
+ // Sound effects using Web Audio API
340
+ const audioContext = new (window.AudioContext || window.webkitAudioContext)();
341
+
342
+ function playSound(frequency, duration, type = 'sine') {
343
+ if (!soundEnabled) return;
344
+
345
+ const oscillator = audioContext.createOscillator();
346
+ const gainNode = audioContext.createGain();
347
+
348
+ oscillator.connect(gainNode);
349
+ gainNode.connect(audioContext.destination);
350
+
351
+ oscillator.frequency.value = frequency;
352
+ oscillator.type = type;
353
+
354
+ gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
355
+ gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + duration);
356
+
357
+ oscillator.start(audioContext.currentTime);
358
+ oscillator.stop(audioContext.currentTime + duration);
359
+ }
360
+
361
+ function playMatchSound() {
362
+ // Happy match sound - ascending notes
363
+ playSound(523, 0.1); // C
364
+ setTimeout(() => playSound(659, 0.1), 50); // E
365
+ setTimeout(() => playSound(784, 0.2), 100); // G
366
+ }
367
+
368
+ function playNoMatchSound() {
369
+ // Sad "no" sound - descending notes
370
+ playSound(400, 0.3, 'sawtooth');
371
+ setTimeout(() => playSound(300, 0.3, 'sawtooth'), 100);
372
+ }
373
+
374
+ function playLevelCompleteSound() {
375
+ // Victory fanfare
376
+ const notes = [523, 659, 784, 1047];
377
+ notes.forEach((note, i) => {
378
+ setTimeout(() => playSound(note, 0.3), i * 100);
379
+ });
380
+ }
381
+
382
+ function playGameOverSound() {
383
+ // Sad game over sound
384
+ playSound(200, 0.5, 'sawtooth');
385
+ setTimeout(() => playSound(150, 0.8, 'sawtooth'), 200);
386
+ }
387
+
388
+ function toggleSound() {
389
+ soundEnabled = !soundEnabled;
390
+ document.getElementById('soundToggle').textContent = soundEnabled ? 'πŸ”Š' : 'πŸ”‡';
391
+ }
392
+
393
+ function startTimer() {
394
+ gameTimer = setInterval(() => {
395
+ if (!gamePaused && gameActive) {
396
+ timeLeft--;
397
+ updateTimerDisplay();
398
+
399
+ if (timeLeft <= 60) {
400
+ document.getElementById('timer').classList.add('warning');
401
+ }
402
+
403
+ if (timeLeft <= 0) {
404
+ gameOver();
405
+ }
406
+ }
407
+ }, 1000);
408
+ }
409
+
410
+ function updateTimerDisplay() {
411
+ const minutes = Math.floor(timeLeft / 60);
412
+ const seconds = timeLeft % 60;
413
+ document.getElementById('timer').textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`;
414
+ }
415
+
416
+ function pauseGame() {
417
+ gamePaused = !gamePaused;
418
+ const pauseBtn = document.getElementById('pauseBtn');
419
+ pauseBtn.textContent = gamePaused ? 'Resume' : 'Pause';
420
+ }
421
+
422
+ function createFloatingTile(tileType, startX, startY) {
423
+ const floatingTile = document.createElement('div');
424
+ floatingTile.className = 'floating-tile';
425
+ floatingTile.textContent = tileType;
426
+ floatingTile.style.left = startX + 'px';
427
+ floatingTile.style.top = startY + 'px';
428
+
429
+ document.body.appendChild(floatingTile);
430
+
431
+ setTimeout(() => {
432
+ floatingTile.remove();
433
+ }, 2000);
434
+ }
435
+
436
+ function initializeBoard() {
437
+ const gameBoard = document.getElementById('gameBoard');
438
+ gameBoard.innerHTML = '';
439
+ board = [];
440
+
441
+ for (let row = 0; row < BOARD_SIZE; row++) {
442
+ board[row] = [];
443
+ for (let col = 0; col < BOARD_SIZE; col++) {
444
+ let tileType;
445
+ do {
446
+ tileType = TILE_TYPES[Math.floor(Math.random() * TILE_TYPES.length)];
447
+ } while (wouldCreateMatch(row, col, tileType));
448
+
449
+ board[row][col] = tileType;
450
+
451
+ const tile = document.createElement('div');
452
+ tile.className = 'tile';
453
+ tile.textContent = tileType;
454
+ tile.dataset.row = row;
455
+ tile.dataset.col = col;
456
+ tile.addEventListener('click', handleTileClick);
457
+ gameBoard.appendChild(tile);
458
+ }
459
+ }
460
+ }
461
+
462
+ function wouldCreateMatch(row, col, tileType) {
463
+ let horizontalCount = 1;
464
+ for (let c = col - 1; c >= 0 && board[row][c] === tileType; c--) {
465
+ horizontalCount++;
466
+ }
467
+ for (let c = col + 1; c < BOARD_SIZE && board[row] && board[row][c] === tileType; c++) {
468
+ horizontalCount++;
469
+ }
470
+
471
+ let verticalCount = 1;
472
+ for (let r = row - 1; r >= 0 && board[r][col] === tileType; r--) {
473
+ verticalCount++;
474
+ }
475
+ for (let r = row + 1; r < BOARD_SIZE && board[r] && board[r][col] === tileType; r++) {
476
+ verticalCount++;
477
+ }
478
+
479
+ return horizontalCount >= 3 || verticalCount >= 3;
480
+ }
481
+
482
+ function handleTileClick(event) {
483
+ if (!gameActive || gamePaused) return;
484
+
485
+ const clickedTile = event.target;
486
+ const row = parseInt(clickedTile.dataset.row);
487
+ const col = parseInt(clickedTile.dataset.col);
488
+
489
+ if (selectedTile === null) {
490
+ selectedTile = { row, col, element: clickedTile };
491
+ clickedTile.classList.add('selected');
492
+ } else {
493
+ if (selectedTile.row === row && selectedTile.col === col) {
494
+ selectedTile.element.classList.remove('selected');
495
+ selectedTile = null;
496
+ } else if (isAdjacent(selectedTile.row, selectedTile.col, row, col)) {
497
+ attemptSwap(selectedTile.row, selectedTile.col, row, col);
498
+ selectedTile.element.classList.remove('selected');
499
+ selectedTile = null;
500
+ } else {
501
+ selectedTile.element.classList.remove('selected');
502
+ selectedTile = { row, col, element: clickedTile };
503
+ clickedTile.classList.add('selected');
504
+ }
505
+ }
506
+ }
507
+
508
+ function isAdjacent(row1, col1, row2, col2) {
509
+ const rowDiff = Math.abs(row1 - row2);
510
+ const colDiff = Math.abs(col1 - col2);
511
+ return (rowDiff === 1 && colDiff === 0) || (rowDiff === 0 && colDiff === 1);
512
+ }
513
+
514
+ function attemptSwap(row1, col1, row2, col2) {
515
+ const temp = board[row1][col1];
516
+ board[row1][col1] = board[row2][col2];
517
+ board[row2][col2] = temp;
518
+
519
+ const matches = findAllMatches();
520
+
521
+ if (matches.length > 0) {
522
+ updateDisplay();
523
+ moves--;
524
+ document.getElementById('moves').textContent = moves;
525
+
526
+ setTimeout(() => {
527
+ processMatches();
528
+ }, 300);
529
+ } else {
530
+ board[row1][col1] = board[row2][col2];
531
+ board[row2][col2] = temp;
532
+ playNoMatchSound();
533
+ }
534
+ }
535
+
536
+ function findAllMatches() {
537
+ const matches = [];
538
+
539
+ // Find horizontal matches
540
+ for (let row = 0; row < BOARD_SIZE; row++) {
541
+ let count = 1;
542
+ let currentType = board[row][0];
543
+
544
+ for (let col = 1; col < BOARD_SIZE; col++) {
545
+ if (board[row][col] === currentType) {
546
+ count++;
547
+ } else {
548
+ if (count >= 3) {
549
+ for (let i = 0; i < count; i++) {
550
+ matches.push({ row, col: col - count + i });
551
+ }
552
+ }
553
+ count = 1;
554
+ currentType = board[row][col];
555
+ }
556
+ }
557
+
558
+ if (count >= 3) {
559
+ for (let i = 0; i < count; i++) {
560
+ matches.push({ row, col: BOARD_SIZE - count + i });
561
+ }
562
+ }
563
+ }
564
+
565
+ // Find vertical matches
566
+ for (let col = 0; col < BOARD_SIZE; col++) {
567
+ let count = 1;
568
+ let currentType = board[0][col];
569
+
570
+ for (let row = 1; row < BOARD_SIZE; row++) {
571
+ if (board[row][col] === currentType) {
572
+ count++;
573
+ } else {
574
+ if (count >= 3) {
575
+ for (let i = 0; i < count; i++) {
576
+ matches.push({ row: row - count + i, col });
577
+ }
578
+ }
579
+ count = 1;
580
+ currentType = board[row][col];
581
+ }
582
+ }
583
+
584
+ if (count >= 3) {
585
+ for (let i = 0; i < count; i++) {
586
+ matches.push({ row: BOARD_SIZE - count + i, col });
587
+ }
588
+ }
589
+ }
590
+
591
+ return matches;
592
+ }
593
+
594
+ function processMatches() {
595
+ const matches = findAllMatches();
596
+
597
+ if (matches.length === 0) {
598
+ checkGameEnd();
599
+ return;
600
+ }
601
+
602
+ playMatchSound();
603
+
604
+ // Create floating animations for matched tiles
605
+ matches.forEach(match => {
606
+ const tile = document.querySelector(`[data-row="${match.row}"][data-col="${match.col}"]`);
607
+ tile.classList.add('matching');
608
+
609
+ // Get tile position for floating animation
610
+ const rect = tile.getBoundingClientRect();
611
+ createFloatingTile(board[match.row][match.col], rect.left, rect.top);
612
+ });
613
+
614
+ // Update match counter
615
+ matchesMade += Math.floor(matches.length / 3);
616
+ const remaining = Math.max(0, matchesNeeded - matchesMade);
617
+ document.getElementById('matchesLeft').textContent = remaining;
618
+
619
+ // Update progress bar
620
+ const progress = (matchesMade / matchesNeeded) * 100;
621
+ document.getElementById('progressFill').style.width = Math.min(100, progress) + '%';
622
+
623
+ // Add score
624
+ score += matches.length * 10 * level;
625
+ document.getElementById('score').textContent = score;
626
+
627
+ setTimeout(() => {
628
+ matches.forEach(match => {
629
+ board[match.row][match.col] = null;
630
+ });
631
+
632
+ dropTiles();
633
+ fillEmptySpaces();
634
+ updateDisplay();
635
+
636
+ setTimeout(() => {
637
+ processMatches();
638
+ }, 400);
639
+ }, 600);
640
+ }
641
+
642
+ function dropTiles() {
643
+ for (let col = 0; col < BOARD_SIZE; col++) {
644
+ let writeIndex = BOARD_SIZE - 1;
645
+
646
+ for (let row = BOARD_SIZE - 1; row >= 0; row--) {
647
+ if (board[row][col] !== null) {
648
+ board[writeIndex][col] = board[row][col];
649
+ if (writeIndex !== row) {
650
+ board[row][col] = null;
651
+ }
652
+ writeIndex--;
653
+ }
654
+ }
655
+ }
656
+ }
657
+
658
+ function fillEmptySpaces() {
659
+ for (let row = 0; row < BOARD_SIZE; row++) {
660
+ for (let col = 0; col < BOARD_SIZE; col++) {
661
+ if (board[row][col] === null) {
662
+ board[row][col] = TILE_TYPES[Math.floor(Math.random() * TILE_TYPES.length)];
663
+ }
664
+ }
665
+ }
666
+ }
667
+
668
+ function updateDisplay() {
669
+ const tiles = document.querySelectorAll('.tile');
670
+ tiles.forEach(tile => {
671
+ const row = parseInt(tile.dataset.row);
672
+ const col = parseInt(tile.dataset.col);
673
+ tile.textContent = board[row][col];
674
+ tile.classList.remove('matching', 'selected');
675
+ tile.classList.add('falling');
676
+
677
+ setTimeout(() => {
678
+ tile.classList.remove('falling');
679
+ }, 400);
680
+ });
681
+ }
682
+
683
+ function checkGameEnd() {
684
+ if (matchesMade >= matchesNeeded) {
685
+ levelComplete();
686
+ } else if (moves <= 0 || timeLeft <= 0) {
687
+ gameOver();
688
+ }
689
+ }
690
+
691
+ function levelComplete() {
692
+ gameActive = false;
693
+ clearInterval(gameTimer);
694
+ playLevelCompleteSound();
695
+
696
+ const popup = document.createElement('div');
697
+ popup.className = 'level-complete';
698
+ popup.innerHTML = `
699
+ <h2>πŸŽ‰ Level ${level} Complete! πŸŽ‰</h2>
700
+ <p>Score: ${score}</p>
701
+ <p>Time Bonus: ${timeLeft * 5}</p>
702
+ <button onclick="nextLevel()" style="margin-top: 20px;">Next Level</button>
703
+ `;
704
+ document.body.appendChild(popup);
705
+
706
+ score += timeLeft * 5; // Time bonus
707
+ document.getElementById('score').textContent = score;
708
+ }
709
+
710
+ function nextLevel() {
711
+ document.querySelector('.level-complete').remove();
712
+ level++;
713
+ matchesNeeded = 15 + (level * 5);
714
+ matchesMade = 0;
715
+ moves = 30 + (level * 2);
716
+ timeLeft = 300 - (level * 15); // Less time each level
717
+ gameActive = true;
718
+
719
+ document.getElementById('level').textContent = level;
720
+ document.getElementById('moves').textContent = moves;
721
+ document.getElementById('matchesLeft').textContent = matchesNeeded;
722
+ document.getElementById('progressFill').style.width = '0%';
723
+ document.getElementById('timer').classList.remove('warning');
724
+
725
+ initializeBoard();
726
+ startTimer();
727
+ }
728
+
729
+ function gameOver() {
730
+ gameActive = false;
731
+ clearInterval(gameTimer);
732
+ playGameOverSound();
733
+
734
+ const popup = document.createElement('div');
735
+ popup.className = 'game-over';
736
+ popup.innerHTML = `
737
+ <h2>πŸ’€ Game Over! πŸ’€</h2>
738
+ <p>Final Score: ${score}</p>
739
+ <p>Level Reached: ${level}</p>
740
+ <button onclick="document.querySelector('.game-over').remove(); newGame();" style="margin-top: 20px;">Play Again</button>
741
+ `;
742
+ document.body.appendChild(popup);
743
+ }
744
+
745
+ function newGame() {
746
+ score = 0;
747
+ moves = 30;
748
+ level = 1;
749
+ matchesNeeded = 20;
750
+ matchesMade = 0;
751
+ timeLeft = 300;
752
+ gameActive = true;
753
+ gamePaused = false;
754
+ selectedTile = null;
755
+
756
+ clearInterval(gameTimer);
757
+
758
+ document.getElementById('score').textContent = score;
759
+ document.getElementById('moves').textContent = moves;
760
+ document.getElementById('level').textContent = level;
761
+ document.getElementById('matchesLeft').textContent = matchesNeeded;
762
+ document.getElementById('progressFill').style.width = '0%';
763
+ document.getElementById('pauseBtn').textContent = 'Pause';
764
+ document.getElementById('timer').classList.remove('warning');
765
+
766
+ // Remove any existing popups
767
+ const existingPopups = document.querySelectorAll('.level-complete, .game-over');
768
+ existingPopups.forEach(popup => popup.remove());
769
+
770
+ initializeBoard();
771
+ startTimer();
772
+ updateTimerDisplay();
773
+ }
774
+
775
+ function findHint() {
776
+ if (!gameActive || gamePaused) return;
777
+
778
+ const tiles = document.querySelectorAll('.tile');
779
+ const randomTile = tiles[Math.floor(Math.random() * tiles.length)];
780
+
781
+ randomTile.style.animation = 'matchPulse 1s ease-in-out 2';
782
+ setTimeout(() => {
783
+ randomTile.style.animation = '';
784
+ }, 2000);
785
+ }
786
+
787
+ // Initialize the game
788
+ newGame();
789
+ </script>
790
+ </body>
791
+ </html>