javascript – Creating a Tetris game

I was following the freecodecamp.org Tetris course, but I changed some things up. I used foreach but the syntax seems right and it matches the freecodecamp.org video syntax so I don’t get what it wants. The problem does not show up every time it shows up when a new Tetromino is coming down or when I rotate the Tetromino too many times. I am getting these errors in the browser console:

Uncaught TypeError: Cannot read properties of undefined (reading 'forEach')
    at draw (app.js:69:13)
    at freeze (app.js:117:9)
    at moveDown (app.js:105:5)
3app.js:75 Uncaught TypeError: Cannot read properties of undefined (reading 'forEach')
    at undraw (app.js:75:13)
    at moveDown (app.js:102:5)
2app.js:75 Uncaught TypeError: Cannot read properties of undefined (reading 'forEach')
    at undraw (app.js:75:13)
    at rotate (app.js:156:5)
    at HTMLDocument.control (app.js:93:10)

HTML:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Tetris</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
    <h3>Score: 0<span id="score"></span></h3>
    <button id="start-button">Start/Pause</button>
    <div class="container">
    <div class="grid"></div>
    <div class="mini-grid"></div>
    </div>
    <script src="app.js"></script>
</body>
</html>

JS:

const grid = document.querySelector(".grid");
const miniGrid = document.querySelector(".mini-grid");
const scoreDisplay = document.querySelector("#score");
const startButton = document.querySelector("#start-button");
const width = 10;

for (let i = 1; i <= 210; i++) {
    var divs = document.createElement('div');
    if (i >= 201) {
        divs.classList.add('taken');
    }
        grid.appendChild(divs);
    }

    for (let i = 1; i <= 16; i++) {
        var div = document.createElement('div');
        miniGrid.appendChild(div);
    }    

const squares = Array.from(document.querySelectorAll(".grid div"));

//The Tetrominoes

const lTetromino = [
    [1, width + 1, width * 2 + 1, 2],
    [width, width + 1, width + 2, width * 2 + 2],
    [1, width + 1, width * 2 + 1, width * 2],
    [width, width * 2, width * 2 + 1, width * 2 + 2]
]

const zTetromino = [
    [width * 2, width + 1, width * 2 + 1, width + 2],
    [0, width, width + 1, width * 2 + 1]
    [width * 2, width + 1, width * 2 + 1, width + 2],
    [0, width, width + 1, width * 2 + 1]
]

const tTetromino = [
    [width, 1, width + 1, width + 2],
    [1, width + 1, width * 2 + 1, width + 2],
    [width, width + 1, width * 2 + 1, width + 2],
    [width, 1, width + 1, width * 2 + 1]
]

const sTetromino = [
    [0, width, 1, width +1],
    [0, width, 1, width +1],
    [0, width, 1, width +1],
    [0, width, 1, width +1]
]

const iTetromino = [
    [1, width + 1, width * 2 + 1, width * 3 + 1],
    [width, width + 1, width + 2, width + 3]
    [1, width + 1, width * 2 + 1, width * 3 + 1],
    [width, width + 1, width + 2, width + 3]
]

const theTetrominoes = [lTetromino, zTetromino, tTetromino, sTetromino, iTetromino];

let random = Math.floor(Math.random() * 4);
let currentRotation = Math.floor(Math.random() * 3);
let currentPosition = Math.floor(Math.random() * 7);
let current = theTetrominoes[random][currentRotation];

//draw the first rotation in the first teromino

function draw () {
    current.forEach(index => {
        squares[currentPosition + index].classList.add('tetromino');
    })
}

function undraw () {
    current.forEach(index => {
        squares[currentPosition + index].classList.remove('tetromino');
    })
}

//moving down

 timerId = setInterval(moveDown, 350);

 //assign functions to keyCodes

 function control(e) {
     if (e.keyCode === 37) {
         moveLeft();
     } else if (e.keyCode === 39) {
         moveRight();
       
     } else if (e.keyCode === 38) {
         rotate();

     } //else if (e.keyCode === 38) {

     //}
 }
 document.addEventListener('keyup', control);

 function moveDown() {
    undraw();
    currentPosition += width;
    draw();
    freeze();
}

//freeze function

function freeze() {
    if (current.some(index => squares[currentPosition + width + index].classList.contains('taken'))) {
        current.forEach(index => squares[currentPosition + index].classList.add('taken'));
        //start a new tetromino
        random = Math.floor(Math.random() * 4);
        currentPosition = Math.floor(Math.random() * 7);
        current = theTetrominoes[random][currentRotation];
        draw();
    }
}

//move the tetromino left, unless is at the edge or there is a blockage

function moveLeft() {
    undraw();
    const isAtLeftEdge = current.some(index => (currentPosition + index) % width === 0)

    if (!isAtLeftEdge) {
        currentPosition -= 1;
    }

    if (current.some(index => squares[currentPosition + index].classList.contains('taken'))) {
        currentPosition += 1;
    }

    draw();
}

function moveRight() {
    undraw();
    const isAtRightEdge = current.some(index => (currentPosition + index) % width === 9)

    if (!isAtRightEdge) {
        currentPosition += 1;
    }

    if (current.some(index => squares[currentPosition + index].classList.contains('taken'))) {
        currentPosition -= 1;
    }

    draw();
}

//rotate the tetromino

function rotate() {
    undraw();
    currentRotation ++;
    if(currentRotation === current.length) {
        currentRotation = 0;
    }
    current = theTetrominoes[random][currentRotation];
    draw();
}

CSS:

.container {
        display: flex;
}

.grid {
        width: 200px;
        height: 400px;
        display: flex;
        flex-wrap: wrap;
        background-color: yellow;
    }
    
    .grid div {
        height: 20px;
        width: 20px;
    }
    
    .mini-grid {
        margin-left: 50px;
        width: 80px;
        height: 80px;
        display: flex;
        flex-wrap: wrap;
        background-color: yellow;
    }
    
    .mini-grid div {
        height: 20px;
        width: 20px;
    }
    
    .tetromino {
        background-color: blue;
    }

Leave a Comment