DiggerZ

by Aleksey P

HTML

<div class="level_index"></div>
<div id="root">
  <div class="left">
    <div class="button top">▲</div>
    <div class="button middle">◀</div>
    <div class="button bottom">▼</div>
  </div>
  <div class="center">
    <div id="map" tabindex="0"></div>
  </div>
  <div class="right">
    <div class="button top">▲</div>
    <div class="button middle">▶</div>
    <div class="button bottom">▼</div>
  </div>
<div>

CSS

body {
  background: black;
  
  -webkit-touch-callout: none; /* iOS Safari */
    -webkit-user-select: none; /* Safari */
     -khtml-user-select: none; /* Konqueror HTML */
       -moz-user-select: none; /* Firefox */
        -ms-user-select: none; /* Internet Explorer/Edge */
            user-select: none; /* Non-prefixed version, currently
                                  supported by Chrome and Opera */
}

#root {
  position: absolute; 
  top: 0; 
  right: 0; 
  bottom: 0; 
  left: 0;
  /* background: red; */
}

div {
  display: flex;
  flex-direction: row;
}

.button {
  margin: 0px;
  padding: 0px;
  border: dotted 1px #444;
  background: black;
  color: #777;
  width:calc(50vw - 50vh - 2px);
  min-width: 50px;
  height:33vh;
  font-size: 23px;
  align-items: center;
  justify-content: center;
  
}

.button:active { 
    background-color: #5D2B2C;
}

.left, .right {
  flex-direction: column;
}

.center {
  color: #888;
  background: #333;
  width: 100vh;
  align-items: center;
  justify-content: center;
  padding-top:calc(50vh - 50vw + 50px + 2px);
  padding-bottom:calc(50vh - 50vw + 50px + 2px);
  
}

#map {
  background-image: url(https://habrastorage.org/webt/as/uk/g7/asukg71pyaj51_ph7xlzcczmu_y.jpeg);
  background-size: 100%;
  color: #f0f;
  height: 100%;
  width: 100%;
  position: relative;
}

div.level_index {
  position: absolute;
  color: yellow;
  font-size: 20px;
  z-index: 100;
}

JavaScript

"use strict";

function level(mapStorage) {
  let index = 0;
  let map;
  let isGameOver;

  this.reset = () => {
    //index = 0;
    isGameOver = false;
    map = mapStorage().getMap(index);
  };

  this.next = () => map = mapStorage().getMap(++index);
  this.getMap = () => map;
  this.getIndex = () => index;
  this.gameOver = () => isGameOver = true;
  this.getIsGameOver = () => isGameOver;
};


function player(level) {
  this.moveUp = () => this.move(0, -1);
  this.moveDown = () => this.move(0, 1);
  this.moveLeft = () => this.move(-1, 0);
  this.moveRight = () => this.move(1, 0);

  this.move = (dx, dy) => {
    let map = level().getMap();
    let mapSize = map.length;

    let x, y;
    playerFinder:
      for (x = 0; x < mapSize; x++)
        for (y = 0; y < mapSize; y++)
          if (map[x][y] === "P") break playerFinder;

    let newX = x + dx;
    let newY = y + dy;
    if (newX < 0 || newY < 0 || newX > mapSize - 1 || newY > mapSize - 1) {
      return;
    };

    let newPlace = map[newX][newY]
    if (newPlace === "#") {
      return;
    };

    if (newPlace === " ") {
      map[x][y] = " ";
      map[newX][newY] = "P";
      x = newX;
      y = newY;
    };

    if (newPlace === "M") {
      level().gameOver();
    };

    if (newPlace === "E") {
      level().next();
    };
  };
};


function monsters(level) {
  let getDirection = (originalMap, startX, startY) => {
    let map = originalMap.slice().map(x => x.slice()); // local clone
    let mapSize = map.length;

    let x, y;
    playerFinder:
      for (x = 0; x < mapSize; x++)
        for (y = 0; y < mapSize; y++)
          if (map[x][y] === "P") break playerFinder;

    let queue = [];
    queue.push({
      x: x,
      y: y
    });
    map[x][y] = 0;
    map[startX][startY] = mapSize * mapSize;

    let tryAddToQueue = (x, y, i) => {
      if (x >= 0 && y >= 0 && x < mapSize && y < mapSize) {
        if (map[x][y] === " " || (Number.isInteger(map[x][y]) && map[x][y] > i)) {
         ...