aboutsummaryrefslogtreecommitdiffstats
path: root/frontend/src/components/Board
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/components/Board')
-rw-r--r--frontend/src/components/Board/TetrisBoard.vue270
1 files changed, 0 insertions, 270 deletions
diff --git a/frontend/src/components/Board/TetrisBoard.vue b/frontend/src/components/Board/TetrisBoard.vue
deleted file mode 100644
index 7528ad7..0000000
--- a/frontend/src/components/Board/TetrisBoard.vue
+++ /dev/null
@@ -1,270 +0,0 @@
-<script setup lang="ts">
-import { ref, type Ref } from 'vue';
-import { mergeTetrominoWithBoard, randomiseNextTetrominoes, tetrominoCollidesWithBoard } from '@/util/tetris';
-import { type Tetromino, allTetrominoes } from '@/model/tetrominoes';
-import { type Board } from '@/model/board';
-
-const renderBoard: Ref<Board> = ref([[]]);
-let gameBoard: Board = [
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-]
-let currentTetromino: Tetromino | null = null;
-let nextTetrominoes: Ref<Array<Tetromino>> = ref([]);
-let gameInterval: ReturnType<typeof setInterval>;
-let gameSpeed = 1000;
-let elapsedBlocks = 0;
-let gameInProgress = false;
-let points = ref(0);
-let notificationMessage = ref('Press start to begin!');
-let notificationBg = ref('\#dfdfdf');
-let notificationFg = ref('black');
-
-function updateRender() {
- if (currentTetromino) {
- renderBoard.value = mergeTetrominoWithBoard(gameBoard, currentTetromino);
- } else {
- renderBoard.value = gameBoard;
- }
-}
-
-
-function rescheduleTickTimer() {
- clearInterval(gameInterval);
- gameInterval = setInterval(tick, gameSpeed);
-}
-
-const tick = () => {
- if (!currentTetromino) {
- let next = nextTetrominoes.value.shift();
- currentTetromino = { ...next! };
- currentTetromino.col = 3;
- if (tetrominoCollidesWithBoard(gameBoard, currentTetromino)) {
- clearInterval(gameInterval);
- notificationBg.value = '\#FF4136';
- notificationFg.value = 'white';
- notificationMessage.value = 'Game over!';
- return;
- }
-
-
- if (nextTetrominoes.value.length === 0) {
- nextTetrominoes.value = randomiseNextTetrominoes();
- }
- }
-
- updateRender();
-
- if (tetrominoCollidesWithBoard(gameBoard, { ...currentTetromino, row: currentTetromino.row + 1 })) {
- gameBoard = mergeTetrominoWithBoard(gameBoard, currentTetromino);
- currentTetromino = null;
- ++elapsedBlocks;
-
- let clears = 0;
- for (let row = 0; row < gameBoard.length; ++row) {
- if (gameBoard[row].every(cell => cell)) {
- clears++;
- gameBoard.splice(row, 1);
- gameBoard.unshift([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
- }
- }
-
- switch (clears) {
- case 1:
- points.value += 40;
- break;
- case 2:
- points.value += 100;
- break;
- case 3:
- points.value += 300;
- break;
- case 4:
- points.value += 1200;
- break;
- }
-
- if (gameSpeed > 150 && elapsedBlocks % 3 === 0) {
- gameSpeed = Math.max(150, gameSpeed - (gameSpeed > 300 ? 75 : 10));
- rescheduleTickTimer();
- }
- return;
- }
-
- ++currentTetromino.row;
-
-};
-
-function startGame() {
- elapsedBlocks = 0;
- gameSpeed = 1000;
- nextTetrominoes.value = randomiseNextTetrominoes();
- gameInProgress = true;
- notificationMessage.value = '';
-
- updateRender();
- rescheduleTickTimer();
-}
-
-document.addEventListener('keydown', event => {
- event.preventDefault();
- if (currentTetromino && event.key === 'r') {
- if (!tetrominoCollidesWithBoard(gameBoard, { ...currentTetromino, rotation: (currentTetromino.rotation + 1) % 4 })) {
- currentTetromino!.rotation = (currentTetromino!.rotation + 1) % 4;
- }
-
- updateRender();
- }
- if (currentTetromino && ['ArrowLeft', 'h'].includes(event.key)) {
- if (!tetrominoCollidesWithBoard(gameBoard, { ...currentTetromino, col: currentTetromino.col - 1 })) {
- --currentTetromino.col;
- }
-
- updateRender();
- }
- if (currentTetromino && ['ArrowRight', 'l'].includes(event.key)) {
- if (!tetrominoCollidesWithBoard(gameBoard, { ...currentTetromino, col: currentTetromino.col + 1 })) {
- ++currentTetromino.col;
- }
-
- updateRender();
- }
- if (currentTetromino && ['ArrowDown', 'j', 'z'].includes(event.key)) {
- if (!tetrominoCollidesWithBoard(gameBoard, { ...currentTetromino, row: currentTetromino.row + 1 })) {
- ++currentTetromino.row;
- }
-
- updateRender();
- }
- if (currentTetromino && ['ArrowUp', 'k', 'c'].includes(event.key)) {
- let rowsDropped = 0;
- while (!tetrominoCollidesWithBoard(gameBoard, { ...currentTetromino, row: currentTetromino.row + 1 })) {
- ++currentTetromino.row;
- ++rowsDropped;
- }
-
- if (rowsDropped === 0) {
- return;
- }
-
- points.value += rowsDropped + 1;
-
- tick();
- }
-});
-</script>
-
-<template>
- <main>
- <h1>Tetris</h1>
- <div class="cols">
- <div>
- <div v-if="notificationMessage" class="notification-banner" :style="{ 'background-color': notificationBg, 'color': notificationFg}">
- {{ notificationMessage }}
- </div>
- <div class="tetris-board">
- <div v-for="(row, rowIndex) of renderBoard" class="tetris-row">
- <div v-for="(col, colIndex) of row" class="tetris-cell"
- :style="{ 'background-color': col ? `rgb(${allTetrominoes[col].color})` : 'white' }">
-
- </div>
- </div>
- </div>
- </div>
- <div class="game-info">
- <button v-if="!gameInProgress" @click="startGame">Start game</button>
- <h2>Next up</h2>
- <div class="next-tetromino">
- <div v-for="(row, rowIndex) of nextTetrominoes[0]?.shapes[0]" class="tetris-row">
- <div v-for="(col, colIndex) of row" class="tetris-cell"
- :style="{ 'background-color': col ? `rgb(${nextTetrominoes[0]?.color})` : 'white' }">
-
- </div>
- </div>
- </div>
-
- <h2>Score</h2>
- <h3>
- {{ points }}
- </h3>
-
- <h2>Controls</h2>
- <p>
- To move left and right, use the arrow keys or <kbd>H</kbd> and <kbd>L</kbd>.
- </p>
-
- <p>
- To rotate, use <kbd>R</kbd>.
- </p>
-
- <p>
- To do a soft drop, use the arrow down key or <kbd>J</kbd>.
- </p>
-
- <p>
- To do a hard drop, use the arrow up key or <kbd>K</kbd>.
- </p>
- </div>
- </div>
-
- </main>
-</template>
-
-<style scoped>
-.cols {
- display: flex;
- flex-direction: row;
- gap: 20px;
-}
-
-.game-info {
- max-width: 250px;
-}
-
-.tetris-board {
- width: calc(32px * 10);
- height: calc(32px * 20);
- border: 1px solid #dfdfdf;
-}
-
-.notification-banner {
- width: calc(32px * 10 + 2px);
- height: 22px;
- text-align: center;
- position: absolute;
-}
-
-.next-tetromino {
- width: calc(32px * 4);
- height: calc(32px * 4);
-}
-
-.tetris-row {
- display: grid;
- grid-template-columns: repeat(10, 1fr);
-}
-
-.tetris-cell {
- width: 30px;
- height: 30px;
- border: 1px solid #dfdfdf;
-}
-</style> \ No newline at end of file