<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Frogger</title>
<style>
    body {
      background-color: #000;
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      margin: 0;
    }
    .points {
      font-family: monospace;
      color: white;
      position: absolute;
      margin-top: -390px;
    }
    .game-board {
      font-family: monospace;
      line-height: 1.2;
      text-align: center;
      overflow: hidden;
      width: 280px;
      height: 360px;
      border: 2px solid #444;
      position: relative;
    }
    .car {
      position: absolute;
      font-size: 36px;
    }
    .bike {
      position: absolute;
      font-size: 36px;
    }
    .aqua {
      position: absolute;
      font-size: 36px;
    }
    .sqm {
      width: 40px;
      height: 40px;
      position: relative;
      float: left; 
    }
    .water {
      background-color: blue;
    }
    .sidewalk {
      background-color: brown;
    }
    .street {
      background-color: gray;
    }
    .frog {
      position: absolute;
      font-size: 30px;
      color: #fff;
      width: 40px;
      height: 40px;
    }
    .invert {
      transform: rotateY(180deg)
    }
</style>
</head>
<body>
  <h1 class="points">0</h1>

  <div class="game-board">
    <div class="sqm sidewalk end"></div>
    <div class="sqm sidewalk end"></div>
    <div class="sqm sidewalk end"></div>
    <div class="sqm sidewalk end"></div>
    <div class="sqm sidewalk end"></div>
    <div class="sqm sidewalk end"></div>
    <div class="sqm sidewalk end"></div>

    <div class="sqm water"></div>
    <div class="sqm water"></div>
    <div class="sqm water"></div>
    <div class="sqm water"></div>
    <div class="sqm water"></div>
    <div class="sqm water"></div>
    <div class="sqm water"></div>
    <div class="sqm water"></div>
    <div class="sqm water"></div>
    <div class="sqm water"></div>
    <div class="sqm water"></div>
    <div class="sqm water"></div>
    <div class="sqm water"></div>
    <div class="sqm water"></div>
    <div class="sqm water"></div>
    <div class="sqm water"></div>
    <div class="sqm water"></div>
    <div class="sqm water"></div>
    <div class="sqm water"></div>
    <div class="sqm water"></div>
    <div class="sqm water"></div>

    <div class="sqm sidewalk"></div>
    <div class="sqm sidewalk"></div>
    <div class="sqm sidewalk"></div>
    <div class="sqm sidewalk"></div>
    <div class="sqm sidewalk"></div>
    <div class="sqm sidewalk"></div>
    <div class="sqm sidewalk"></div>

    <div class="sqm street"></div>
    <div class="sqm street"></div>
    <div class="sqm street"></div>
    <div class="sqm street"></div>
    <div class="sqm street"></div>
    <div class="sqm street"></div>
    <div class="sqm street"></div>
    <div class="sqm street"></div>
    <div class="sqm street"></div>
    <div class="sqm street"></div>
    <div class="sqm street"></div>
    <div class="sqm street"></div>
    <div class="sqm street"></div>
    <div class="sqm street"></div>
    <div class="sqm street"></div>
    <div class="sqm street"></div>
    <div class="sqm street"></div>
    <div class="sqm street"></div>
    <div class="sqm street"></div>
    <div class="sqm street"></div>
    <div class="sqm street"></div>

    <div class="sqm sidewalk"></div>
    <div class="sqm sidewalk"></div>
    <div class="sqm sidewalk"></div>
    <div class="sqm sidewalk"></div>
    <div class="sqm sidewalk"></div>
    <div class="sqm sidewalk"></div>
    <div class="sqm sidewalk"></div>

    <div class="aqua">🚁</div>
    <div class="aqua">🚣</div>
    <div class="aqua invert">🚣</div>

    <div class="bike">🚴</div>

    <div class="car">🚗</div>
    <div class="car invert">🚓</div>
    <div class="car invert">🚑</div>
    <div class="car">🚗</div>

    <div class="frog">🐸</div>
  </div>

  <script>
    let state;
    const positions = {};
    // 🚁🚑🚣🚴🚓🚛🚎
    const frogEl = document.querySelector('.frog');
    const sqmSize = 40;

    for (let x=0;x<9;x++) {
      for (let y=0;y<8;y++) {
        positions[''+y+x] = {x: sqmSize*y, y: sqmSize*x}
      }
    }

    const initialState = {
      points: 0,
      side: 0,
      sqm: '38',
      objects: [{
        sqm: '65',
        direction: 'L',
        moveFactor: 14,
        timeCounter: 0,
        el: document.querySelectorAll('.car')[0]
      }, {
        sqm: '26',
        direction: 'R',
        moveFactor: 10,
        timeCounter: 0,
        el: document.querySelectorAll('.car')[1]
      }, {
        sqm: '06',
        direction: 'R',
        moveFactor: 10,
        timeCounter: 0,
        el: document.querySelectorAll('.car')[2]
      }, {
        sqm: '67',
        direction: 'L',
        moveFactor: 20,
        timeCounter: 0,
        el: document.querySelectorAll('.car')[3]
      }, {
        sqm: '64',
        direction: 'L',
        moveFactor: 20,
        timeCounter: 0,
        el: document.querySelectorAll('.bike')[0]
      }, {
        sqm: '61',
        direction: 'L',
        moveFactor: 10,
        timeCounter: 0,
        el: document.querySelectorAll('.aqua')[0]
      }, {
        sqm: '02',
        direction: 'R',
        moveFactor: 10,
        timeCounter: 0,
        el: document.querySelectorAll('.aqua')[1]
      }, {
        sqm: '63',
        direction: 'L',
        moveFactor: 20,
        timeCounter: 0,
        el: document.querySelectorAll('.aqua')[2]
      }]
    };

    window.addEventListener("keydown", ({key}) => {
      const {sqm} = state;
      const [x,y] = sqm.split('');
      switch (key) {
        case 'w':
          if (y == 0) return;
          state.sqm = String(x)+(y-1);
        break;
        case 'a':
          if (x == 0) return;
          state.sqm = String(x-1)+y;
        break;
        case 'd':
          if (x == 6) return;
          state.sqm = String(parseInt(x)+1)+y;
        break;
        case 's':
          if (y == 8) return;
          state.sqm = String(x)+(parseInt(y)+1);
        break;
      }
    });

    function eventLoop() {
      frogEl.style.top = positions[state.sqm].y + 'px';
      frogEl.style.left = positions[state.sqm].x + 'px';

      for (let o of state.objects) {
        o.el.style.top = positions[o.sqm].y + 'px';
        o.el.style.left = positions[o.sqm].x + 'px';
        let [x,y] = o.sqm.split('');
        if (o.timeCounter === o.moveFactor && o.direction == 'L') {
          o.sqm = String(x-1>-1 ? x-1 : 7)+y;
          o.timeCounter = 0;
        } else if (o.timeCounter === o.moveFactor && o.direction == 'R') {
          x = parseInt(x);
          o.sqm = String(x+1<7 ? x+1 : 0)+y;
          o.timeCounter = 0;
        }
        o.timeCounter++;
      }
      colisionCheck();
      pointCheck();
      document.querySelector('.points').innerText = state.points;
    }

    function start() {
      state = {...initialState};
    }

    function pointCheck() {
      const [x,y] = state.sqm.split('');
      if (state.side && y == 8) {
        state.points++;
        state.side = 0;
      } else if (state.side == 0 && y == 0) {
        state.points++;
        state.side = 1;
      }
    }

    function colisionCheck() {
      const {sqm, objects} = state;
      for (let o of objects) {
        if (o.sqm === sqm) {
          start();
        }
      }
    }

    start();
    window.setInterval(eventLoop, 20);
  </script>
</body>
</html>

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.