bestofaiml commited on
Commit
91ca8e9
·
verified ·
1 Parent(s): 3c65d7e

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +804 -19
index.html CHANGED
@@ -1,19 +1,804 @@
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>Classic Tetris</title>
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ font-family: 'Arial', sans-serif;
13
+ }
14
+
15
+ body {
16
+ display: flex;
17
+ justify-content: center;
18
+ align-items: center;
19
+ min-height: 100vh;
20
+ background: linear-gradient(135deg, #1e1e2f, #2d2d44);
21
+ color: #fff;
22
+ overflow: hidden;
23
+ }
24
+
25
+ .game-container {
26
+ display: flex;
27
+ gap: 30px;
28
+ align-items: flex-start;
29
+ }
30
+
31
+ #game-board {
32
+ border: 4px solid #4a4a6b;
33
+ border-radius: 5px;
34
+ display: grid;
35
+ grid-template-rows: repeat(20, 1fr);
36
+ grid-template-columns: repeat(10, 1fr);
37
+ gap: 1px;
38
+ background-color: #2a2a3a;
39
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
40
+ width: 300px;
41
+ height: 600px;
42
+ }
43
+
44
+ .cell {
45
+ border: 1px solid rgba(255, 255, 255, 0.05);
46
+ background-color: #2a2a3a;
47
+ }
48
+
49
+ .controls {
50
+ display: flex;
51
+ flex-direction: column;
52
+ gap: 30px;
53
+ }
54
+
55
+ .info-panel {
56
+ background-color: #2a2a3a;
57
+ border: 4px solid #4a4a6b;
58
+ border-radius: 5px;
59
+ padding: 20px;
60
+ width: 180px;
61
+ box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
62
+ }
63
+
64
+ .next-piece-container {
65
+ width: 120px;
66
+ height: 120px;
67
+ display: grid;
68
+ grid-template-rows: repeat(4, 1fr);
69
+ grid-template-columns: repeat(4, 1fr);
70
+ gap: 2px;
71
+ margin-top: 10px;
72
+ margin-bottom: 20px;
73
+ }
74
+
75
+ .next-cell {
76
+ background-color: #3a3a4a;
77
+ border-radius: 2px;
78
+ }
79
+
80
+ h2 {
81
+ font-size: 18px;
82
+ margin-bottom: 10px;
83
+ color: #ddd;
84
+ }
85
+
86
+ .score-display {
87
+ font-size: 24px;
88
+ margin-bottom: 15px;
89
+ color: #fff;
90
+ }
91
+
92
+ .level-display {
93
+ font-size: 18px;
94
+ margin-bottom: 15px;
95
+ color: #fff;
96
+ }
97
+
98
+ .controls-info {
99
+ background-color: #2a2a3a;
100
+ border: 4px solid #4a4a6b;
101
+ border-radius: 5px;
102
+ padding: 20px;
103
+ width: 180px;
104
+ box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
105
+ }
106
+
107
+ .control-item {
108
+ display: flex;
109
+ justify-content: space-between;
110
+ margin-bottom: 10px;
111
+ font-size: 14px;
112
+ color: #ccc;
113
+ }
114
+
115
+ .key {
116
+ background-color: #4a4a6b;
117
+ color: #fff;
118
+ padding: 3px 8px;
119
+ border-radius: 4px;
120
+ font-family: monospace;
121
+ }
122
+
123
+ .game-over {
124
+ position: absolute;
125
+ top: 0;
126
+ left: 0;
127
+ width: 100%;
128
+ height: 100%;
129
+ background-color: rgba(0, 0, 0, 0.8);
130
+ display: flex;
131
+ flex-direction: column;
132
+ justify-content: center;
133
+ align-items: center;
134
+ z-index: 10;
135
+ opacity: 0;
136
+ pointer-events: none;
137
+ transition: opacity 0.3s;
138
+ }
139
+
140
+ .game-over.show {
141
+ opacity: 1;
142
+ pointer-events: all;
143
+ }
144
+
145
+ .game-over h1 {
146
+ font-size: 42px;
147
+ margin-bottom: 20px;
148
+ color: #ff5555;
149
+ }
150
+
151
+ .final-score {
152
+ font-size: 24px;
153
+ margin-bottom: 30px;
154
+ }
155
+
156
+ .restart-btn {
157
+ background-color: #4CAF50;
158
+ color: white;
159
+ border: none;
160
+ padding: 12px 24px;
161
+ font-size: 16px;
162
+ cursor: pointer;
163
+ border-radius: 4px;
164
+ transition: background-color 0.3s;
165
+ }
166
+
167
+ .restart-btn:hover {
168
+ background-color: #45a049;
169
+ }
170
+
171
+ .tetromino-i { background-color: #00f0f0; }
172
+ .tetromino-j { background-color: #0000f0; }
173
+ .tetromino-l { background-color: #f0a000; }
174
+ .tetromino-o { background-color: #f0f000; }
175
+ .tetromino-s { background-color: #00f000; }
176
+ .tetromino-t { background-color: #a000f0; }
177
+ .tetromino-z { background-color: #f00000; }
178
+
179
+ .tetromino-i.ghost { background-color: rgba(0, 240, 240, 0.2); }
180
+ .tetromino-j.ghost { background-color: rgba(0, 0, 240, 0.2); }
181
+ .tetromino-l.ghost { background-color: rgba(240, 160, 0, 0.2); }
182
+ .tetromino-o.ghost { background-color: rgba(240, 240, 0, 0.2); }
183
+ .tetromino-s.ghost { background-color: rgba(0, 240, 0, 0.2); }
184
+ .tetromino-t.ghost { background-color: rgba(160, 0, 240, 0.2); }
185
+ .tetromino-z.ghost { background-color: rgba(240, 0, 0, 0.2); }
186
+
187
+ @media (max-width: 768px) {
188
+ .game-container {
189
+ flex-direction: column;
190
+ align-items: center;
191
+ }
192
+
193
+ .controls {
194
+ flex-direction: row;
195
+ margin-top: 20px;
196
+ }
197
+ }
198
+ </style>
199
+ </head>
200
+ <body>
201
+ <div class="game-container">
202
+ <div id="game-board"></div>
203
+
204
+ <div class="controls">
205
+ <div class="info-panel">
206
+ <h2>Next Piece</h2>
207
+ <div class="next-piece-container" id="next-piece"></div>
208
+
209
+ <h2>Score</h2>
210
+ <div class="score-display" id="score">0</div>
211
+
212
+ <h2>Level</h2>
213
+ <div class="level-display" id="level">1</div>
214
+ </div>
215
+
216
+ <div class="controls-info">
217
+ <h2>Controls</h2>
218
+ <div class="control-item">
219
+ <span>Move Left</span>
220
+ <span class="key">←</span>
221
+ </div>
222
+ <div class="control-item">
223
+ <span>Move Right</span>
224
+ <span class="key">→</span>
225
+ </div>
226
+ <div class="control-item">
227
+ <span>Rotate</span>
228
+ <span class="key">↑</span>
229
+ </div>
230
+ <div class="control-item">
231
+ <span>Soft Drop</span>
232
+ <span class="key">↓</span>
233
+ </div>
234
+ <div class="control-item">
235
+ <span>Hard Drop</span>
236
+ <span class="key">Space</span>
237
+ </div>
238
+ <div class="control-item">
239
+ <span>Pause</span>
240
+ <span class="key">P</span>
241
+ </div>
242
+ </div>
243
+ </div>
244
+ </div>
245
+
246
+ <div class="game-over" id="game-over">
247
+ <h1>GAME OVER</h1>
248
+ <div class="final-score">Score: <span id="final-score">0</span></div>
249
+ <button class="restart-btn" id="restart-btn">Play Again</button>
250
+ </div>
251
+
252
+ <script>
253
+ document.addEventListener('DOMContentLoaded', () => {
254
+ // Game constants
255
+ const COLS = 10;
256
+ const ROWS = 20;
257
+ const BLOCK_SIZE = 30;
258
+ const NEXT_PIECE_COLS = 4;
259
+ const NEXT_PIECE_ROWS = 4;
260
+
261
+ // DOM elements
262
+ const gameBoard = document.getElementById('game-board');
263
+ const nextPieceContainer = document.getElementById('next-piece');
264
+ const scoreDisplay = document.getElementById('score');
265
+ const levelDisplay = document.getElementById('level');
266
+ const gameOverScreen = document.getElementById('game-over');
267
+ const finalScoreDisplay = document.getElementById('final-score');
268
+ const restartBtn = document.getElementById('restart-btn');
269
+
270
+ // Game state
271
+ let board = Array(ROWS).fill().map(() => Array(COLS).fill(0));
272
+ let currentPiece = null;
273
+ let nextPiece = null;
274
+ let currentPosition = { x: 0, y: 0 };
275
+ let score = 0;
276
+ let level = 1;
277
+ let linesCleared = 0;
278
+ let gameOver = false;
279
+ let isPaused = false;
280
+ let dropStart;
281
+ let gameInterval;
282
+
283
+ // Tetromino shapes
284
+ const SHAPES = {
285
+ I: [
286
+ [0, 0, 0, 0],
287
+ [1, 1, 1, 1],
288
+ [0, 0, 0, 0],
289
+ [0, 0, 0, 0]
290
+ ],
291
+ J: [
292
+ [1, 0, 0],
293
+ [1, 1, 1],
294
+ [0, 0, 0]
295
+ ],
296
+ L: [
297
+ [0, 0, 1],
298
+ [1, 1, 1],
299
+ [0, 0, 0]
300
+ ],
301
+ O: [
302
+ [1, 1],
303
+ [1, 1]
304
+ ],
305
+ S: [
306
+ [0, 1, 1],
307
+ [1, 1, 0],
308
+ [0, 0, 0]
309
+ ],
310
+ T: [
311
+ [0, 1, 0],
312
+ [1, 1, 1],
313
+ [0, 0, 0]
314
+ ],
315
+ Z: [
316
+ [1, 1, 0],
317
+ [0, 1, 1],
318
+ [0, 0, 0]
319
+ ]
320
+ };
321
+
322
+ const COLORS = {
323
+ I: 'tetromino-i',
324
+ J: 'tetromino-j',
325
+ L: 'tetromino-l',
326
+ O: 'tetromino-o',
327
+ S: 'tetromino-s',
328
+ T: 'tetromino-t',
329
+ Z: 'tetromino-z'
330
+ };
331
+
332
+ // Initialize game board
333
+ function initBoard() {
334
+ gameBoard.innerHTML = '';
335
+
336
+ for (let row = 0; row < ROWS; row++) {
337
+ for (let col = 0; col < COLS; col++) {
338
+ const cell = document.createElement('div');
339
+ cell.className = 'cell';
340
+ cell.id = `${row}-${col}`;
341
+ gameBoard.appendChild(cell);
342
+ }
343
+ }
344
+ }
345
+
346
+ // Initialize next piece display
347
+ function initNextPieceDisplay() {
348
+ nextPieceContainer.innerHTML = '';
349
+
350
+ for (let row = 0; row < NEXT_PIECE_ROWS; row++) {
351
+ for (let col = 0; col < NEXT_PIECE_COLS; col++) {
352
+ const cell = document.createElement('div');
353
+ cell.className = 'next-cell';
354
+ cell.id = `next-${row}-${col}`;
355
+ nextPieceContainer.appendChild(cell);
356
+ }
357
+ }
358
+ }
359
+
360
+ // Get random tetromino
361
+ function getRandomPiece() {
362
+ const keys = Object.keys(SHAPES);
363
+ const randomKey = keys[Math.floor(Math.random() * keys.length)];
364
+ return {
365
+ shape: SHAPES[randomKey],
366
+ color: COLORS[randomKey],
367
+ type: randomKey
368
+ };
369
+ }
370
+
371
+ // Draw the current piece on the board
372
+ function drawPiece(x, y, piece, isGhost = false) {
373
+ piece.shape.forEach((row, rowIndex) => {
374
+ row.forEach((value, colIndex) => {
375
+ if (value) {
376
+ const boardRow = y + rowIndex;
377
+ const boardCol = x + colIndex;
378
+
379
+ if (boardRow >= 0 && boardRow < ROWS && boardCol >= 0 && boardCol < COLS) {
380
+ const cell = document.getElementById(`${boardRow}-${boardCol}`);
381
+ if (cell) {
382
+ cell.classList.add(piece.color);
383
+ if (isGhost) {
384
+ cell.classList.add('ghost');
385
+ }
386
+ }
387
+ }
388
+ }
389
+ });
390
+ });
391
+ }
392
+
393
+ // Clear the current piece from the board
394
+ function clearPiece(x, y, piece) {
395
+ piece.shape.forEach((row, rowIndex) => {
396
+ row.forEach((value, colIndex) => {
397
+ if (value) {
398
+ const boardRow = y + rowIndex;
399
+ const boardCol = x + colIndex;
400
+
401
+ if (boardRow >= 0 && boardRow < ROWS && boardCol >= 0 && boardCol < COLS) {
402
+ const cell = document.getElementById(`${boardRow}-${boardCol}`);
403
+ if (cell) {
404
+ cell.className = 'cell';
405
+ }
406
+ }
407
+ }
408
+ });
409
+ });
410
+ }
411
+
412
+ // Draw the ghost piece (projection of where the piece will land)
413
+ function drawGhostPiece() {
414
+ let ghostY = currentPosition.y;
415
+ while (!collision(currentPosition.x, ghostY + 1, currentPiece)) {
416
+ ghostY++;
417
+ }
418
+
419
+ if (ghostY !== currentPosition.y) {
420
+ // First clear any existing ghost pieces
421
+ clearGhost();
422
+
423
+ // Draw the new ghost piece
424
+ drawPiece(currentPosition.x, ghostY, currentPiece, true);
425
+ }
426
+ }
427
+
428
+ // Clear all ghost pieces from the board
429
+ function clearGhost() {
430
+ const ghostCells = document.querySelectorAll('.ghost');
431
+ ghostCells.forEach(cell => {
432
+ const className = cell.className;
433
+ const colorClass = className.split(' ').find(cls => cls.startsWith('tetromino-'));
434
+ cell.className = 'cell';
435
+ if (colorClass) {
436
+ cell.classList.remove(colorClass, 'ghost');
437
+ }
438
+ });
439
+ }
440
+
441
+ // Check for collision
442
+ function collision(x, y, piece) {
443
+ for (let row = 0; row < piece.shape.length; row++) {
444
+ for (let col = 0; col < piece.shape[row].length; col++) {
445
+ if (!piece.shape[row][col]) continue;
446
+
447
+ const boardX = x + col;
448
+ const boardY = y + row;
449
+
450
+ if (
451
+ boardX < 0 ||
452
+ boardX >= COLS ||
453
+ boardY >= ROWS ||
454
+ (boardY >= 0 && board[boardY][boardX])
455
+ ) {
456
+ return true;
457
+ }
458
+ }
459
+ }
460
+ return false;
461
+ }
462
+
463
+ // Rotate piece
464
+ function rotate(piece) {
465
+ const N = piece.shape.length;
466
+ const rotated = Array(N).fill().map(() => Array(N).fill(0));
467
+
468
+ // Transpose the matrix
469
+ for (let i = 0; i < N; i++) {
470
+ for (let j = 0; j < N; j++) {
471
+ rotated[i][j] = piece.shape[N - j - 1][i];
472
+ }
473
+ }
474
+
475
+ // Special case for I piece to make it rotate properly
476
+ if (piece.type === 'I') {
477
+ if (currentPosition.x < 0) {
478
+ currentPosition.x = 0;
479
+ } else if (currentPosition.x > COLS - 4) {
480
+ currentPosition.x = COLS - 4;
481
+ }
482
+ }
483
+
484
+ return {
485
+ ...piece,
486
+ shape: rotated
487
+ };
488
+ }
489
+
490
+ // Lock piece in place
491
+ function lockPiece() {
492
+ currentPiece.shape.forEach((row, rowIndex) => {
493
+ row.forEach((value, colIndex) => {
494
+ if (value) {
495
+ const boardRow = currentPosition.y + rowIndex;
496
+ const boardCol = currentPosition.x + colIndex;
497
+
498
+ if (boardRow >= 0) {
499
+ board[boardRow][boardCol] = currentPiece.color;
500
+ }
501
+ }
502
+ });
503
+ });
504
+
505
+ // Check for completed lines
506
+ checkLines();
507
+
508
+ // Check for game over
509
+ if (currentPosition.y <= 0) {
510
+ gameOver = true;
511
+ showGameOver();
512
+ return;
513
+ }
514
+
515
+ // Get next piece
516
+ currentPiece = nextPiece;
517
+ nextPiece = getRandomPiece();
518
+ currentPosition = { x: Math.floor(COLS / 2) - Math.floor(currentPiece.shape[0].length / 2), y: 0 };
519
+
520
+ // Update next piece display
521
+ updateNextPieceDisplay();
522
+
523
+ // Draw the new piece and ghost
524
+ drawPiece(currentPosition.x, currentPosition.y, currentPiece);
525
+ drawGhostPiece();
526
+
527
+ // Reset drop interval
528
+ dropStart = Date.now();
529
+ }
530
+
531
+ // Check for completed lines
532
+ function checkLines() {
533
+ let linesToClear = 0;
534
+
535
+ for (let row = ROWS - 1; row >= 0; row--) {
536
+ if (board[row].every(cell => cell)) {
537
+ linesToClear++;
538
+
539
+ // Shift all rows above down
540
+ for (let y = row; y > 0; y--) {
541
+ board[y] = [...board[y - 1]];
542
+ }
543
+ board[0] = Array(COLS).fill(0);
544
+
545
+ // Since we modified the current row, need to check it again
546
+ row++;
547
+ }
548
+ }
549
+
550
+ if (linesToClear > 0) {
551
+ // Update score
552
+ updateScore(linesToClear);
553
+
554
+ // Redraw the board
555
+ drawBoard();
556
+ }
557
+ }
558
+
559
+ // Update score
560
+ function updateScore(lines) {
561
+ const points = [0, 40, 100, 300, 1200]; // Points for 0, 1, 2, 3, 4 lines
562
+ score += points[lines] * level;
563
+ linesCleared += lines;
564
+
565
+ // Every 10 lines increases the level
566
+ level = Math.floor(linesCleared / 10) + 1;
567
+
568
+ // Update displays
569
+ scoreDisplay.textContent = score;
570
+ levelDisplay.textContent = level;
571
+ }
572
+
573
+ // Draw the entire board
574
+ function drawBoard() {
575
+ for (let row = 0; row < ROWS; row++) {
576
+ for (let col = 0; col < COLS; col++) {
577
+ const cell = document.getElementById(`${row}-${col}`);
578
+ cell.className = 'cell';
579
+
580
+ if (board[row][col]) {
581
+ cell.classList.add(board[row][col]);
582
+ }
583
+ }
584
+ }
585
+ }
586
+
587
+ // Update next piece display
588
+ function updateNextPieceDisplay() {
589
+ // Clear the next piece display
590
+ for (let row = 0; row < NEXT_PIECE_ROWS; row++) {
591
+ for (let col = 0; col < NEXT_PIECE_COLS; col++) {
592
+ const cell = document.getElementById(`next-${row}-${col}`);
593
+ cell.className = 'next-cell';
594
+ }
595
+ }
596
+
597
+ // Draw the next piece in the center
598
+ const startRow = Math.floor((NEXT_PIECE_ROWS - nextPiece.shape.length) / 2);
599
+ const startCol = Math.floor((NEXT_PIECE_COLS - nextPiece.shape[0].length) / 2);
600
+
601
+ for (let row = 0; row < nextPiece.shape.length; row++) {
602
+ for (let col = 0; col < nextPiece.shape[row].length; col++) {
603
+ if (nextPiece.shape[row][col]) {
604
+ const cell = document.getElementById(`next-${startRow + row}-${startCol + col}`);
605
+ if (cell) {
606
+ cell.classList.add(nextPiece.color);
607
+ }
608
+ }
609
+ }
610
+ }
611
+ }
612
+
613
+ // Move piece down
614
+ function moveDown() {
615
+ if (gameOver || isPaused) return;
616
+
617
+ clearPiece(currentPosition.x, currentPosition.y, currentPiece);
618
+ clearGhost();
619
+
620
+ if (!collision(currentPosition.x, currentPosition.y + 1, currentPiece)) {
621
+ currentPosition.y++;
622
+ drawPiece(currentPosition.x, currentPosition.y, currentPiece);
623
+ drawGhostPiece();
624
+ return true;
625
+ } else {
626
+ drawPiece(currentPosition.x, currentPosition.y, currentPiece);
627
+ drawGhostPiece();
628
+ lockPiece();
629
+ return false;
630
+ }
631
+ }
632
+
633
+ // Hard drop
634
+ function hardDrop() {
635
+ if (gameOver || isPaused) return;
636
+
637
+ clearPiece(currentPosition.x, currentPosition.y, currentPiece);
638
+ clearGhost();
639
+
640
+ while (!collision(currentPosition.x, currentPosition.y + 1, currentPiece)) {
641
+ currentPosition.y++;
642
+ }
643
+
644
+ drawPiece(currentPosition.x, currentPosition.y, currentPiece);
645
+ lockPiece();
646
+ dropStart = Date.now();
647
+ }
648
+
649
+ // Move piece left or right
650
+ function movePiece(direction) {
651
+ if (gameOver || isPaused) return;
652
+
653
+ clearPiece(currentPosition.x, currentPosition.y, currentPiece);
654
+ clearGhost();
655
+
656
+ const newX = currentPosition.x + direction;
657
+ if (!collision(newX, currentPosition.y, currentPiece)) {
658
+ currentPosition.x = newX;
659
+ }
660
+
661
+ drawPiece(currentPosition.x, currentPosition.y, currentPiece);
662
+ drawGhostPiece();
663
+ }
664
+
665
+ // Rotate current piece
666
+ function rotatePiece() {
667
+ if (gameOver || isPaused) return;
668
+
669
+ clearPiece(currentPosition.x, currentPosition.y, currentPiece);
670
+ clearGhost();
671
+
672
+ const rotated = rotate(currentPiece);
673
+
674
+ // Wall kick - try moving left/right if rotation would cause a collision
675
+ if (!collision(currentPosition.x, currentPosition.y, rotated)) {
676
+ currentPiece = rotated;
677
+ } else if (!collision(currentPosition.x - 1, currentPosition.y, rotated)) {
678
+ currentPiece = rotated;
679
+ currentPosition.x--;
680
+ } else if (!collision(currentPosition.x + 1, currentPosition.y, rotated)) {
681
+ currentPiece = rotated;
682
+ currentPosition.x++;
683
+ }
684
+
685
+ drawPiece(currentPosition.x, currentPosition.y, currentPiece);
686
+ drawGhostPiece();
687
+ }
688
+
689
+ // Game loop
690
+ function gameLoop() {
691
+ const now = Date.now();
692
+ const delta = now - dropStart;
693
+ const dropInterval = Math.max(1000 - (level - 1) * 100, 100); // Speeds up as level increases
694
+
695
+ if (delta > dropInterval) {
696
+ moveDown();
697
+ dropStart = now;
698
+ }
699
+
700
+ if (!gameOver) {
701
+ requestAnimationFrame(gameLoop);
702
+ }
703
+ }
704
+
705
+ // Show game over screen
706
+ function showGameOver() {
707
+ gameOverScreen.classList.add('show');
708
+ finalScoreDisplay.textContent = score;
709
+ clearInterval(gameInterval);
710
+ }
711
+
712
+ // Reset game
713
+ function resetGame() {
714
+ board = Array(ROWS).fill().map(() => Array(COLS).fill(0));
715
+ score = 0;
716
+ level = 1;
717
+ linesCleared = 0;
718
+ gameOver = false;
719
+ isPaused = false;
720
+
721
+ scoreDisplay.textContent = score;
722
+ levelDisplay.textContent = level;
723
+
724
+ // Initialize pieces
725
+ currentPiece = getRandomPiece();
726
+ nextPiece = getRandomPiece();
727
+ currentPosition = { x: Math.floor(COLS / 2) - Math.floor(currentPiece.shape[0].length / 2), y: 0 };
728
+
729
+ // Clear the board
730
+ drawBoard();
731
+ updateNextPieceDisplay();
732
+
733
+ // Draw current piece and ghost
734
+ drawPiece(currentPosition.x, currentPosition.y, currentPiece);
735
+ drawGhostPiece();
736
+
737
+ // Hide game over screen
738
+ gameOverScreen.classList.remove('show');
739
+
740
+ // Reset drop time and start game loop
741
+ dropStart = Date.now();
742
+ gameLoop();
743
+ }
744
+
745
+ // Pause/unpause the game
746
+ function togglePause() {
747
+ if (gameOver) return;
748
+
749
+ isPaused = !isPaused;
750
+
751
+ if (!isPaused) {
752
+ dropStart = Date.now(); // Reset drop timer
753
+ gameLoop();
754
+ }
755
+ }
756
+
757
+ // Initialize the game
758
+ function init() {
759
+ initBoard();
760
+ initNextPieceDisplay();
761
+
762
+ // Initialize first pieces
763
+ currentPiece = getRandomPiece();
764
+ nextPiece = getRandomPiece();
765
+ currentPosition = { x: Math.floor(COLS / 2) - Math.floor(currentPiece.shape[0].length / 2), y: 0 };
766
+
767
+ updateNextPieceDisplay();
768
+ drawPiece(currentPosition.x, currentPosition.y, currentPiece);
769
+ drawGhostPiece();
770
+
771
+ // Keyboard controls
772
+ document.addEventListener('keydown', event => {
773
+ if (event.key === 'ArrowLeft') {
774
+ movePiece(-1);
775
+ } else if (event.key === 'ArrowRight') {
776
+ movePiece(1);
777
+ } else if (event.key === 'ArrowDown') {
778
+ moveDown();
779
+ } else if (event.key === 'ArrowUp') {
780
+ rotatePiece();
781
+ } else if (event.key === ' ') {
782
+ hardDrop();
783
+ } else if (event.key === 'p' || event.key === 'P') {
784
+ togglePause();
785
+ }
786
+
787
+ // Prevent default for arrow keys and space to avoid scrolling
788
+ if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', ' '].includes(event.key)) {
789
+ event.preventDefault();
790
+ }
791
+ });
792
+
793
+ restartBtn.addEventListener('click', resetGame);
794
+
795
+ // Start game loop
796
+ dropStart = Date.now();
797
+ gameLoop();
798
+ }
799
+
800
+ init();
801
+ });
802
+ </script>
803
+ </body>
804
+ </html>