<commit_before>Store = new Persist.Store('High Score');

Cell = function (state, game, x, y) {
  this.state = state;
  this.grid = state.grid;
  this.game = game;
  this.x = x;
  this.y = y;

  this.circle = game.add.sprite(60 + (x * 120), 378 + (y * 120), 'circles');
  this.circle.anchor.setTo(0.5, 0.5);
  for (var i = 0; i < 9; i++) {
    this.circle.animations.add('' + (i + 1), [ i ]);
  }
  this.circle.animations.add('x', [ 9, 10, 9, 10, 9], 20);
  this.circle.animations.add('x-no-anim', [ 9 ]);

  this.roll();
  this.circle.inputEnabled = true;
  this.circle.events.onInputDown.add(this.click, this);

  this.connector = game.add.sprite(x * 120, 320 + (y * 120), 'connectors');
  this.connector.scale.setTo(2, 2);

  this.connector.animations.add('none', [ 0 ]);
  this.connector.animations.add('dot', [ 1 ]);
  this.connector.animations.add('up', [ 2 ]);
  this.connector.animations.add('right', [ 3 ]);
  this.connector.animations.add('down', [ 4 ]);
  this.connector.animations.add('left', [ 5 ]);
  this.connector.animations.add('up-right', [ 6 ]);
  this.connector.animations.add('right-down', [ 7 ]);
  this.connector.animations.add('down-left', [ 8 ]);
  this.connector.animations.add('left-up', [ 9 ]);
  this.connector.animations.add('up-down', [ 10 ]);
  this.connector.animations.add('right-left', [ 11 ]);
  this.connector.animations.add('right-up', [ 6 ]);
  this.connector.animations.add('down-right', [ 7 ]);
  this.connector.animations.add('left-down', [ 8 ]);
  this.connector.animations.add('up-left', [ 9 ]);
  this.connector.animations.add('down-up', [ 10 ]);
  this.connector.animations.add('left-right', [ 11 ]);

  this.tagged = false;
  this.prev = null;

};

Cell.prototype = {
  roll: function() {
    this.value = (Math.floor(Math.random() * 9) + 1);
    this.circle.play('' + this.value);
  },

  reroll: function(delay) {
    this.connector.play('none');
    this.roll();
    this.prev = null;
    this.tagged = false;
    this.circle.scale.setTo(0, 0);
    this.tween = this.game.add.tween(this.circle.scale).to( { x: 1, y: 1 }, 150, Phaser.Easing.Linear.None, true, delay * 15);
  },

  changeToBlocker: function () {
    this.value = 0;
    if (this.tween !== undefined && this.tween.isRunning) {
      this.circle.play('x-no-anim');
    } else {
      this.circle.play('x');
    }
  },

  removeBlocker: function () {
    this.circle.scale.setTo(0, 0);
    this.roll();
    this.game.add.tween(this.circle.scale).to( { x: 1, y: 1 }, 150, Phaser.Easing.Linear.None, true);
  },

  click: function () {
    // ignore clicks when game is not running
    // or when blockers are clicked
    if (!this.state.gameRunning || this.value === 0) {
      return;
    }
    if (this.state.taggingStarted) {
      var clicked = this;

      if (this.state.tagEnd.prev === this) {
        clicked = this.state.tagEnd;
      }
      if (this.state.tagEnd === clicked) {
        this.displayRipple();
        if (clicked.prev === null) {
          this.state.taggingStarted = false;
          this.state.tagEnd = null;
          clicked.tagged = false;
          clicked.clearConnector();
        } else {
          this.state.tagEnd = clicked.prev;
          clicked.tagged = false;
          clicked.prev.displayConnectorEnd();
          clicked.prev = null;
          clicked.clearConnector();
        }
      } else if (this.tagged === true) {
        return;
      } else if (this.adjacentTo(this.state.tagEnd)) {
        this.displayRipple();
        this.prev = this.state.tagEnd;
        this.prev.displayConnectorMid(this);
        this.state.tagEnd = this;
        this.displayConnectorEnd();
        this.tagged = true;
      }
    } else {
      this.displayRipple();
      this.state.taggingStarted = true;
      this.state.tagEnd = this;
      this.tagged = true;
      this.displayConnectorEnd();
    }
    this.state.checkSum();
    //console.log(this.grid[this.x - 1][this.y - 1])
  },

  adjacentTo: function(endCell) {
    return ((Math.abs(this.x - endCell.x) < 2 && this.y === endCell.y) || 
            (Math.abs(this.y - endCell.y) < 2 && this.x === endCell.x));
  },

  clearConnector: function() {
    this.connector.play('none');
  },

  displayConnectorMid: function(next) {
    var direction = "";
    if (this.rightOf(next)) {
      direction = 'left';
    }
    if (this.leftOf(next)) {
      direction = 'right';
    }
    if (this.bottomOf(next)) {
      direction = 'up';
    }
    if (this.topOf(next)) {
      direction = 'down';
    }
    if (this.prev === null) {
      this.connector.play(direction);
    } else {
      if (this.rightOf(this.prev)) {
        this.connector.play(direction + '-left');
      } else if (this.leftOf(this.prev)) {
        this.connector.play(direction + '-right');
      } else if (this.bottomOf(this.prev)) {
        this.connector.play(direction + '-up');
      } else if (this.topOf(this.prev)) {
        this.connector.play(direction + '-down');
      }
    }
  },

  displayConnectorEnd: function() {
    if (this.prev === null) {
      this.connector.play('dot');
    } else if (this.rightOf(this.prev)) {
      this.connector.play('left');
    } else if (this.leftOf(this.prev)) {
      this.connector.play('right');
    } else if (this.bottomOf(this.prev)) {
      this.connector.play('up');
    } else if (this.topOf(this.prev)) {
      this.connector.play('down');
    }
  },

  rightOf: function(other) {
    return (this.x === other.x + 1 && this.y === other.y);
  },

  leftOf: function(other) {
    return (this.x === other.x - 1 && this.y === other.y);
  },

  bottomOf: function(other) {
    return (this.y === other.y + 1 && this.x === other.x);
  },

  topOf: function(other) {
    return (this.y === other.y - 1 && this.x === other.x);
  },

  displayRipple: function() {
    var ripple = this.state.ripples.getFirstExists(false);
    if (ripple !== null) {
      ripple.reset(this.x * 120 + 60, 380 + (this.y * 120));
      ripple.play('ripple', 10, false, true);
    }
  }

};


BasicGame.Game = function (game) {

};

BasicGame.Game.prototype = {

  create: function () {

    this.stage.backgroundColor = '#ddd';

    this.grid = [];
    for (var x = 0; x < 8; x++) {
      var column = [];
      for (var y = 0; y < 8; y++) {
        var cell = new Cell(this, this.game, x, y);
        column.push(cell);
      }
      this.grid.push(column);
    }

    this.ripples = this.add.group();
    this.ripples.createMultiple(10, 'ripple');
    this.ripples.setAll('anchor.x', 0.5);
    this.ripples.setAll('anchor.y', 0.5);
    this.ripples.forEach(function (ripple) {
      ripple.animations.add('ripple', [ 0, 1, 2, 3, 4, 5, 6, 7]);
    }, this);

    this.gameRunning = true;
    this.taggingStarted = false;
    this.tagEnd = null;

    this.score = 0;
    this.timeLimit = 90.0;

    this.prevHighScore = Store.get("highScore");
    if (this.prevHighScore === null) {
      this.prevHighScore = 0;
    } else {
      this.prevHighScore = parseInt(this.prevHighScore);
    }

    this.curHighScore = this.prevHighScore;

    this.prevBestTime = Store.get("bestTime");
    if (this.prevBestTime === null) {
      this.prevBestTime = 90.0;
    } else {
      this.prevBestTime = parseFloat(this.prevBestTime);
    }

    this.prevMillionTime = Store.get("bestMillionTime");
    this.millionTime = null;

    this.highScoreText = this.add.text(480, 55, "HIGH SCORE: " + this.prevHighScore, { font: "30px Roboto Mono", fill: "#222"});
    this.highScoreText.anchor.setTo(0.5, 0.5);

    this.scoreHeader = this.add.text(180, 110, "SCORE", { font: "30px Roboto Mono", fill: "#222"});
    this.scoreHeader.anchor.setTo(0.5, 0.5);
    this.add.text(780, 110, "TIME LEFT", { font: "30px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
    this.add.text(480, 110, "SUM", { font: "30px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);

    this.scoreText = this.add.text(180, 160, this.score, { font: "60px 'Roboto Mono'", fill: "#444"});
    this.scoreText.anchor.setTo(0.5, 0.5);


    this.timeText = this.add.text(780, 160, this.timeLimit, { font: "60px Roboto Mono", fill: "#444"});
    this.timeText.anchor.setTo(0.5, 0.5);

    this.addScoreGroup = this.add.group();
    this.highScoreGroup = this.add.group();
    this.addTimeGroup = this.add.group();
    this.resultGroup = this.add.group();
    this.result2Group = this.add.group();
    for (var i = 0; i < 5; i++) {
      var addScoreText = this.add.text(180, 160, "", { font: "50px 'Roboto Mono'", fill: "#080"});
      addScoreText.anchor.setTo(0.5, 0.5);
      addScoreText.kill();
      this.addScoreGroup.add(addScoreText);

      var highScoreText = this.add.text(180, 55, "", { font: "30px 'Roboto Mono'", fill: "#080"});
      highScoreText.anchor.setTo(0.5, 0.5);
      highScoreText.kill();
      this.highScoreGroup.add(highScoreText);

      var addTimeText = this.add.text(780, 160, "", { font: "50px 'Roboto Mono'", fill: "#080"});
      addTimeText.anchor.setTo(0.5, 0.5);
      addTimeText.kill();
      this.addTimeGroup.add(addTimeText);

      var resultText = this.add.text(480, 250, "", { font: "40px 'Roboto Mono'", fill: "#080"});
      resultText.anchor.setTo(0.5, 0.5);
      resultText.kill();
      this.resultGroup.add(resultText);

      var result2Text = this.add.text(480, 250, "", { font: "40px 'Roboto Mono'", fill: "#080"});
      result2Text.anchor.setTo(0.5, 0.5);
      result2Text.kill();
      this.result2Group.add(result2Text);
    }

    this.sumText = this.add.text(480, 190, '?', { font: "150px 'Roboto Mono'", fill: "#222"});
    this.sumText.anchor.setTo(0.5, 0.5);

    this.pointsText = this.add.text(480, 270, "0 digits, 0 points", { font: "30px Roboto Mono", fill: "#222"});
    this.pointsText.anchor.setTo(0.5, 0.5);

    this.time.reset();

    this.primeTable = [ false,
      false, true, true, false, true, false, true, false, false, false,
      true, false, true, false, false, false, true, false, true, false,
      false, false, true, false, false, false, false, false, true, false,
      true, false, false, false, false, false, true, false, false, false,
      true, false, true, false, false, false, true, false, false, false,
      false, false, true, false, false, false, false, false, true, false,
      true, false, false, false
    ];
    this.colorTable = [ "#444", "#41dbdb", "#b40561", "#9cff2e", "#710a92",
      "#f8ed2d", "#501095", "#febd2e", "#2b1e98", "#fe642c" ];
    this.blockers = [];
  },

  update: function () {
    var timeLeft = this.timeLimit - this.time.totalElapsedSeconds();
    if (timeLeft > 0 && this.blockers.length < 64) { 
      var text = Math.floor(timeLeft);
      if (text !== this.timeText.text) {
        this.timeText.text = text;
      }

      if (this.timeText.style.fill === '#444' && timeLeft < 16) {
        this.timeText.style.fill = '#d44';
        this.timeText.style.font = '700 65px Roboto Mono';
      } else if (this.timeText.style.fill === '#d44' && timeLeft > 16) {
        this.timeText.style.fill = '#444';
        this.timeText.style.font = '60px Roboto Mono';
      } 
    } else if (this.gameRunning) {
      this.endGame(timeLeft);
    }
    this.handleDragging();
  },

  handleDragging: function () {
    var pointer = this.input.activePointer;
    if (pointer.isDown) {
      //console.log(pointer.x + " " + pointer.y);
      //console.log(this.cellAt(pointer.x, pointer.y));
      if (this.dragging === undefined || !this.dragging) {
        this.dragging = true;
        this.lastClicked = this.cellAt(pointer.x, pointer.y);
      } else {
        var over = this.cellAt(pointer.x, pointer.y);
        if (this.lastClicked !== over) {
          if (over !== null && over !== undefined) {
            over.click();
          }
          this.lastClicked = over;
        }
      }
    } else if (pointer.isUp) {
      this.dragging = false;
    }
  },

  cellAt: function (x, y) {
    if (y < 320) {
      return null;
    }
    var newX = Math.floor(x/120);
    var newY = Math.floor((y-320)/120);
    if (newX >= 0 && newX < 8 && newY >= 0 && newX < 8) {
      return this.grid[newX][newY];
    } else {
      return null;
    }
  },

  checkSum: function () {
    var length = 0;
    var sum = 0;
    var cur = this.tagEnd;
    while (cur !== null) {
      sum += cur.value;
      length++;
      cur = cur.prev;
    }
    if (length > 1 && sum % 10 === 0) {

      this.score += this.calculatePoints(sum);
      
      if (this.score < 1000000) {
        this.scoreText.text = this.score;
      } else {
        if (this.millionTime === null) {
          this.millionTime = this.time.totalElapsedSeconds();
        }
        if (this.score <= 9999999999) {
          this.scoreHeader.text = "CONGRATULATIONS!";
        } else {
          this.scoreHeader.text = "PLEASE STOP";
        }
        this.displayColoredScore();
      }

      if (this.score > this.curHighScore) {
        Store.set("highScore", this.score);
        this.highScoreText.text = "HIGH SCORE: " + this.score;
        var highScoreText = this.highScoreGroup.getFirstExists(false);
        if (highScoreText !== null) {
          highScoreText.reset(480, 55);
          highScoreText.text = "            +" + (this.score - this.curHighScore);
          highScoreText.alpha = 1;
          var tween0 = this.add.tween(highScoreText).to( { alpha: 0, y: -25 }, 3000, Phaser.Easing.Linear.None, true);
          tween0.onComplete.add(function(text) {
            text.kill();
          }, this);
        }
        this.curHighScore = this.score;
      }

      var addScoreText = this.addScoreGroup.getFirstExists(false);
      if (addScoreText !== null) {
        addScoreText.reset(180, 100);
        addScoreText.text = "+" + this.calculatePoints(sum);
        addScoreText.alpha = 1;
        var tween = this.add.tween(addScoreText).to( { alpha: 0, y: 20 }, 3000, Phaser.Easing.Linear.None, true);
        tween.onComplete.add(function(text) {
          text.kill();
        }, this);
      }

      // clear all ripple animations and reroll cells
      this.ripples.forEachAlive(function(ripple) {
        ripple.kill();
      }, this);

      cur = this.tagEnd;
      var index = length;
      while (cur !== null) {
        var prev = cur.prev;
        cur.reroll(index--);
        cur = prev;
      }
      this.taggingStarted = false;
      this.tagEnd = null;

      this.sumText.text = "?";
      this.pointsText.text = "0 digits, 0 points";

      // TODO if prime, roll for removal of blocks but no bonus time
      // else, roll for creation of blocks

      var clearMessage = "";
      var blockerMessage = null;
      var clearFill = "#080";
      var addTime = "";
      if (this.primeTable[length]) {
        var removed = this.rollBlockRemoval(length);

        this.timeLimit += length * 1.0 / 2;
        addTime = "+" + Math.floor(length / 2);

        clearMessage = length + " - Prime";
        if (removed > 0) {
          blockerMessage = removed + " blocker" + (removed == 1 ? "" : "s") + " cleared";
          clearFill = "#a80";
        }
      } else {
        var added = this.rollBlockCreation(length);
        this.timeLimit += length * 2;

        addTime = "+" + length * 2;

        clearMessage = length + " - Composite";
        if (added > 0) {
          blockerMessage = added + " blocker" + (added === 1 ? "" : "s") + " added";
          clearFill = "#a01";
        }
      }
      
      var resultText = this.resultGroup.getFirstExists(false);
      var result2Text = this.result2Group.getFirstExists(false);

      if (resultText !== null && result2Text !== null) {
        resultText.reset(480, 250);
        resultText.alpha = 1;
        resultText.style.fill = clearFill;
        resultText.text = clearMessage;
        if (blockerMessage !== null) {
          resultText.y = 185;
          result2Text.reset(480, 230);
          result2Text.alpha = 1;
          result2Text.style.fill = clearFill;
          result2Text.text = blockerMessage;

          var rTween = this.add.tween(resultText).to( { alpha: 0, y: -25 }, 3000, Phaser.Easing.Linear.None, true);
          rTween.onComplete.add(function (text) { text.kill(); }, this);

          var rTween2 = this.add.tween(result2Text).to( { alpha: 0, y: 20 }, 3000, Phaser.Easing.Linear.None, true);
          rTween2.onComplete.add(function (text) { text.kill(); }, this);
        } else {
          resultText.y = 230;
          var rTween3 = this.add.tween(resultText).to( { alpha: 0, y: 20 }, 3000, Phaser.Easing.Linear.None, true);
          rTween3.onComplete.add(function (text) { text.kill(); }, this);
        }
      }

      if (this.timeLimit > this.prevBestTime) {
        Store.set("bestTime", this.timeLimit);
      }

      var addTimeText = this.addTimeGroup.getFirstExists(false);
      if (addTimeText !== null) {
        addTimeText.reset(780, 100);
        addTimeText.text = addTime;
        addTimeText.alpha = 1;
        var tween2 = this.add.tween(addTimeText).to( { alpha: 0, y: 20 }, 3000, Phaser.Easing.Linear.None, true);
        tween2.onComplete.add(function(text) {
          text.kill();
        }, this);
      }
    } else {
      if (sum === 0) {
        this.sumText.text = "?";
        this.pointsText.text = "0 digits, 0 points";
      } else {
        this.sumText.text = sum % 10;
        this.pointsText.text = length + " digit" + (length == 1 ? "" : "s") + 
          (this.primeTable[length + 1] ? " (prime next)" : "") + ", " + 
          this.calculatePoints(sum) + " point" + (this.calculatePoints(sum) == 1 ? "" : "s");
      }
    }
  },

  calculatePoints: function (sum) {
    return Math.pow(Math.floor(sum / 10), 3) * 5;
  },

  rollBlockRemoval: function (length) {
    //console.log(this.blockers);
    if (this.blockers.length === 0) {
      return 0;
    }
    var removed = 0;
    for (var i = 0; i < length; i++) {
      // per digit, there's a 1 in 5 chance of removing a block
      if (Math.random() * 5 < 1) {
        var delIdx = Math.floor(Math.random() * this.blockers.length);
        // reroll selected
        this.blockers[delIdx].removeBlocker();
        // remove from list
        this.blockers.splice(delIdx, 1);

        removed++;
         
        if (this.blockers.length === 0) {
          break;
        }
      }
    }
    return removed;
  },

  rollBlockCreation: function (length) {
    //console.log(this.blockers);
    var added = 0;
    for (var i = 0; i < length; i++) {
      // per digit, there's a 1 in 5 chance of removing a block
      if (Math.random() * 4 < 1) {
        var cell = null;
        while (cell === null) {
          var x = Math.floor(Math.random() * 8);
          var y = Math.floor(Math.random() * 8);
          if (this.grid[x][y].value !== 0) {
            cell = this.grid[x][y];
          }
        }

        cell.changeToBlocker();

        this.blockers.push(cell);
        added++;

        if (this.blockers.length === 64) {
          break;
        }
      }
    }
    return added;
  },

  timeToText: function (seconds) {
    var hours = Math.floor(seconds / 3600);
    var remainingSecs = seconds - hours * 3600;
    var minutes = Math.floor(remainingSecs / 60);
    remainingSecs = remainingSecs - minutes * 60;
    var ms = remainingSecs % 1;
    remainingSecs = Math.floor(remainingSecs);

    var text = "";
    if (hours > 0) {
      text += hours + ":";
    }
    text += ("0" + minutes).slice(-2)  + ":";
    text += ("0" + Math.floor(remainingSecs)).slice(-2)  + "." + ("0" + Math.floor(ms * 10)).slice(-1);
    return text;
  },

  displayColoredScore: function () {
    if (this.scoreText.text !== "") {
      this.scoreText.text = "";
    }
    if (this.milText === undefined || this.milText === null || !this.milText[0].alive) {
      this.milText = [];
      for (var i = 0; i < 10; i++) {
        var text = this.add.text(180, 160, "", { font: "700 64px 'Roboto Mono'", fill: "#444"});
        text.anchor.setTo(0.5, 0.5);
        this.milText.push(text);
      }
    }
    var scoreStr = "" + this.score;
    for (var j = 0; j < 10 && j < scoreStr.length; j++) {
      this.milText[j].x = 160 + (scoreStr.length / 2 * 38) - (j * 38);
      this.milText[j].style.fill = this.colorTable[Math.floor(Math.random() * 10)];
      this.milText[j].text = scoreStr.substr(scoreStr.length - 1 - j, 1);
    }
  },

  endGame: function (timeLeft) {
    this.gameRunning = false;

    if (timeLeft <= 0) {
      this.timeText.text = "0";
    }

    this.overlay = this.add.sprite(100, 300, "overlay");

    this.add.text(480, 400, "Game Over", { font: "64px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
    
    var runText = null;
    var milText = null;
    if (this.millionTime !== null) { 
      runText = this.add.text(480, 463, "Run Time - " + this.timeToText(this.timeLimit), { font: "30px Roboto Mono", fill: "#222"});
      runText.anchor.setTo(0.5, 0.5);
      milText = this.add.text(480, 497, "Million reached at " + this.timeToText(this.millionTime), { font: "30px Roboto Mono", fill: "#222"});
      milText.anchor.setTo(0.5, 0.5);
    } else {
      runText = this.add.text(480, 480, "Run Time: " + this.timeToText(this.timeLimit), { font: "36px Roboto Mono", fill: "#222"});
      runText.anchor.setTo(0.5, 0.5);
    }

    var newHighScore = false;
    if (this.score > this.prevHighScore) {
      newHighScore = true;
    }
    var newBestTime = false;
    if (this.timeLimit > this.prevBestTime) {
      newBestTime = true;
    }
    var newMillionTime = false;
    if (this.millionTime !== null && 
        ( (this.prevMillionTime !== null && parseFloat(this.prevMillionTime) > this.millionTime) ||
          (this.prevMillionTime === null) ) ) {
      Store.set("bestMillionTime", this.millionTime);
      newMillionTime = true;
    }
    
    if (newHighScore) {
      if (newBestTime) {
        if (newMillionTime) {
          this.add.text(480, 570, "New High Score!", { font: "44px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
          this.add.text(480, 620, "New Longest Run!", { font: "44px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
          this.add.text(480, 670, "New Fastest Million!", { font: "44px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
        } else {
          this.add.text(480, 595, "New High Score!", { font: "48px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
          this.add.text(480, 645, "New Longest Run!", { font: "48px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
        }
      } else {
        if (newMillionTime) {
          this.add.text(480, 595, "New High Score!", { font: "48px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
          this.add.text(480, 645, "New Fastest Million!", { font: "48px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
        } else {
          this.add.text(480, 620, "New High Score!", { font: "56px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
        }
      }
    } else if (newBestTime) {
      if (newMillionTime) {
        this.add.text(480, 595, "New Longest Run!", { font: "48px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
        this.add.text(480, 645, "New Fastest Million!", { font: "48px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
      } else {
        this.add.text(480, 620, "New Longest Run!", { font: "56px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
      }
    } else if (newMillionTime) {
      this.add.text(480, 620, "New Fastest Million!", { font: "56px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
    } else {
      runText.y += 100;
      if (milText !== null) {
        milText.y += 100;
      }
    }

    this.add.text(480, 770, "Previous Bests", { font: "40px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
    this.add.text(480, 820, "High Score - " + this.prevHighScore, { font: "28px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
    this.add.text(480, 850, "Longest Run - " + this.timeToText(this.prevBestTime), { font: "28px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);

    if (this.prevMillionTime !== null) {
      this.add.text(480, 880, "Fastest Million - " + this.timeToText(this.prevMillionTime, true), { font: "28px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
    }

    this.time.events.add(1000, function () {
      this.add.text(480, 960, "Tap/click to return to main menu", { font: "32px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
      this.overlay.inputEnabled = true;
      this.overlay.events.onInputDown.add(this.quitGame, this);
    }, this);

    this.addSocialBar();
  },

  addSocialBar: function() {
    this.overlay = this.add.sprite(100, 1080, "social");
    this.add.text(480, 1100, "share this on", { font: "28px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);

    var fullUrl, ogUrl, text, url, icon;

    url = encodeURIComponent("http://zero.karaniwan.org/");
    ogUrl = encodeURIComponent("http://zero.karaniwan.org/<%= image_path "screenshot.png" %>");

    text = encodeURIComponent("I got " + this.score + " points in \"zero\", a mathematical puzzle game. Try beating my score!");

    fullUrl = "https://www.facebook.com/dialog/share?app_id=944062788970440&href=" + url + "&display=page&redirect_uri=https://facebook.com";
    icon = this.add.sprite(200, 1170, "social-buttons");
    icon.anchor.setTo(0.5, 0.5);
    icon.animations.add('s', [ 0 ]);
    icon.play('s');
    icon.inputEnabled = true;
    icon.events.onInputDown.add(function() {
      var win = window.open(this, '_blank');
      win.focus();  
    }, fullUrl);


    fullUrl = "https://twitter.com/intent/tweet?url=" + url + "&text=" + text;
    icon = this.add.sprite(340, 1170, "social-buttons");
    icon.anchor.setTo(0.5, 0.5);
    icon.animations.add('s', [ 1 ]);
    icon.play('s');
    icon.inputEnabled = true;
    icon.events.onInputDown.add(function() {
      var win = window.open(this, '_blank');<commit_msg>Fix screenshot<commit_after>Store = new Persist.Store('High Score');

Cell = function (state, game, x, y) {
  this.state = state;
  this.grid = state.grid;
  this.game = game;
  this.x = x;
  this.y = y;

  this.circle = game.add.sprite(60 + (x * 120), 378 + (y * 120), 'circles');
  this.circle.anchor.setTo(0.5, 0.5);
  for (var i = 0; i < 9; i++) {
    this.circle.animations.add('' + (i + 1), [ i ]);
  }
  this.circle.animations.add('x', [ 9, 10, 9, 10, 9], 20);
  this.circle.animations.add('x-no-anim', [ 9 ]);

  this.roll();
  this.circle.inputEnabled = true;
  this.circle.events.onInputDown.add(this.click, this);

  this.connector = game.add.sprite(x * 120, 320 + (y * 120), 'connectors');
  this.connector.scale.setTo(2, 2);

  this.connector.animations.add('none', [ 0 ]);
  this.connector.animations.add('dot', [ 1 ]);
  this.connector.animations.add('up', [ 2 ]);
  this.connector.animations.add('right', [ 3 ]);
  this.connector.animations.add('down', [ 4 ]);
  this.connector.animations.add('left', [ 5 ]);
  this.connector.animations.add('up-right', [ 6 ]);
  this.connector.animations.add('right-down', [ 7 ]);
  this.connector.animations.add('down-left', [ 8 ]);
  this.connector.animations.add('left-up', [ 9 ]);
  this.connector.animations.add('up-down', [ 10 ]);
  this.connector.animations.add('right-left', [ 11 ]);
  this.connector.animations.add('right-up', [ 6 ]);
  this.connector.animations.add('down-right', [ 7 ]);
  this.connector.animations.add('left-down', [ 8 ]);
  this.connector.animations.add('up-left', [ 9 ]);
  this.connector.animations.add('down-up', [ 10 ]);
  this.connector.animations.add('left-right', [ 11 ]);

  this.tagged = false;
  this.prev = null;

};

Cell.prototype = {
  roll: function() {
    this.value = (Math.floor(Math.random() * 9) + 1);
    this.circle.play('' + this.value);
  },

  reroll: function(delay) {
    this.connector.play('none');
    this.roll();
    this.prev = null;
    this.tagged = false;
    this.circle.scale.setTo(0, 0);
    this.tween = this.game.add.tween(this.circle.scale).to( { x: 1, y: 1 }, 150, Phaser.Easing.Linear.None, true, delay * 15);
  },

  changeToBlocker: function () {
    this.value = 0;
    if (this.tween !== undefined && this.tween.isRunning) {
      this.circle.play('x-no-anim');
    } else {
      this.circle.play('x');
    }
  },

  removeBlocker: function () {
    this.circle.scale.setTo(0, 0);
    this.roll();
    this.game.add.tween(this.circle.scale).to( { x: 1, y: 1 }, 150, Phaser.Easing.Linear.None, true);
  },

  click: function () {
    // ignore clicks when game is not running
    // or when blockers are clicked
    if (!this.state.gameRunning || this.value === 0) {
      return;
    }
    if (this.state.taggingStarted) {
      var clicked = this;

      if (this.state.tagEnd.prev === this) {
        clicked = this.state.tagEnd;
      }
      if (this.state.tagEnd === clicked) {
        this.displayRipple();
        if (clicked.prev === null) {
          this.state.taggingStarted = false;
          this.state.tagEnd = null;
          clicked.tagged = false;
          clicked.clearConnector();
        } else {
          this.state.tagEnd = clicked.prev;
          clicked.tagged = false;
          clicked.prev.displayConnectorEnd();
          clicked.prev = null;
          clicked.clearConnector();
        }
      } else if (this.tagged === true) {
        return;
      } else if (this.adjacentTo(this.state.tagEnd)) {
        this.displayRipple();
        this.prev = this.state.tagEnd;
        this.prev.displayConnectorMid(this);
        this.state.tagEnd = this;
        this.displayConnectorEnd();
        this.tagged = true;
      }
    } else {
      this.displayRipple();
      this.state.taggingStarted = true;
      this.state.tagEnd = this;
      this.tagged = true;
      this.displayConnectorEnd();
    }
    this.state.checkSum();
    //console.log(this.grid[this.x - 1][this.y - 1])
  },

  adjacentTo: function(endCell) {
    return ((Math.abs(this.x - endCell.x) < 2 && this.y === endCell.y) || 
            (Math.abs(this.y - endCell.y) < 2 && this.x === endCell.x));
  },

  clearConnector: function() {
    this.connector.play('none');
  },

  displayConnectorMid: function(next) {
    var direction = "";
    if (this.rightOf(next)) {
      direction = 'left';
    }
    if (this.leftOf(next)) {
      direction = 'right';
    }
    if (this.bottomOf(next)) {
      direction = 'up';
    }
    if (this.topOf(next)) {
      direction = 'down';
    }
    if (this.prev === null) {
      this.connector.play(direction);
    } else {
      if (this.rightOf(this.prev)) {
        this.connector.play(direction + '-left');
      } else if (this.leftOf(this.prev)) {
        this.connector.play(direction + '-right');
      } else if (this.bottomOf(this.prev)) {
        this.connector.play(direction + '-up');
      } else if (this.topOf(this.prev)) {
        this.connector.play(direction + '-down');
      }
    }
  },

  displayConnectorEnd: function() {
    if (this.prev === null) {
      this.connector.play('dot');
    } else if (this.rightOf(this.prev)) {
      this.connector.play('left');
    } else if (this.leftOf(this.prev)) {
      this.connector.play('right');
    } else if (this.bottomOf(this.prev)) {
      this.connector.play('up');
    } else if (this.topOf(this.prev)) {
      this.connector.play('down');
    }
  },

  rightOf: function(other) {
    return (this.x === other.x + 1 && this.y === other.y);
  },

  leftOf: function(other) {
    return (this.x === other.x - 1 && this.y === other.y);
  },

  bottomOf: function(other) {
    return (this.y === other.y + 1 && this.x === other.x);
  },

  topOf: function(other) {
    return (this.y === other.y - 1 && this.x === other.x);
  },

  displayRipple: function() {
    var ripple = this.state.ripples.getFirstExists(false);
    if (ripple !== null) {
      ripple.reset(this.x * 120 + 60, 380 + (this.y * 120));
      ripple.play('ripple', 10, false, true);
    }
  }

};


BasicGame.Game = function (game) {

};

BasicGame.Game.prototype = {

  create: function () {

    this.stage.backgroundColor = '#ddd';

    this.grid = [];
    for (var x = 0; x < 8; x++) {
      var column = [];
      for (var y = 0; y < 8; y++) {
        var cell = new Cell(this, this.game, x, y);
        column.push(cell);
      }
      this.grid.push(column);
    }

    this.ripples = this.add.group();
    this.ripples.createMultiple(10, 'ripple');
    this.ripples.setAll('anchor.x', 0.5);
    this.ripples.setAll('anchor.y', 0.5);
    this.ripples.forEach(function (ripple) {
      ripple.animations.add('ripple', [ 0, 1, 2, 3, 4, 5, 6, 7]);
    }, this);

    this.gameRunning = true;
    this.taggingStarted = false;
    this.tagEnd = null;

    this.score = 0;
    this.timeLimit = 90.0;

    this.prevHighScore = Store.get("highScore");
    if (this.prevHighScore === null) {
      this.prevHighScore = 0;
    } else {
      this.prevHighScore = parseInt(this.prevHighScore);
    }

    this.curHighScore = this.prevHighScore;

    this.prevBestTime = Store.get("bestTime");
    if (this.prevBestTime === null) {
      this.prevBestTime = 90.0;
    } else {
      this.prevBestTime = parseFloat(this.prevBestTime);
    }

    this.prevMillionTime = Store.get("bestMillionTime");
    this.millionTime = null;

    this.highScoreText = this.add.text(480, 55, "HIGH SCORE: " + this.prevHighScore, { font: "30px Roboto Mono", fill: "#222"});
    this.highScoreText.anchor.setTo(0.5, 0.5);

    this.scoreHeader = this.add.text(180, 110, "SCORE", { font: "30px Roboto Mono", fill: "#222"});
    this.scoreHeader.anchor.setTo(0.5, 0.5);
    this.add.text(780, 110, "TIME LEFT", { font: "30px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
    this.add.text(480, 110, "SUM", { font: "30px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);

    this.scoreText = this.add.text(180, 160, this.score, { font: "60px 'Roboto Mono'", fill: "#444"});
    this.scoreText.anchor.setTo(0.5, 0.5);


    this.timeText = this.add.text(780, 160, this.timeLimit, { font: "60px Roboto Mono", fill: "#444"});
    this.timeText.anchor.setTo(0.5, 0.5);

    this.addScoreGroup = this.add.group();
    this.highScoreGroup = this.add.group();
    this.addTimeGroup = this.add.group();
    this.resultGroup = this.add.group();
    this.result2Group = this.add.group();
    for (var i = 0; i < 5; i++) {
      var addScoreText = this.add.text(180, 160, "", { font: "50px 'Roboto Mono'", fill: "#080"});
      addScoreText.anchor.setTo(0.5, 0.5);
      addScoreText.kill();
      this.addScoreGroup.add(addScoreText);

      var highScoreText = this.add.text(180, 55, "", { font: "30px 'Roboto Mono'", fill: "#080"});
      highScoreText.anchor.setTo(0.5, 0.5);
      highScoreText.kill();
      this.highScoreGroup.add(highScoreText);

      var addTimeText = this.add.text(780, 160, "", { font: "50px 'Roboto Mono'", fill: "#080"});
      addTimeText.anchor.setTo(0.5, 0.5);
      addTimeText.kill();
      this.addTimeGroup.add(addTimeText);

      var resultText = this.add.text(480, 250, "", { font: "40px 'Roboto Mono'", fill: "#080"});
      resultText.anchor.setTo(0.5, 0.5);
      resultText.kill();
      this.resultGroup.add(resultText);

      var result2Text = this.add.text(480, 250, "", { font: "40px 'Roboto Mono'", fill: "#080"});
      result2Text.anchor.setTo(0.5, 0.5);
      result2Text.kill();
      this.result2Group.add(result2Text);
    }

    this.sumText = this.add.text(480, 190, '?', { font: "150px 'Roboto Mono'", fill: "#222"});
    this.sumText.anchor.setTo(0.5, 0.5);

    this.pointsText = this.add.text(480, 270, "0 digits, 0 points", { font: "30px Roboto Mono", fill: "#222"});
    this.pointsText.anchor.setTo(0.5, 0.5);

    this.time.reset();

    this.primeTable = [ false,
      false, true, true, false, true, false, true, false, false, false,
      true, false, true, false, false, false, true, false, true, false,
      false, false, true, false, false, false, false, false, true, false,
      true, false, false, false, false, false, true, false, false, false,
      true, false, true, false, false, false, true, false, false, false,
      false, false, true, false, false, false, false, false, true, false,
      true, false, false, false
    ];
    this.colorTable = [ "#444", "#41dbdb", "#b40561", "#9cff2e", "#710a92",
      "#f8ed2d", "#501095", "#febd2e", "#2b1e98", "#fe642c" ];
    this.blockers = [];
  },

  update: function () {
    var timeLeft = this.timeLimit - this.time.totalElapsedSeconds();
    if (timeLeft > 0 && this.blockers.length < 64) { 
      var text = Math.floor(timeLeft);
      if (text !== this.timeText.text) {
        this.timeText.text = text;
      }

      if (this.timeText.style.fill === '#444' && timeLeft < 16) {
        this.timeText.style.fill = '#d44';
        this.timeText.style.font = '700 65px Roboto Mono';
      } else if (this.timeText.style.fill === '#d44' && timeLeft > 16) {
        this.timeText.style.fill = '#444';
        this.timeText.style.font = '60px Roboto Mono';
      } 
    } else if (this.gameRunning) {
      this.endGame(timeLeft);
    }
    this.handleDragging();
  },

  handleDragging: function () {
    var pointer = this.input.activePointer;
    if (pointer.isDown) {
      //console.log(pointer.x + " " + pointer.y);
      //console.log(this.cellAt(pointer.x, pointer.y));
      if (this.dragging === undefined || !this.dragging) {
        this.dragging = true;
        this.lastClicked = this.cellAt(pointer.x, pointer.y);
      } else {
        var over = this.cellAt(pointer.x, pointer.y);
        if (this.lastClicked !== over) {
          if (over !== null && over !== undefined) {
            over.click();
          }
          this.lastClicked = over;
        }
      }
    } else if (pointer.isUp) {
      this.dragging = false;
    }
  },

  cellAt: function (x, y) {
    if (y < 320) {
      return null;
    }
    var newX = Math.floor(x/120);
    var newY = Math.floor((y-320)/120);
    if (newX >= 0 && newX < 8 && newY >= 0 && newX < 8) {
      return this.grid[newX][newY];
    } else {
      return null;
    }
  },

  checkSum: function () {
    var length = 0;
    var sum = 0;
    var cur = this.tagEnd;
    while (cur !== null) {
      sum += cur.value;
      length++;
      cur = cur.prev;
    }
    if (length > 1 && sum % 10 === 0) {

      this.score += this.calculatePoints(sum);
      
      if (this.score < 1000000) {
        this.scoreText.text = this.score;
      } else {
        if (this.millionTime === null) {
          this.millionTime = this.time.totalElapsedSeconds();
        }
        if (this.score <= 9999999999) {
          this.scoreHeader.text = "CONGRATULATIONS!";
        } else {
          this.scoreHeader.text = "PLEASE STOP";
        }
        this.displayColoredScore();
      }

      if (this.score > this.curHighScore) {
        Store.set("highScore", this.score);
        this.highScoreText.text = "HIGH SCORE: " + this.score;
        var highScoreText = this.highScoreGroup.getFirstExists(false);
        if (highScoreText !== null) {
          highScoreText.reset(480, 55);
          highScoreText.text = "            +" + (this.score - this.curHighScore);
          highScoreText.alpha = 1;
          var tween0 = this.add.tween(highScoreText).to( { alpha: 0, y: -25 }, 3000, Phaser.Easing.Linear.None, true);
          tween0.onComplete.add(function(text) {
            text.kill();
          }, this);
        }
        this.curHighScore = this.score;
      }

      var addScoreText = this.addScoreGroup.getFirstExists(false);
      if (addScoreText !== null) {
        addScoreText.reset(180, 100);
        addScoreText.text = "+" + this.calculatePoints(sum);
        addScoreText.alpha = 1;
        var tween = this.add.tween(addScoreText).to( { alpha: 0, y: 20 }, 3000, Phaser.Easing.Linear.None, true);
        tween.onComplete.add(function(text) {
          text.kill();
        }, this);
      }

      // clear all ripple animations and reroll cells
      this.ripples.forEachAlive(function(ripple) {
        ripple.kill();
      }, this);

      cur = this.tagEnd;
      var index = length;
      while (cur !== null) {
        var prev = cur.prev;
        cur.reroll(index--);
        cur = prev;
      }
      this.taggingStarted = false;
      this.tagEnd = null;

      this.sumText.text = "?";
      this.pointsText.text = "0 digits, 0 points";

      // TODO if prime, roll for removal of blocks but no bonus time
      // else, roll for creation of blocks

      var clearMessage = "";
      var blockerMessage = null;
      var clearFill = "#080";
      var addTime = "";
      if (this.primeTable[length]) {
        var removed = this.rollBlockRemoval(length);

        this.timeLimit += length * 1.0 / 2;
        addTime = "+" + Math.floor(length / 2);

        clearMessage = length + " - Prime";
        if (removed > 0) {
          blockerMessage = removed + " blocker" + (removed == 1 ? "" : "s") + " cleared";
          clearFill = "#a80";
        }
      } else {
        var added = this.rollBlockCreation(length);
        this.timeLimit += length * 2;

        addTime = "+" + length * 2;

        clearMessage = length + " - Composite";
        if (added > 0) {
          blockerMessage = added + " blocker" + (added === 1 ? "" : "s") + " added";
          clearFill = "#a01";
        }
      }
      
      var resultText = this.resultGroup.getFirstExists(false);
      var result2Text = this.result2Group.getFirstExists(false);

      if (resultText !== null && result2Text !== null) {
        resultText.reset(480, 250);
        resultText.alpha = 1;
        resultText.style.fill = clearFill;
        resultText.text = clearMessage;
        if (blockerMessage !== null) {
          resultText.y = 185;
          result2Text.reset(480, 230);
          result2Text.alpha = 1;
          result2Text.style.fill = clearFill;
          result2Text.text = blockerMessage;

          var rTween = this.add.tween(resultText).to( { alpha: 0, y: -25 }, 3000, Phaser.Easing.Linear.None, true);
          rTween.onComplete.add(function (text) { text.kill(); }, this);

          var rTween2 = this.add.tween(result2Text).to( { alpha: 0, y: 20 }, 3000, Phaser.Easing.Linear.None, true);
          rTween2.onComplete.add(function (text) { text.kill(); }, this);
        } else {
          resultText.y = 230;
          var rTween3 = this.add.tween(resultText).to( { alpha: 0, y: 20 }, 3000, Phaser.Easing.Linear.None, true);
          rTween3.onComplete.add(function (text) { text.kill(); }, this);
        }
      }

      if (this.timeLimit > this.prevBestTime) {
        Store.set("bestTime", this.timeLimit);
      }

      var addTimeText = this.addTimeGroup.getFirstExists(false);
      if (addTimeText !== null) {
        addTimeText.reset(780, 100);
        addTimeText.text = addTime;
        addTimeText.alpha = 1;
        var tween2 = this.add.tween(addTimeText).to( { alpha: 0, y: 20 }, 3000, Phaser.Easing.Linear.None, true);
        tween2.onComplete.add(function(text) {
          text.kill();
        }, this);
      }
    } else {
      if (sum === 0) {
        this.sumText.text = "?";
        this.pointsText.text = "0 digits, 0 points";
      } else {
        this.sumText.text = sum % 10;
        this.pointsText.text = length + " digit" + (length == 1 ? "" : "s") + 
          (this.primeTable[length + 1] ? " (prime next)" : "") + ", " + 
          this.calculatePoints(sum) + " point" + (this.calculatePoints(sum) == 1 ? "" : "s");
      }
    }
  },

  calculatePoints: function (sum) {
    return Math.pow(Math.floor(sum / 10), 3) * 5;
  },

  rollBlockRemoval: function (length) {
    //console.log(this.blockers);
    if (this.blockers.length === 0) {
      return 0;
    }
    var removed = 0;
    for (var i = 0; i < length; i++) {
      // per digit, there's a 1 in 5 chance of removing a block
      if (Math.random() * 5 < 1) {
        var delIdx = Math.floor(Math.random() * this.blockers.length);
        // reroll selected
        this.blockers[delIdx].removeBlocker();
        // remove from list
        this.blockers.splice(delIdx, 1);

        removed++;
         
        if (this.blockers.length === 0) {
          break;
        }
      }
    }
    return removed;
  },

  rollBlockCreation: function (length) {
    //console.log(this.blockers);
    var added = 0;
    for (var i = 0; i < length; i++) {
      // per digit, there's a 1 in 5 chance of removing a block
      if (Math.random() * 4 < 1) {
        var cell = null;
        while (cell === null) {
          var x = Math.floor(Math.random() * 8);
          var y = Math.floor(Math.random() * 8);
          if (this.grid[x][y].value !== 0) {
            cell = this.grid[x][y];
          }
        }

        cell.changeToBlocker();

        this.blockers.push(cell);
        added++;

        if (this.blockers.length === 64) {
          break;
        }
      }
    }
    return added;
  },

  timeToText: function (seconds) {
    var hours = Math.floor(seconds / 3600);
    var remainingSecs = seconds - hours * 3600;
    var minutes = Math.floor(remainingSecs / 60);
    remainingSecs = remainingSecs - minutes * 60;
    var ms = remainingSecs % 1;
    remainingSecs = Math.floor(remainingSecs);

    var text = "";
    if (hours > 0) {
      text += hours + ":";
    }
    text += ("0" + minutes).slice(-2)  + ":";
    text += ("0" + Math.floor(remainingSecs)).slice(-2)  + "." + ("0" + Math.floor(ms * 10)).slice(-1);
    return text;
  },

  displayColoredScore: function () {
    if (this.scoreText.text !== "") {
      this.scoreText.text = "";
    }
    if (this.milText === undefined || this.milText === null || !this.milText[0].alive) {
      this.milText = [];
      for (var i = 0; i < 10; i++) {
        var text = this.add.text(180, 160, "", { font: "700 64px 'Roboto Mono'", fill: "#444"});
        text.anchor.setTo(0.5, 0.5);
        this.milText.push(text);
      }
    }
    var scoreStr = "" + this.score;
    for (var j = 0; j < 10 && j < scoreStr.length; j++) {
      this.milText[j].x = 160 + (scoreStr.length / 2 * 38) - (j * 38);
      this.milText[j].style.fill = this.colorTable[Math.floor(Math.random() * 10)];
      this.milText[j].text = scoreStr.substr(scoreStr.length - 1 - j, 1);
    }
  },

  endGame: function (timeLeft) {
    this.gameRunning = false;

    if (timeLeft <= 0) {
      this.timeText.text = "0";
    }

    this.overlay = this.add.sprite(100, 300, "overlay");

    this.add.text(480, 400, "Game Over", { font: "64px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
    
    var runText = null;
    var milText = null;
    if (this.millionTime !== null) { 
      runText = this.add.text(480, 463, "Run Time - " + this.timeToText(this.timeLimit), { font: "30px Roboto Mono", fill: "#222"});
      runText.anchor.setTo(0.5, 0.5);
      milText = this.add.text(480, 497, "Million reached at " + this.timeToText(this.millionTime), { font: "30px Roboto Mono", fill: "#222"});
      milText.anchor.setTo(0.5, 0.5);
    } else {
      runText = this.add.text(480, 480, "Run Time: " + this.timeToText(this.timeLimit), { font: "36px Roboto Mono", fill: "#222"});
      runText.anchor.setTo(0.5, 0.5);
    }

    var newHighScore = false;
    if (this.score > this.prevHighScore) {
      newHighScore = true;
    }
    var newBestTime = false;
    if (this.timeLimit > this.prevBestTime) {
      newBestTime = true;
    }
    var newMillionTime = false;
    if (this.millionTime !== null && 
        ( (this.prevMillionTime !== null && parseFloat(this.prevMillionTime) > this.millionTime) ||
          (this.prevMillionTime === null) ) ) {
      Store.set("bestMillionTime", this.millionTime);
      newMillionTime = true;
    }
    
    if (newHighScore) {
      if (newBestTime) {
        if (newMillionTime) {
          this.add.text(480, 570, "New High Score!", { font: "44px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
          this.add.text(480, 620, "New Longest Run!", { font: "44px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
          this.add.text(480, 670, "New Fastest Million!", { font: "44px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
        } else {
          this.add.text(480, 595, "New High Score!", { font: "48px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
          this.add.text(480, 645, "New Longest Run!", { font: "48px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
        }
      } else {
        if (newMillionTime) {
          this.add.text(480, 595, "New High Score!", { font: "48px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
          this.add.text(480, 645, "New Fastest Million!", { font: "48px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
        } else {
          this.add.text(480, 620, "New High Score!", { font: "56px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
        }
      }
    } else if (newBestTime) {
      if (newMillionTime) {
        this.add.text(480, 595, "New Longest Run!", { font: "48px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
        this.add.text(480, 645, "New Fastest Million!", { font: "48px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
      } else {
        this.add.text(480, 620, "New Longest Run!", { font: "56px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
      }
    } else if (newMillionTime) {
      this.add.text(480, 620, "New Fastest Million!", { font: "56px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
    } else {
      runText.y += 100;
      if (milText !== null) {
        milText.y += 100;
      }
    }

    this.add.text(480, 770, "Previous Bests", { font: "40px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
    this.add.text(480, 820, "High Score - " + this.prevHighScore, { font: "28px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
    this.add.text(480, 850, "Longest Run - " + this.timeToText(this.prevBestTime), { font: "28px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);

    if (this.prevMillionTime !== null) {
      this.add.text(480, 880, "Fastest Million - " + this.timeToText(this.prevMillionTime, true), { font: "28px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
    }

    this.time.events.add(1000, function () {
      this.add.text(480, 960, "Tap/click to return to main menu", { font: "32px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);
      this.overlay.inputEnabled = true;
      this.overlay.events.onInputDown.add(this.quitGame, this);
    }, this);

    this.addSocialBar();
  },

  addSocialBar: function() {
    this.overlay = this.add.sprite(100, 1080, "social");
    this.add.text(480, 1100, "share this on", { font: "28px Roboto Mono", fill: "#222"}).anchor.setTo(0.5, 0.5);

    var fullUrl, ogUrl, text, url, icon;

    url = encodeURIComponent("http://zero.karaniwan.org/");
    ogUrl = encodeURIComponent("http://zero.karaniwan.org<%= image_path "screenshot.png" %>");

    text = encodeURIComponent("I got " + this.score + " points in \"zero\", a mathematical puzzle game. Try beating my score!");

    fullUrl = "https://www.facebook.com/dialog/share?app_id=944062788970440&href=" + url + "&display=page&redirect_uri=https://facebook.com";
    icon = this.add.sprite(200, 1170, "social-buttons");
    icon.anchor.setTo(0.5, 0.5);
    icon.animations.add('s', [ 0 ]);
    icon.play('s');
    icon.inputEnabled = true;
    icon.events.onInputDown.add(function() {
      var win = window.open(this, '_blank');
      win.focus();  
    }, fullUrl);


    fullUrl = "https://twitter.com/intent/tweet?url=" + url + "&text=" + text;
    icon = this.add.sprite(340, 1170, "social-buttons");
    icon.anchor.setTo(0.5, 0.5);
    icon.animations.add('s', [ 1 ]);
    icon.play('s');
    icon.inputEnabled = true;
    icon.events.onInputDown.add(function() {
      var win = window.open(this, '_blank');
{'fraction_non_alphanumeric': 0.17716657016020074, 'fraction_numerical': 0.039837869137232196, 'mean_word_length': 2.425520661157025, 'pattern_counts': {'":': 4, '<': 47, '<?xml version=': 0, '>': 31, 'https://': 6, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1187145', 'n_tokens_mistral': 19630, 'n_tokens_neox': 17902, 'n_words': 3742}