Skip to content

Commit

Permalink
Added Tetris Game (Spandan-Bhattacharya#290)
Browse files Browse the repository at this point in the history
  • Loading branch information
Surajit0573 authored Feb 18, 2024
1 parent eab3963 commit 537e8f2
Show file tree
Hide file tree
Showing 4 changed files with 349 additions and 5 deletions.
271 changes: 271 additions & 0 deletions Tetris/app.js
Original file line number Diff line number Diff line change
@@ -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);
19 changes: 19 additions & 0 deletions Tetris/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<title>Tetris Game</title>
<meta charset="UTF-8">
<link rel="stylesheet" href="./style.css">
</head>
<body background="../assets/bg.webp">
<div id="container">

<canvas width="320" height="640" id="game"></canvas>
<div class="btn">
<button id="restartButton">Restart</button>
<a href="../index.html"><button>Back to Home</button></a>
</div>
</div>
<script src="./app.js"></script>
</body>
</html>
40 changes: 40 additions & 0 deletions Tetris/style.css
Original file line number Diff line number Diff line change
@@ -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;
}
24 changes: 19 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -530,11 +530,11 @@ <h1>2048</h1>
<h3>Game</h3>
<p> Merge numbers to get 2048</p>
<a href="./2048/index.html">
<div class="trynow-button">TRY NOW!</div>
<div class="trynow-button">TRY NOW!</div>
</a>
</div>
</div>
<div class="box game hide">
<div class="box game hide">
<span>Snake Game</span>
<div class="content">
<h1>Snake Game</h1>
Expand All @@ -546,9 +546,23 @@ <h3>Game</h3>
</a>
</div>
</div>
</div>
<!-- GAME SECTION ENDS HERE -->


<div class="box game hide">
<span>Tetris</span>
<div class="content">
<h1>Tetris</h1>
<h3>Game</h3>
<p> Play the Exciting Tetris Game !</p>
<a href="./Tetris/index.html">

<div class="trynow-button">TRY NOW!</div>
</a>
</div>
</div>

</div>
<!-- GAME SECTION ENDS HERE -->



<!-- grid ends -->
Expand Down

0 comments on commit 537e8f2

Please sign in to comment.