2048 Game

2048 Game made with html, css, js

Demo

Some product links are affiliate links which means if you something we'll receive a small commission.

Youtube Link

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" />
    <link rel="stylesheet" href="./style.css" />
    <title>2048</title>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <h1 class="title">2048</h1>
        <div class="score_box">
          <span class="score_title">SCORE</span>
          <strong id="score" class="score">0</strong>
        </div>
      </div>
      <div id="game-board"></div>
      <button id="new-game-btn" class="game_start_button" type="button">New Game</button>
    </div>
    <script src="./index.js"></script>
  </body>
</html>

css

body {
  background-color: #f6f2e9;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0;
}

.container {
  text-align: center;
  width: 412px;
}

.header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}

.score_box {
  background-color: #c8bdae;
  border: 1px solid #baab9f;
  padding: 10px 15px;
  border-radius: 5px;
}

.score_title {
  display: block;
  color: #f2e3da;
}

.score {
  color: #fff;
  font-size: 20px;
  display: block;
  margin-top: 4px;
}

.title {
  font-size: 70px;
  color: #776e65;
  font-weight: 900;
  margin: 0;
}

#game-board {
  width: 400px;
  height: 400px;
  border: 6px solid #baab9f;
  border-radius: 8px;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(4, 1fr);
}

.tile {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 36px;
  font-weight: bold;
  background-color: #c8bdae;
  border: 4px solid #baad9f;
}

.game_start_button {
  background-color: #90786a;
  color: #fff;
  border: 0;
  margin-top: 20px;
  padding: 10px 20px;
  font-size: 18px;
  border-radius: 4px;
}

js

const scoreEl = document.getElementById("score");

let board = [
  [0, 0, 0, 0],
  [0, 0, 0, 0],
  [0, 0, 0, 0],
  [0, 0, 0, 0],
];

let score = 0;

function startGame() {
  board = [
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0],
  ];
  addNewTile();
  addNewTile();
  updateBoard();
}

function addNewTile() {
  const emptyTiles = [];

  for (let row = 0; row < 4; row++) {
    for (let col = 0; col < 4; col++) {
      if (board[row][col] === 0) {
        emptyTiles.push({ row, col });
      }
    }
  }

  if (emptyTiles.length > 0) {
    const randomIndex = Math.floor(Math.random() * emptyTiles.length);
    const { row, col } = emptyTiles[randomIndex];

    const newValue = Math.random() < 0.9 ? 2 : 4;
    board[row][col] = newValue;
  }
}

function updateBoard() {
  const gameBoard = document.getElementById("game-board");
  gameBoard.innerHTML = "";

  for (let row = 0; row < 4; row++) {
    for (let col = 0; col < 4; col++) {
      const tileValue = board[row][col];
      const tile = document.createElement("div");

      tile.className = "tile";
      tile.textContent = tileValue !== 0 ? tileValue : "";

      tile.style.backgroundColor = getTileColor(tileValue);
      tile.style.color = [2, 4, 8].includes(tileValue) ? "#6b6359" : "#fff";

      gameBoard.appendChild(tile);
    }
  }
}

function getTileColor(value) {
  if (value === 0) return "#c8bdae";

  const colors = ["#e7dfd3", "#E7DBBD", "#EFAC73", "#F48E5F", "#EB7A54", "#F45B38", "#E8C96A", "#ECC95C"];

  for (let i in colors) {
    if (2 ** i === value) {
      return colors[i];
    }
  }

  return "#ecc95c";
}

function moveTiles(direction) {
  let tileMoved = false;
  console.log(direction);
  const rowIndices = direction === "up" ? [0, 1, 2, 3] : [3, 2, 1, 0];
  const colIndices = direction === "left" ? [0, 1, 2, 3] : [3, 2, 1, 0];

  for (let row of rowIndices) {
    for (let col of colIndices) {
      const currentValue = board[row][col];

      if (currentValue === 0) continue;

      let newRow = row;
      let newCol = col;
      let currentRow = row;
      let currentCol = col;

      while (true) {
        if (direction === "up") {
          newRow--;
          currentRow = newRow + 1;
        } else if (direction === "down") {
          newRow++;
          currentRow = newRow - 1;
        } else if (direction === "left") {
          newCol--;
          currentCol = newCol + 1;
        } else if (direction === "right") {
          newCol++;
          currentCol = newCol - 1;
        }

        if (newRow < 0 || newRow >= 4 || newCol < 0 || newCol >= 4) {
          newRow -= direction === "up" ? -1 : 1;
          newCol -= direction === "left" ? -1 : 1;
          break;
        }

        const newValue = board[newRow][newCol];

        if (newValue === 0) {
          board[newRow][newCol] = currentValue;
          board[currentRow][currentCol] = 0;
          tileMoved = true;
        } else if (newValue === currentValue) {
          board[newRow][newCol] += currentValue;
          board[currentRow][currentCol] = 0;
          tileMoved = true;
          score += currentValue;
          scoreEl.innerText = score;
          break;
        } else {
          newRow -= direction === "up" ? -1 : 1;
          newCol -= direction === "left" ? -1 : 1;
          break;
        }
      }
    }
  }

  if (tileMoved) {
    addNewTile();
    updateBoard();
  }
}

document.addEventListener("keydown", function (event) {
  console.log(event.key);
  if (event.key === "ArrowUp") {
    moveTiles("up");
  } else if (event.key === "ArrowDown") {
    moveTiles("down");
  } else if (event.key === "ArrowLeft") {
    moveTiles("left");
  } else if (event.key === "ArrowRight") {
    moveTiles("right");
  }
});

const newGameBtn = document.getElementById("new-game-btn");
newGameBtn.addEventListener("click", startGame);

startGame();