{"version":3,"sources":["config.ts","model.ts","animations.ts","view.ts","index.ts"],"names":[],"mappings":"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","file":"src.6872f834.map","sourceRoot":"../src","sourcesContent":["export const width = 5;\nexport const height = 5;\nexport const numCells = width * height;\n","import { width, height, numCells } from './config';\n\nfunction coordinateToIndex(x: number, y: number) {\n  return y * width + x;\n}\n\nfunction indexToCoordinate(i: number) {\n  return [i % width, Math.floor(i / width)];\n}\n\nexport class Model {\n  cells: number[] = new Array(numCells);\n  par = 0;\n  movesUsed = 0;\n\n  constructor() {\n    this.cells.fill(0);\n  }\n\n  /**\n   * Generates a random level where each cell has a `chance` probability of\n   * being toggled.\n   */\n  randomLevel(chance: number = 0.5) {\n    this.cells.fill(0);\n    for (let i = 0; i < this.cells.length; i++) {\n      if (Math.random() < chance) {\n        this.toggleCell(i);\n        this.par++;\n      }\n    }\n    this.par = 0;\n    this.movesUsed = 0;\n  }\n\n  /**\n   * Generates a random level by randomly selecting `moves` many cells and\n   * toggling them.\n   */\n  randomLevelNMoves(moves: number) {\n    this.cells.fill(0);\n    const indices = [];\n    for (let i = 0; i < numCells; i++) indices.push(i);\n    // a Fisher-Yates approach to select items from `indices`...\n    for (let m = 0; m < moves; m++) {\n      const numChoices = numCells - m;\n      const choice = Math.floor(Math.random() * numChoices) + m;\n      [indices[m], indices[choice]] = [indices[choice], indices[m]];\n      this.toggleCell(indices[m]);\n    }\n    this.par = moves;\n    this.movesUsed = 0;\n  }\n\n  toggleCell(i: number) {\n    this.movesUsed++;\n    const [x, y] = indexToCoordinate(i);\n    const candidates = [\n      [x, y], // center\n      [x, y + 1], // top\n      [x, y - 1], // bottom\n      [x - 1, y], // left\n      [x + 1, y], // right\n    ];\n    candidates\n      .filter(([x, y]) => x >= 0 && x < width && y >= 0 && y < height)\n      .forEach(([x, y]) => {\n        this.cells[coordinateToIndex(x, y)] ^= 1;\n      });\n  }\n\n  isSolved(): boolean {\n    return this.cells.every(cell => cell === 0);\n  }\n}\n","import { numCells } from './config';\n\nconst charToCellState: { [key: string]: number } = {\n  '-': 0,\n  '#': 1,\n};\n\n/**\n * Converts an easy-to-author text format that depicts frames of an animation\n * into an array of grid configurations --- one configuration per frame.\n */\nfunction parse(textFrames: string): Array<Array<number>> {\n  const frames = textFrames.split('\\n\\n').map(frame =>\n    frame\n      .split('')\n      .map(char => charToCellState[char])\n      .filter(val => val !== undefined)\n  );\n  frames.forEach(frame => {\n    if (frame.length !== numCells) {\n      throw new Error(\n        `Expected ${numCells} pixels in frame, but frame was: ${frame}`\n      );\n    }\n  });\n  return frames;\n}\n\nexport const diamondExplode = parse(`\n  -----\n  -----\n  -----\n  -----\n  -----\n\n  -----\n  -----\n  --#--\n  -----\n  -----\n\n  -----\n  --#--\n  -###-\n  --#--\n  -----\n\n  --#--\n  -###-\n  #####\n  -###-\n  --#--\n\n  -###-\n  #####\n  #####\n  #####\n  -###-\n\n  #####\n  #####\n  #####\n  #####\n  #####\n\n  #####\n  #####\n  ##-##\n  #####\n  #####\n\n  #####\n  ##-##\n  #---#\n  ##-##\n  #####\n\n  ##-##\n  #---#\n  -----\n  #---#\n  ##-##\n\n  #---#\n  -----\n  -----\n  -----\n  #---#\n\n  -----\n  -----\n  -----\n  -----\n  -----\n`);\n\nexport const diamondIris = parse(`\n  -----\n  -----\n  -----\n  -----\n  -----\n\n  #---#\n  -----\n  -----\n  -----\n  #---#\n\n  ##-##\n  #---#\n  -----\n  #---#\n  ##-##\n\n  #####\n  ##-##\n  #---#\n  ##-##\n  #####\n\n  #####\n  #####\n  ##-##\n  #####\n  #####\n\n  #####\n  #####\n  #####\n  #####\n  #####\n\n  #####\n  #####\n  #####\n  #####\n  #####\n\n  #####\n  #####\n  ##-##\n  #####\n  #####\n\n  #####\n  ##-##\n  #---#\n  ##-##\n  #####\n\n  ##-##\n  #---#\n  -----\n  #---#\n  ##-##\n\n  #---#\n  -----\n  -----\n  -----\n  #---#\n\n  -----\n  -----\n  -----\n  -----\n  -----\n`);\n\nexport const verticalDoors = parse(`\n  -----\n  -----\n  -----\n  -----\n  -----\n\n  #---#\n  #---#\n  #---#\n  #---#\n  #---#\n\n  ##-##\n  ##-##\n  ##-##\n  ##-##\n  ##-##\n\n  #####\n  #####\n  #####\n  #####\n  #####\n\n  #####\n  #####\n  #####\n  #####\n  #####\n\n  #####\n  #####\n  #####\n  #####\n  #####\n\n  ##-##\n  ##-##\n  ##-##\n  ##-##\n  ##-##\n\n  #---#\n  #---#\n  #---#\n  #---#\n  #---#\n\n  -----\n  -----\n  -----\n  -----\n  -----\n`);\n\nexport const wipeRight = parse(`\n  -----\n  -----\n  -----\n  -----\n  -----\n\n  #----\n  #----\n  #----\n  #----\n  #----\n\n  ##---\n  ##---\n  ##---\n  ##---\n  ##---\n\n  ###--\n  ###--\n  ###--\n  ###--\n  ###--\n\n  ####-\n  ####-\n  ####-\n  ####-\n  ####-\n\n  #####\n  #####\n  #####\n  #####\n  #####\n\n  -####\n  -####\n  -####\n  -####\n  -####\n\n  --###\n  --###\n  --###\n  --###\n  --###\n\n  ---##\n  ---##\n  ---##\n  ---##\n  ---##\n\n  ----#\n  ----#\n  ----#\n  ----#\n  ----#\n\n  -----\n  -----\n  -----\n  -----\n  -----\n`);\n\nexport const window = parse(`\n  -----\n  -----\n  -----\n  -----\n  -----\n\n  #####\n  -----\n  -----\n  -----\n  -----\n\n  #####\n  #####\n  -----\n  -----\n  -----\n\n  #####\n  #####\n  #####\n  -----\n  -----\n\n  #####\n  #####\n  #####\n  #####\n  -----\n\n  #####\n  #####\n  #####\n  #####\n  #####\n\n  #####\n  #####\n  #####\n  #####\n  #####\n\n  #####\n  #####\n  #####\n  #####\n  #####\n\n  #####\n  #####\n  #####\n  #####\n  -----\n\n  #####\n  #####\n  #####\n  -----\n  -----\n\n  #####\n  #####\n  -----\n  -----\n  -----\n\n  #####\n  -----\n  -----\n  -----\n  -----\n\n  -----\n  -----\n  -----\n  -----\n  -----\n`);\n","import { numCells } from './config';\nimport { Model } from './model';\n\nimport * as animations from './animations';\n\nexport class View {\n  cellEls: Element[] = [];\n\n  constructor(private model: Model, hostEl: Element) {\n    const gridEl = document.createElement('div');\n    gridEl.classList.add('grid');\n\n    for (let cellIdx = 0; cellIdx < numCells; cellIdx++) {\n      const cellEl = document.createElement('div');\n      cellEl.addEventListener('click', () => {\n        this.toggleCell(cellIdx);\n      });\n      cellEl.classList.add('cell');\n      this.cellEls.push(cellEl);\n      gridEl.appendChild(cellEl);\n    }\n\n    hostEl.appendChild(gridEl);\n    this.newGame();\n  }\n\n  newGame() {\n    this.model.randomLevelNMoves(4);\n    this.render();\n  }\n\n  render() {\n    this.drawFrame(this.model.cells);\n  }\n\n  drawFrame(frame: number[]) {\n    for (let cellIdx = 0; cellIdx < numCells; cellIdx++) {\n      const cellEl = this.cellEls[cellIdx];\n      const cellState = frame[cellIdx];\n      if (cellState === 0) {\n        cellEl.classList.remove('cell--on');\n      } else {\n        cellEl.classList.add('cell--on');\n      }\n    }\n  }\n\n  playAnimation(frames: Array<Array<number>>) {\n    return new Promise(resolve => {\n      let delay = 0;\n      for (let frame of frames) {\n        setTimeout(() => {\n          this.drawFrame(frame);\n        }, delay);\n        delay += 100;\n      }\n      setTimeout(resolve, delay);\n    });\n  }\n\n  toggleCell(i: number) {\n    this.model.toggleCell(i);\n    this.render();\n    if (this.model.isSolved()) {\n      const animation =\n        this.model.movesUsed > this.model.par\n          ? animations.window\n          : animations.diamondExplode;\n      this.playAnimation(animation).then(() => {\n        this.newGame();\n      });\n    }\n  }\n}\n","import { Model } from './model';\nimport { View } from './view';\n\nwindow.addEventListener('load', () => {\n  const model = new Model();\n  new View(model, document.body);\n});\n"]}