<commit_before>/**
 * Tetrjs is a javascript implementation of Tetris.
 *
 * @author <NAME>
 * @license MIT
 * @version 1.0
 * @link https://github.com/destinmoulton/tetrjs
 */

import util from "./util";
import { BLOCKS, BLOCK_TYPES } from "./blocks";
import { SETTINGS } from "./settings";

/**
 * The constructor.
 * Initializes the basic configuration values.
 * @return void
 */
export default class Tetrjs {
    board = {};

    isPaused = false;

    DOM_IDS = {
        BOARD: "tetrjs-board",
        PREVIEW_CONTAINER: "tetrjs-next-piece-preview-container",
        SCORE_CONTAINER: "tetrjs-score-container",
        LEVEL_CONTAINER: "tetrjs-level-container",
        MODAL: "tetrjs-modal",
        MODAL_VEIL: "tetrjs-modal-veil"
    };

    DOM_CLASSES = {
        BOARD_BLOCK: "tetrjs-board-block"
    };

    currentBlock = {
        type: "",
        blockIds: [],
        blockPositions: [],
        class: "",
        row: SETTINGS.PIECE_START_ROW,
        col: SETTINGS.PIECE_START_COL,
        position: SETTINGS.PIECE_START_POS
    };

    previewPiece = {
        type: "",
        class: "",
        blocks: []
    };

    gameIntervalTimer = {
        obj: false,
        ms: SETTINGS.GAME_INTERVAL_MS
    };

    currentGame = {
        score: 0,
        rowsEliminated: 0,
        level: 1
    };

    /**
     * Setup the Tetrjs board.
     *  1. Clear the board
     *     i. Remove any existing HTML
     *     ii. Clear the multidimensional/matrix board object
     *  2. Set the board width and height (in px)
     *  3. Create the new, clean, board
     *     i. Instantiate the multidimensional/matrix board container
     *     ii. Create div boxes at absolute position to hold blocks
     *
     * @return void
     */
    setupBoard() {
        const elBoard = document.getElementById(this.DOM_IDS.BOARD);

        // Clear the board
        elBoard.innerHTML = "";
        this.board = {};

        // Set the board size
        const boardWidth = SETTINGS.BOARD_COLS_WIDE * SETTINGS.CELL_WIDTH_PX;
        const boardHeight = SETTINGS.BOARD_ROWS_HIGH * SETTINGS.CELL_HEIGHT_PX;
        elBoard.style.width = `${boardWidth}px`;
        elBoard.style.height = `${boardHeight}px`;

        for (let i = 1; i <= SETTINGS.BOARD_ROWS_HIGH; i++) {
            this.board[i] = {};
            const top_pos = (i - 1) * SETTINGS.CELL_HEIGHT_PX;
            for (let j = 1; j <= SETTINGS.BOARD_COLS_WIDE; j++) {
                // Setup the object for storing block positions
                this.board[i][j] = {};

                // Calculate left px position of the cell
                const left_pos = (j - 1) * SETTINGS.CELL_WIDTH_PX;

                // Add the block to the board
                const block = document.createElement("div");
                block.style.left = left_pos.toString() + "px";
                block.style.top = top_pos.toString() + "px";
                block.className = this.DOM_CLASSES.BOARD_BLOCK;
                block.setAttribute("id", `tb_${j}_${i}`);
                elBoard.appendChild(block);
            }
        }
    }

    /**
     * Setup the small preview board to display the next piece.
     *
     * Almost identical to the setupBoard function, except we
     * do not need a multidimensional representation of the board.
     *
     * @return void
     */
    setupPreviewBoard() {
        const elPreviewBoard = document.getElementById(
            this.DOM_IDS.PREVIEW_CONTAINER
        );
        const preview_sections_wide = 6;
        const preview_sections_high = 4;

        // Clear the board
        const boardWidth = preview_sections_wide * SETTINGS.CELL_WIDTH_PX;
        const boardHeight = preview_sections_high * SETTINGS.CELL_HEIGHT_PX;
        elPreviewBoard.innerHTML = "";
        elPreviewBoard.style.width = `${boardWidth}px`;
        elPreviewBoard.style.height = `${boardHeight}px`;

        for (let i = 1; i <= preview_sections_high; i++) {
            const top_pos = (i - 1) * SETTINGS.CELL_HEIGHT_PX;
            for (let j = 1; j <= preview_sections_wide; j++) {
                const left_pos = (j - 1) * SETTINGS.CELL_WIDTH_PX;
                let block = document.createElement("div");
                block.style.top = top_pos + "px";
                block.style.left = left_pos + "px";
                block.className = this.DOM_CLASSES.BOARD_BLOCK;
                block.setAttribute("id", `tp_${j}_${i}`);
                elPreviewBoard.appendChild(block);
            }
        }
    }

    /**
     * Get a random block type.
     *
     * @return string Block type
     */
    generateRandomBlockType() {
        return BLOCK_TYPES[Math.floor(Math.random() * BLOCK_TYPES.length)];
    }

    /**
     * Make the preview block in the preview board.
     *
     * @return void
     */
    makePreviewPiece() {
        if (this.isPaused) {
            return;
        }

        //Remove the current block from the preview
        for (let block_id of this.previewPiece.blocks) {
            const block = document.getElementById(block_id);
            util.removeClass(block, this.previewPiece.class);
        }
        this.previewPiece.blocks = [];

        //Get a random block
        this.previewPiece.type = this.generateRandomBlockType();

        this.previewPiece.class = BLOCKS[this.previewPiece.type]["class"];
        const start_col = 2;
        const start_row = 2;
        const curr_block_position_rows =
            BLOCKS[this.previewPiece.type]["positions"][0]["rows"];

        // Rows are stored as an object-matrix
        const row_keys = Object.keys(curr_block_position_rows);
        for (let row_index of row_keys) {
            const row = curr_block_position_rows[row_index];
            const col_keys = Object.keys(row);
            for (let col_index of col_keys) {
                if (row[col_index] === 1) {
                    const block_col = start_col + parseInt(col_index);
                    const block_row = start_row + parseInt(row_index);
                    const id = "tp_" + block_col + "_" + block_row;
                    const el = document.getElementById(id);
                    util.addClass(el, this.previewPiece.class);

                    this.previewPiece.blocks.push(id);
                }
            }
        }
    }

    /**
     * Move a block on the board.
     * This is mostly called as the keyboard event handler.
     *
     * @return void
     */
    moveBlock(desiredDirection) {
        const curr_block_no_positions =
            BLOCKS[this.currentBlock.type]["no_positions"];
        let currBlockPosTransRow = 0;
        let currBlockPosTransCol = 0;
        let desiredPosition = this.currentBlock.position;

        // 'up' rotates the block
        if (desiredDirection == "up") {
            desiredPosition = this.currentBlock.position + 1;
            if (desiredPosition > curr_block_no_positions - 1) {
                //Reset the transition back to 0<commit_msg>Rebuilt makePreviewPiece<commit_after>/**
 * Tetrjs is a javascript implementation of Tetris.
 *
 * @author <NAME>
 * @license MIT
 * @version 1.0
 * @link https://github.com/destinmoulton/tetrjs
 */

import util from "./util";
import { BLOCKS, BLOCK_TYPES } from "./blocks";
import { SETTINGS } from "./settings";

/**
 * The constructor.
 * Initializes the basic configuration values.
 * @return void
 */
export default class Tetrjs {
    board = [];

    isPaused = false;

    DOM_IDS = {
        BOARD: "tetrjs-board",
        PREVIEW_CONTAINER: "tetrjs-next-piece-preview-container",
        SCORE_CONTAINER: "tetrjs-score-container",
        LEVEL_CONTAINER: "tetrjs-level-container",
        MODAL: "tetrjs-modal",
        MODAL_VEIL: "tetrjs-modal-veil"
    };

    DOM_CLASSES = {
        BOARD_BLOCK: "tetrjs-board-block"
    };

    currentBlock = {
        type: "",
        blockIds: [],
        blockPositions: [],
        class: "",
        row: SETTINGS.PIECE_START_ROW,
        col: SETTINGS.PIECE_START_COL,
        position: SETTINGS.PIECE_START_POS
    };

    previewPiece = {
        type: "",
        class: "",
        blocks: []
    };

    gameIntervalTimer = {
        obj: false,
        ms: SETTINGS.GAME_INTERVAL_MS
    };

    currentGame = {
        score: 0,
        rowsEliminated: 0,
        level: 1
    };

    /**
     * Setup the Tetrjs board.
     *  1. Clear the board
     *     i. Remove any existing HTML
     *     ii. Clear the multidimensional/matrix board object
     *  2. Set the board width and height (in px)
     *  3. Create the new, clean, board
     *     i. Instantiate the multidimensional/matrix board container
     *     ii. Create div boxes at absolute position to hold blocks
     *
     * @return void
     */
    setupBoard() {
        const elBoard = document.getElementById(this.DOM_IDS.BOARD);

        // Clear the board
        elBoard.innerHTML = "";
        this.board = {};

        // Set the board size
        const boardWidth = SETTINGS.BOARD_COLS_WIDE * SETTINGS.CELL_WIDTH_PX;
        const boardHeight = SETTINGS.BOARD_ROWS_HIGH * SETTINGS.CELL_HEIGHT_PX;
        elBoard.style.width = `${boardWidth}px`;
        elBoard.style.height = `${boardHeight}px`;

        for (let i = 1; i <= SETTINGS.BOARD_ROWS_HIGH; i++) {
            this.board[i] = [];
            const top_pos = (i - 1) * SETTINGS.CELL_HEIGHT_PX;
            for (let j = 1; j <= SETTINGS.BOARD_COLS_WIDE; j++) {
                // Setup the object for storing block positions
                this.board[i][j] = {};

                // Calculate left px position of the cell
                const left_pos = (j - 1) * SETTINGS.CELL_WIDTH_PX;

                // Add the block to the board
                const block = document.createElement("div");
                block.style.left = left_pos.toString() + "px";
                block.style.top = top_pos.toString() + "px";
                block.className = this.DOM_CLASSES.BOARD_BLOCK;
                block.setAttribute("id", `tb_${j}_${i}`);
                elBoard.appendChild(block);
            }
        }
    }

    /**
     * Setup the small preview board to display the next piece.
     *
     * Almost identical to the setupBoard function, except we
     * do not need a multidimensional representation of the board.
     *
     * @return void
     */
    setupPreviewBoard() {
        const elPreviewBoard = document.getElementById(
            this.DOM_IDS.PREVIEW_CONTAINER
        );
        const preview_sections_wide = 6;
        const preview_sections_high = 4;

        // Clear the board
        const boardWidth = preview_sections_wide * SETTINGS.CELL_WIDTH_PX;
        const boardHeight = preview_sections_high * SETTINGS.CELL_HEIGHT_PX;
        elPreviewBoard.innerHTML = "";
        elPreviewBoard.style.width = `${boardWidth}px`;
        elPreviewBoard.style.height = `${boardHeight}px`;

        for (let i = 1; i <= preview_sections_high; i++) {
            const top_pos = (i - 1) * SETTINGS.CELL_HEIGHT_PX;
            for (let j = 1; j <= preview_sections_wide; j++) {
                const left_pos = (j - 1) * SETTINGS.CELL_WIDTH_PX;
                let block = document.createElement("div");
                block.style.top = top_pos + "px";
                block.style.left = left_pos + "px";
                block.className = this.DOM_CLASSES.BOARD_BLOCK;
                block.setAttribute("id", `tp_${j}_${i}`);
                elPreviewBoard.appendChild(block);
            }
        }
    }

    /**
     * Get a random block type.
     *
     * @return string Block type
     */
    generateRandomBlockType() {
        return BLOCK_TYPES[Math.floor(Math.random() * BLOCK_TYPES.length)];
    }

    /**
     * Make the preview block in the preview board.
     *
     * @return void
     */
    makePreviewPiece() {
        if (this.isPaused) {
            return;
        }

        //Remove the current block from the preview
        for (let block_id of this.previewPiece.blocks) {
            const block = document.getElementById(block_id);
            util.removeClass(block, this.previewPiece.class);
        }
        this.previewPiece.blocks = [];

        //Get a random block
        this.previewPiece.type = this.generateRandomBlockType();

        this.previewPiece.class = BLOCKS[this.previewPiece.type]["class"];
        const startCol = 2;
        const startRow = 2;
        const blockRows =
            BLOCKS[this.previewPiece.type]["positions"][0]["rows"];

        // Rows are stored as a matrix
        for (let rowIndex = 0; rowIndex < blockRows.length; rowIndex++) {
            const row = blockRows[rowIndex];
            for (let colIndex = 0; colIndex < row.length; colIndex++) {
                if (row[colIndex] === 1) {
                    const blockCol = startCol + colIndex;
                    const blockRow = startRow + rowIndex;
                    const id = "tp_" + blockCol + "_" + blockRow;
                    const el = document.getElementById(id);
                    util.addClass(el, this.previewPiece.class);

                    this.previewPiece.blocks.push(id);
                }
            }
        }
    }

    /**
     * Move a block on the board.
     * This is mostly called as the keyboard event handler.
     *
     * @return void
     */
    moveBlock(desiredDirection) {
        const curr_block_no_positions =
            BLOCKS[this.currentBlock.type]["no_positions"];
        let currBlockPosTransRow = 0;
        let currBlockPosTransCol = 0;
        let desiredPosition = this.currentBlock.position;

        // 'up' rotates the block
        if (desiredDirection == "up") {
            desiredPosition = this.currentBlock.position + 1;
            if (desiredPosition > curr_block_no_positions - 1) {
                //Reset the transition back to 0
{'fraction_non_alphanumeric': 0.10857928240740741, 'fraction_numerical': 0.004050925925925926, 'mean_word_length': 1.8700435955989205, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 7, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7606866', 'n_tokens_mistral': 4258, 'n_tokens_neox': 4070, 'n_words': 954}