diff --git a/Tetris/app.js b/Tetris/app.js new file mode 100644 index 0000000..ad44c03 --- /dev/null +++ b/Tetris/app.js @@ -0,0 +1,271 @@ +document.getElementById('restartButton').addEventListener('click', restartGame); +function restartGame() { + cancelAnimationFrame(rAF); + gameOver = false; + + for (let row = -2; row < playfield.length; row++) { + for (let col = 0; col < playfield[row].length; col++) { + playfield[row][col] = 0; + } + } + + tetrominoSequence.length = 0; + tetromino = getNextTetromino(); + + rAF = requestAnimationFrame(loop); +} +function getRandomInt(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +function generateSequence() { + const sequence = ['I', 'J', 'L', 'O', 'S', 'T', 'Z']; + + while (sequence.length) { + const rand = getRandomInt(0, sequence.length - 1); + const name = sequence.splice(rand, 1)[0]; + tetrominoSequence.push(name); + } +} + +// get the next tetromino in the sequence +function getNextTetromino() { + if (tetrominoSequence.length === 0) { + generateSequence(); + } + + const name = tetrominoSequence.pop(); + const matrix = tetrominos[name]; + + const col = playfield[0].length / 2 - Math.ceil(matrix[0].length / 2); + + const row = name === 'I' ? -1 : -2; + + return { + name: name, + matrix: matrix, + row: row, + col: col + }; +} + +function rotate(matrix) { + const N = matrix.length - 1; + const result = matrix.map((row, i) => + row.map((val, j) => matrix[N - j][i]) + ); + + return result; +} + +function isValidMove(matrix, cellRow, cellCol) { + for (let row = 0; row < matrix.length; row++) { + for (let col = 0; col < matrix[row].length; col++) { + if (matrix[row][col] && ( + cellCol + col < 0 || + cellCol + col >= playfield[0].length || + cellRow + row >= playfield.length || + + playfield[cellRow + row][cellCol + col]) + ) { + return false; + } + } + } + + return true; +} + +function placeTetromino() { + for (let row = 0; row < tetromino.matrix.length; row++) { + for (let col = 0; col < tetromino.matrix[row].length; col++) { + if (tetromino.matrix[row][col]) { + + if (tetromino.row + row < 0) { + return showGameOver(); + } + + playfield[tetromino.row + row][tetromino.col + col] = tetromino.name; + } + } + } + + for (let row = playfield.length - 1; row >= 0;) { + if (playfield[row].every(cell => !!cell)) { + + for (let r = row; r >= 0; r--) { + for (let c = 0; c < playfield[r].length; c++) { + playfield[r][c] = playfield[r - 1][c]; + } + } + } + else { + row--; + } + } + + tetromino = getNextTetromino(); +} + +function showGameOver() { + cancelAnimationFrame(rAF); + gameOver = true; + + context.fillStyle = 'black'; + context.globalAlpha = 0.75; + context.fillRect(0, canvas.height / 2 - 30, canvas.width, 60); + + context.globalAlpha = 1; + context.fillStyle = 'white'; + context.font = '36px monospace'; + context.textAlign = 'center'; + context.textBaseline = 'middle'; + context.fillText('GAME OVER!', canvas.width / 2, canvas.height / 2); +} + +const canvas = document.getElementById('game'); +const context = canvas.getContext('2d'); +const grid = 32; +const tetrominoSequence = []; + +const playfield = []; + +for (let row = -2; row < 20; row++) { + playfield[row] = []; + + for (let col = 0; col < 10; col++) { + playfield[row][col] = 0; + } +} + +const tetrominos = { + 'I': [ + [0, 0, 0, 0], + [1, 1, 1, 1], + [0, 0, 0, 0], + [0, 0, 0, 0] + ], + 'J': [ + [1, 0, 0], + [1, 1, 1], + [0, 0, 0], + ], + 'L': [ + [0, 0, 1], + [1, 1, 1], + [0, 0, 0], + ], + 'O': [ + [1, 1], + [1, 1], + ], + 'S': [ + [0, 1, 1], + [1, 1, 0], + [0, 0, 0], + ], + 'Z': [ + [1, 1, 0], + [0, 1, 1], + [0, 0, 0], + ], + 'T': [ + [0, 1, 0], + [1, 1, 1], + [0, 0, 0], + ] +}; + +const colors = { + 'I': 'cyan', + 'O': 'yellow', + 'T': 'purple', + 'S': 'green', + 'Z': 'red', + 'J': 'blue', + 'L': 'orange' +}; + +let count = 0; +let tetromino = getNextTetromino(); +let rAF = null; +let gameOver = false; + +function loop() { + rAF = requestAnimationFrame(loop); + context.clearRect(0, 0, canvas.width, canvas.height); + + for (let row = 0; row < 20; row++) { + for (let col = 0; col < 10; col++) { + if (playfield[row][col]) { + const name = playfield[row][col]; + context.fillStyle = colors[name]; + + context.fillRect(col * grid, row * grid, grid - 1, grid - 1); + } + } + } + + if (tetromino) { + + if (++count > 35) { + tetromino.row++; + count = 0; + + if (!isValidMove(tetromino.matrix, tetromino.row, tetromino.col)) { + tetromino.row--; + placeTetromino(); + } + } + + context.fillStyle = colors[tetromino.name]; + + for (let row = 0; row < tetromino.matrix.length; row++) { + for (let col = 0; col < tetromino.matrix[row].length; col++) { + if (tetromino.matrix[row][col]) { + + context.fillRect((tetromino.col + col) * grid, (tetromino.row + row) * grid, grid - 1, grid - 1); + } + } + } + } +} + +document.addEventListener('keydown', function (e) { + if (gameOver) return; + + if (e.which === 37 || e.which === 39) { + const col = e.which === 37 + ? tetromino.col - 1 + : tetromino.col + 1; + + if (isValidMove(tetromino.matrix, tetromino.row, col)) { + tetromino.col = col; + } + } + + if (e.which === 38) { + const matrix = rotate(tetromino.matrix); + if (isValidMove(matrix, tetromino.row, tetromino.col)) { + tetromino.matrix = matrix; + } + } + + if (e.which === 40) { + const row = tetromino.row + 1; + + if (!isValidMove(tetromino.matrix, row, tetromino.col)) { + tetromino.row = row - 1; + + placeTetromino(); + return; + } + + tetromino.row = row; + } +}); + +rAF = requestAnimationFrame(loop); \ No newline at end of file diff --git a/Tetris/index.html b/Tetris/index.html new file mode 100644 index 0000000..f2908b4 --- /dev/null +++ b/Tetris/index.html @@ -0,0 +1,19 @@ + + + + Tetris Game + + + + +
+ + +
+ + +
+
+ + + \ No newline at end of file diff --git a/Tetris/style.css b/Tetris/style.css new file mode 100644 index 0000000..b61caa1 --- /dev/null +++ b/Tetris/style.css @@ -0,0 +1,40 @@ +html, body { + height: 100%; + margin: 0; + } + + body { + display: flex; + align-items: center; + justify-content: center; + } + + canvas { + border: 1px solid white; + height: 80%; + } + #container{ + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + height: 100%; + } + + button { + margin-top: 20px; + padding: 10px 20px; + font-size: 16px; + background-color: #1665cc; + color: #fff; + border: none; + border-radius: 4px; + cursor: pointer; + transition: all 0.3s ease; + margin-right: 1rem; +} + +.btn{ + display: flex; + justify-content: space-evenly; +} \ No newline at end of file diff --git a/index.html b/index.html index 70fda08..d1cb876 100644 --- a/index.html +++ b/index.html @@ -530,11 +530,11 @@

2048

Game

Merge numbers to get 2048

-
TRY NOW!
+
TRY NOW!
-
+
Snake Game

Snake Game

@@ -546,9 +546,23 @@

Game

-
- - + +
+ Tetris +
+

Tetris

+

Game

+

Play the Exciting Tetris Game !

+ + +
TRY NOW!
+
+
+
+ + + +