All files / src/lib game.js

0% Statements 0/71
0% Branches 0/24
0% Functions 0/12
0% Lines 0/70

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174                                                                                                                                                                                                                                                                                                                                                           
import { MemoryImageList } from './image-list';
import { MemoryCanvaslist } from './canvas-list';
import { MemoryPairsList } from './pairs-list';
import { Counter } from './counter';
 
/**
 * @classdesc Controls main actions directly related to the game itself.
 * @class
 */
export class Game {
  /**
   * @summary Contruct
   * @param {Array} canvas List of canvas elements to be drawn image on.
   * @param {HTMLImageElement} cardBack Image element to be drown
   * as card back face.
   */
  constructor(canvas, cardBack) {
    // Event Listener Object. This is not actually used as DOM object.
    this.events = document.createElement('div');
 
    this.cardBack = cardBack;
    this.canvas = new MemoryCanvaslist();
    this.images = new MemoryImageList();
 
    this.pairs = new MemoryPairsList();
 
    this.canvas.addCanvas(canvas);
    this.state = [];
    this.counter = new Counter();
    this.prepared = false;
 
    this.cards = {
      open: 0,
      length: 0,
    };
  }
 
  /**
   * @summary Includes given image to the game.
   * @param {HTMLImageElement} img image to be added.
   */
  addImage(img) {
    this.images.push(img);
 
    if (this.images.length === this.canvas.length / 2) {
      this.prepare();
    }
  }
  /**
   * Prepares the Game.
   */
  prepare() {
    const self = this;
 
    self.cards.open = 0;
    self.cards.length = self.images.length;
    this.canvas.forEach((c) => {
      c.addEventListener('click', (e) => {
        if (this.counter.timer.diff === 0) {
          this.counter.start();
        }
        if (e.target.classList.contains('open')) {
          return;
        }
        if (!self.pairs.hasPair(e.target)) {
          const randomPair = self.canvas.randomPair(e.target);
          self.pairs.push(randomPair.concat(self.images.random()));
        }
        switch (self.state.length) {
          case 2: {
            self.closeCard(self.state.pop());
            self.closeCard(self.state.pop());
          }
          case 0: {
            self.state.push(e.target);
 
            self.openCard(e.target);
            break;
          }
          case 1: {
            self.state.push(e.target);
            self.openCard(e.target);
            if (self.pairs.arePairs(self.state)) {
              self.state = [];
              self.cards.open++;
              if (self.cards.open === self.cards.length) {
                self.counter.stop();
                const eventWin = new CustomEvent('win', {});
                self.events.dispatchEvent(eventWin);
              }
            }
            break;
          }
 
          default:
        }
      });
    });
 
    self.prepared = true;
    const delay = 1000 / self.canvas.length;
    self.canvas.forEach((c, i) => {
      setTimeout(() => {
        c.classList.remove('wait');
        self.closeCard(c);
      }, i * delay);
    });
    const eventReady = new CustomEvent('ready', {});
    self.events.dispatchEvent(eventReady);
  }
 
  /**
   * @summary Opens  card by drawing it's image on given canvas.
   * @param {HTMLCanvasElement} canvas Elment to be opened.
   */
  openCard(canvas) {
    const self = this;
    const img = self.pairs.getImage(canvas);
 
    if (img.constructor !== HTMLImageElement) {
      console.warn('Translate-error: no image for the canvas found ');
      return;
    }
    canvas.classList.add('open');
    self.drawImageOnCanvas(canvas, img);
  }
  /**
   * Closes card by drawing cardback image on given canvas.
   * @param {HTMLCanvasElement} canvas Canvas element to be closed.
   */
  closeCard(canvas) {
    const self = this;
    self.drawImageOnCanvas(canvas, self.cardBack);
    canvas.classList.remove('open');
  }
  /**
   * Draws any image on given canvas.
   * @param {HTMLCanvasElement} canvas target element to be drawn on to.
   * @param {HTMLImageElement} image Image drawn on.
   */
  drawImageOnCanvas(canvas, image) {
    const ctx = canvas.getContext('2d');
    ctx.restore();
 
    const props = {
      cw: canvas.width,
      ch: canvas.height,
      iw: image.width,
      ih: image.height,
    };
 
    ctx.clearRect(0, 0, props.cw, props.ch);
    ctx.drawImage(image, 0, 0, props.iw, props.ih, 0, 0, props.cw, props.ch);
  }
  /**
   * Calculates dimensions of next level.
   * @param {{}} options All attriburtes.
   * @return {string} Matrix of the next level.
   */
  nextLevel(options) {
    self = this;
    let col;
    let row;
    [col, row] = options.matrix.split('x').map((n) => parseInt(n));
    col === row ? col++ : row++;
 
    if (col > 10 || row > 10) {
      return '2x2';
    } else {
      return `${col}x${row}`;
    }
  }
}