DEV Community

artydev
artydev

Posted on

2

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

AWS GenAI LIVE image

Real challenges. Real solutions. Real talk.

From technical discussions to philosophical debates, AWS and AWS Partners examine the impact and evolution of gen AI.

Learn more

Top comments (0)

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay