DEV Community

artydev
artydev

Posted on

A Very Simple Game in plain JS

You can play with it here SlidingGame:

<html lang="de">
  <head>
    <meta charset="utf-8" />
    <title>title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script src="https://efpage.de/DML/DML_homepage/lib/DML-min.js"></script>
  </head>
  <body>
    <script>
      var dove = new Image();
      dove.src =
        "https://pbs.twimg.com/profile_images/810261498635423745/7Jt0ZuOq_400x400.jpg";
      function sleep(ms) {
        return new Promise((r, err) => {
          setTimeout(r, ms);
        });
      }

      class Board {
        cssCell = `
      background:darkorange;
      height:100px; width:100px;
      margin:0px;cursor:pointer;flex: 0 0 100px;
      display:flex;align-items: center;
      justify-content: center;color: orange; 
      padding: 1px;
    `;

        cssBoard = `
      padding:10px;display:flex;
      flex-wrap:wrap;background:darkorange;
      width:408px;margin:0 auto;
      border-radius: 5px;
    `;

        historypos = [];
        undos = [];
        redos = [];
        undoing = false;
        redoing = false;

        checkValidBoard() {
          function checkPos(c) {
            return c.dataset.pos == c.dataset.curpos;
          }
          return this.cells.every(checkPos);
        }

        findDirectionToMove(cell) {
          const [getCol, getRow] = [
            (pos) => pos % 4,
            (pos) => Math.trunc(pos / 4)
          ];

          const cellpos = Number(cell.dataset.curpos);
          const emptyCellpos = Number(this.emptyCell.dataset.curpos);

          const rowcolEmpty = [getRow(emptyCellpos), getCol(emptyCellpos)];
          const rowcolCell = [getRow(cellpos), getCol(cellpos)];

          const sameColOrRow =
            rowcolEmpty[0] == rowcolCell[0] || rowcolEmpty[1] == rowcolCell[1];

          if (!sameColOrRow) return;

          const directions = {
            [cellpos - 1]: "left",
            [cellpos + 1]: "right",
            [cellpos - 4]: "up",
            [cellpos + 4]: "down"
          };
          let posdir = Object.keys(directions).find(
            (pos) => pos == emptyCellpos
          );
          return directions[posdir];
        }

        findOpositeDirection(direction) {
          if (direction == "up") {
            return "down";
          }
          if (direction == "down") {
            return "up";
          }
          if (direction == "left") {
            return "right";
          }
          if ((direction = "right")) {
            return "left";
          }
        }

        moveCell(cell) {
          const direction = this.findDirectionToMove(cell);
          if (!direction) return;

          const amount = 102;
          const duration = 200;
          const coef = {
            left: -1,
            right: 1,
            down: 1,
            up: -1
          };

          const oppositeDirection = this.findOpositeDirection(direction);

          const cssTranslate = (cell, direction) => {
            if (direction == "left" || direction == "right") {
              cell.dataset.dx =
                Number(cell.dataset.dx) + amount * coef[direction];
            }
            if (direction == "up" || direction == "down") {
              cell.dataset.dy =
                Number(cell.dataset.dy) + amount * coef[direction];
            }
            return `translate(${cell.dataset.dx}px, ${cell.dataset.dy}px )`;
          };

          cell.animate(
            { transform: cssTranslate(cell, direction) },
            { duration: duration, fill: "forwards" }
          );

          this.emptyCell.animate(
            { transform: cssTranslate(this.emptyCell, oppositeDirection) },
            { duration: duration, fill: "forwards" }
          );

          let temp = this.emptyCell.dataset.curpos;
          this.emptyCell.dataset.curpos = cell.dataset.curpos;
          cell.dataset.curpos = temp;

          this.historypos.push(Number(cell.dataset.curpos));

          if (this.undoing == false) this.undos = [...this.historypos];
          this.undoing = false;

          if (this.redoing == false) this.redos = [...this.undos];
          this.redoing = false;
        }

        createCells() {
          // fills cells array with cell element
          this.cells = [...Array(16)].map((_, i) => {
            let y = Math.trunc(i / 4);
            let x = i % 4;
            let options = {
              style: this.cssCell,
              ["data-pos"]: i,
              ["data-curpos"]: i,
              ["data-dx"]: 0,
              ["data-dy"]: 0
            };
            let cell = create("div", options);
            selectBase(cell);
            var canvas = canvas2D({ width: "100px", height: "100px" });
            canvas.ctx.drawImage(
              dove,
              100 * x,
              100 * y,
              100,
              100,
              0,
              0,
              100,
              100
            );
            unselectBase();
            cell.onclick = () => {
              this.moveCell(cell);
            };
            return cell;
          });

          // empty cell customisation
          this.emptyCell = this.cells[15];
          this.emptyCell.style.opacity = "0.25";
          this.emptyCell.style.zIndex = 0;
        }

        displayBoard() {
          selectBase(div(""));
          print("<h1 style='text-align:center'>Sliding Puzzle</h1>");
          unselectBase();

          this.board = selectBase(div("", { style: this.cssBoard }));
          this.cells.map(appendBase);
          unselectBase();

          selectBase(div("", "text-align:center;margin-top:20px"));
          button("Shuffle").onclick = () => this.shuffle();
          button("Reset").onclick = () => {
            this.board.innerHTML = "";
            selectBase(this.board);
            this.createCells();
            this.cells.map(appendBase);
            unselectBase();
          };
          button("undo").onclick = () => {
            if (this.undos.length > 0) {
              this.undoing = true;
              let lastpos = this.undos.splice(-1)[0];
              this.moveCellByCurpos(lastpos);
            }
          };
          button("redo").onclick = () => {
            if (this.redos.length > 0) {
              this.redoing = true;
              let lastpos = this.redos.splice(-1)[0];
              this.moveCellByCurpos(lastpos);
            }
          };
          unselectBase();
        }

        moveCellByCurpos(cellpos) {
          let cell = this.cells.find((cell) => cell.dataset.curpos == cellpos);
          this.moveCell(cell);
        }

        async shuffle() {
          for (let i = 0; i < 100; i++) {
            const emptyPos = Number(this.emptyCell.dataset.curpos);
            const validPos = [
              emptyPos - 1,
              emptyPos + 1,
              emptyPos - 4,
              emptyPos + 4
            ].filter((pos) => {
              return pos >= 0 && pos <= 15;
            });
            const randomPos =
              validPos[Math.floor(Math.random() * validPos.length)];
            await sleep(10);
            this.moveCellByCurpos(randomPos);
          }
        }

        start() {
          this.createCells();
          this.displayBoard();
        }
      }

      function main() {
        dove.onload = () => {
          window.b = new Board();
          b.start();
        };
      }

      main();
    </script>
  </body>
</html>

Enter fullscreen mode Exit fullscreen mode

Top comments (0)