<commit_before>"use strict";
var Board = (function() {

  /* Copy an array. */
  function arrayCopy(source) {
    var i, len = source.length, target = new Array(len);
    for (i = 0; i < len; ++i) {
      target[i] = source[i];
    }
    return target;
  }

  /* Return the last element of an array. */
  function last(arr) {
    return arr[arr.length - 1];
  }

  /* Parse a move in one of the following formats:
   * Quantum:   '6-3'
   * Collapse:  '->3'
   * Classical: '8'
   */
  function parseMove(s) {
    var a, b;
    if (s.match(/\d-\d/)) {
      a = +s.charAt(0);
      b = +s.charAt(2);
      if (a && b) {
        return { type: Board.QUANTUM, cells: [a, b] };
      }      
    } else if (s.match(/->\d/)) {
      a = +s.charAt(2);
      if (a) {
        return { type: Board.COLLAPSE, cells: a };
      }
    } else if (s.match(/\d/)) {
      a = +s;
      if (a) {
        return { type: Board.CLASSICAL, cells: a };
      }
    }
    return null;
  }

  /* Render a move as a string, */
  function stringifyMove(move) {
    if (!move) {
      return '';
    }
    if (move.type === Board.QUANTUM) {
      return move.cells[0] + '-' + move.cells[1];
    }
    if (move.type === Board.COLLAPSE) {
      return '->' + move.cells;
    }
    if (move.type === Board.CLASSICAL) {
      return move.cells.toString();
    }
    return '';
  }

  /* Take either a string or a move object, and return a move object. */
  function convertMove(move) {
    if (typeof move === 'string') {
      return parseMove(move);
    }
    if (typeof move === 'object') {
      return move;
    }
    return null;
  }

  /* Score a list of tic-tac-toes by giving them a score property. */
  function scoreTicTacToes(tictactoes) {
    var i, minPiece = 9, rowMaxPiece;

    function maxPiece(tictactoe) {
      return Math.max.apply(this, tictactoe.pieces);
    }

    for (i = 0; i < tictactoes.length; ++i) {
      rowMaxPiece = maxPiece(tictactoes[i]);
      if (minPiece > rowMaxPiece) {
        minPiece = rowMaxPiece;
      }
    }
    for (i = 0; i < tictactoes.length; ++i) {
      tictactoes[i].score = minPiece === maxPiece(tictactoes[i]) ? 2 : 1;
    }
  }

  var Board = function() {
    this.clear();
  };

  // Public class constants
  Board.QUANTUM = 'quantum';
  Board.COLLAPSE = 'collapse';
  Board.CLASSICAL = 'classical';

  Board.PLAYERX = 'X';
  Board.PLAYERO = 'O';

  Board.WIN_POSITIONS = [
    // Rows
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
    // Columns
    [1, 4, 7],
    [2, 5, 8],
    [3, 6, 9],
    // Diagonals
    [1, 5, 9],
    [3, 5, 7]
  ];

  // Prototype methods
  Board.prototype = {
    clear: function() {
      var i;
      this._board = [];
      this._edges = [];
      for (i = 0; i < 9; ++i) {
        this._board[i] = [];
        this._edges[i] = [];
      }

      this._placed = 0;
      this._nextType = Board.QUANTUM;
      this._tictactoes = [];

      this._history = [];
      this._collapseStates = [];
    },

    get: function(i) {
      var cell = this._board[i - 1];
      return cell ?
        { type: Array.isArray(cell) ? Board.QUANTUM : Board.CLASSICAL,
          pieces: cell
        } : null;
    },

    turn: function() {
      return this._placed % 2 ? Board.PLAYERO : Board.PLAYERX;
    },

    gameOver: function() {
      return !this._nextType;
    },

    tictactoes: function() {
      return this._tictactoes;
    },

    scores: function () {
      var scores = {}, tictactoes = this._tictactoes, i, tictactoe;
      if (!this.gameOver()) {
        return null;
      }
      scores[Board.PLAYERX] = scores[Board.PLAYERO] = 0;
      for (i = 0; i < tictactoes.length; ++i) {
        tictactoe = tictactoes[i];
        scores[tictactoe.player] += tictactoe.score;
      }
      return scores;
    },

    canMove: function(move) {
      return this._canMove(convertMove(move));
    },

    move: function(move) {
      var moveObj = convertMove(move);

      if (!this._canMove(moveObj)) {
        return null;
      }

      this._history.push(moveObj);
      this._applyMove(moveObj);
      return moveObj;
    },

    history: function(verbose) {
      var history = this._history, terseHistory = [], i;
      if (verbose) {
        return history;
      }
      for (i = 0; i < history.length; ++i) {
        terseHistory[i] = stringifyMove(history[i]);
      }
      return terseHistory;
    },

    undo: function() {
      var moveObj = this._history.pop();
      if (moveObj) {
        this._unapplyMove(moveObj);
      }
      return moveObj;
    },

    _isQuantum: function(i) {
      return Array.isArray(this._board[i - 1]);
    },

    _countClassicalPieces: function() {
      var i, classical = 0;
      for (i = 1; i <= 9; ++i) {
        if (!this._isQuantum(i)) {
          ++classical;
        }
      }
      return classical;
    },

    _canMove: function (move) {
      if (!move || move.type !== this._nextType) {
        return false;
      }

      var a, b;
      if (move.type === Board.QUANTUM) {
        a = move.cells[0];
        b = move.cells[1];
        return a && b && this._isQuantum(a) && this._isQuantum(b) && a !== b;
      }
      if (move.type === Board.COLLAPSE) {
        a = move.cells;
        return a && this._isQuantum(a) &&
               last(this._board[a - 1]) === this._placed;
      }
      if (move.type === Board.CLASSICAL) {
        a = move.cells;
        return a && this._isQuantum(a);
      }
      return false;
    },

    _applyMove: function(move) {
      var a, b;
      if (move.type === Board.QUANTUM) {
        a = move.cells[0];
        b = move.cells[1];
        this._placed++;
        if (this._reachable(a, b)) {
            this._nextType = Board.COLLAPSE;
        }
        this._board[a - 1].push(this._placed);
        this._board[b - 1].push(this._placed);
        this._edges[a - 1].push(b);
        this._edges[b - 1].push(a);
      } else if (move.type === Board.COLLAPSE) {
        a = move.cells;
        this._collapseStates.push(arrayCopy(this._board));
        this._collapseCell(this._placed, a);
        this._nextType = this._countClassicalPieces() === 8 ? Board.CLASSICAL
                                                            : Board.QUANTUM;
        this._updateGameStatus();
      } else if (move.type === Board.CLASSICAL) {
        a = move.cells;
        this._placed++;
        this._board[a - 1] = this._placed;
        this._updateGameStatus();
      }
    },

    _unapplyMove: function(move) {
      var a, b, collapseState;
      this._nextType = move.type;
      this._tictactoes = [];
      if (move.type === Board.QUANTUM) {
        a = move.cells[0];
        b = move.cells[1];
        this._placed--;
        this._board[a - 1].pop();
        this._board[b - 1].pop();
        this._edges[a - 1].pop();
        this._edges[b - 1].pop();
      } else if (move.type === Board.COLLAPSE) {
        this._board = this._collapseStates.pop();
      } else if (move.type === Board.CLASSICAL) {
        a = move.cells;
        this._placed--;
        this._board[a - 1] = [];
      }
    },

    _reachable: function(src, dest) {
      var visited = [], edges = this._edges;
      function visit(i) {
        var j, neighbors;
        if (visited.indexOf(i) !== -1) {
          return;
        }
        visited.push(i);
        neighbors = edges[i - 1];
        for (j = 0; j < neighbors.length; ++j) {
          visit(neighbors[j]);
        }
      }

      visit(src);
      return visited.indexOf(dest) !== -1;
    },

    _collapseCell: function(piece, i) {
      /* It seems like the last move will be collapsed into two cells here, but
       * since the moves are ordered, some other move will be collapsed into the
       * other cell before the last move is processed.
       */
      var neighbors = this._edges[i - 1], cells = this._board[i - 1], j;
      if (!this._isQuantum(i)) {
        return;
      }
      this._board[i - 1] = piece;
      for (j = 0; j < neighbors.length; ++j) {
        this._collapseCell(cells[j], neighbors[j]);
      }
    },

    _updateGameStatus: function() {
      var i, j, cells, pieces, player, tictactoes = [];

      function isX(c) {
        return typeof c === 'number' && c % 2 === 1;
      }

      function isO(c) {
        return typeof c === 'number' && c % 2 === 0;
      }

      for (i = 0; i < Board.WIN_POSITIONS.length; ++i) {
        cells = Board.WIN_POSITIONS[i];
        pieces = [];
        player = null;
        for (j = 0; j < cells.length; ++j) {
          pieces[j] = this._board[cells[j] - 1];
        }
        if (pieces.every(isX)) {
          player = Board.PLAYERX;
        } else if (pieces.every(isO)) {
          player = Board.PLAYERO;
        }
        if (player) {
          tictactoes.push({
            player: player,
            cells: cells,
            pieces: pieces});
        }
      }

      scoreTicTacToes(tictactoes);<commit_msg>Inline scoreTictactoes<commit_after>"use strict";
var Board = (function() {

  /* Copy an array. */
  function arrayCopy(source) {
    var i, len = source.length, target = new Array(len);
    for (i = 0; i < len; ++i) {
      target[i] = source[i];
    }
    return target;
  }

  /* Return the last element of an array. */
  function last(arr) {
    return arr[arr.length - 1];
  }

  /* Parse a move in one of the following formats:
   * Quantum:   '6-3'
   * Collapse:  '->3'
   * Classical: '8'
   */
  function parseMove(s) {
    var a, b;
    if (s.match(/\d-\d/)) {
      a = +s.charAt(0);
      b = +s.charAt(2);
      if (a && b) {
        return { type: Board.QUANTUM, cells: [a, b] };
      }      
    } else if (s.match(/->\d/)) {
      a = +s.charAt(2);
      if (a) {
        return { type: Board.COLLAPSE, cells: a };
      }
    } else if (s.match(/\d/)) {
      a = +s;
      if (a) {
        return { type: Board.CLASSICAL, cells: a };
      }
    }
    return null;
  }

  /* Render a move as a string. The inverse of parseMove(s). */
  function stringifyMove(move) {
    if (!move) {
      return '';
    }
    if (move.type === Board.QUANTUM) {
      return move.cells[0] + '-' + move.cells[1];
    }
    if (move.type === Board.COLLAPSE) {
      return '->' + move.cells;
    }
    if (move.type === Board.CLASSICAL) {
      return move.cells.toString();
    }
    return '';
  }

  /* Take either a string or a move object, and return a move object. */
  function convertMove(move) {
    if (typeof move === 'string') {
      return parseMove(move);
    }
    if (typeof move === 'object') {
      return move;
    }
    return null;
  }

  var Board = function() {
    this.clear();
  };

  // Public class constants
  Board.QUANTUM = 'quantum';
  Board.COLLAPSE = 'collapse';
  Board.CLASSICAL = 'classical';

  Board.PLAYERX = 'X';
  Board.PLAYERO = 'O';

  Board.WIN_POSITIONS = [
    // Rows
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
    // Columns
    [1, 4, 7],
    [2, 5, 8],
    [3, 6, 9],
    // Diagonals
    [1, 5, 9],
    [3, 5, 7]
  ];

  // Prototype methods
  Board.prototype = {
    clear: function() {
      var i;
      this._board = [];
      this._edges = [];
      for (i = 0; i < 9; ++i) {
        this._board[i] = [];
        this._edges[i] = [];
      }

      this._placed = 0;
      this._nextType = Board.QUANTUM;
      this._tictactoes = [];

      this._history = [];
      this._collapseStates = [];
    },

    get: function(i) {
      var cell = this._board[i - 1];
      return cell ?
        { type: Array.isArray(cell) ? Board.QUANTUM : Board.CLASSICAL,
          pieces: cell
        } : null;
    },

    turn: function() {
      return this._placed % 2 ? Board.PLAYERO : Board.PLAYERX;
    },

    gameOver: function() {
      return !this._nextType;
    },

    tictactoes: function() {
      return this._tictactoes;
    },

    scores: function () {
      var scores = {}, tictactoes = this._tictactoes, i, tictactoe;
      if (!this.gameOver()) {
        return null;
      }
      scores[Board.PLAYERX] = scores[Board.PLAYERO] = 0;
      for (i = 0; i < tictactoes.length; ++i) {
        tictactoe = tictactoes[i];
        scores[tictactoe.player] += tictactoe.score;
      }
      return scores;
    },

    canMove: function(move) {
      return this._canMove(convertMove(move));
    },

    move: function(move) {
      var moveObj = convertMove(move);

      if (!this._canMove(moveObj)) {
        return null;
      }

      this._history.push(moveObj);
      this._applyMove(moveObj);
      return moveObj;
    },

    history: function(verbose) {
      var history = this._history, terseHistory = [], i;
      if (verbose) {
        return history;
      }
      for (i = 0; i < history.length; ++i) {
        terseHistory[i] = stringifyMove(history[i]);
      }
      return terseHistory;
    },

    undo: function() {
      var moveObj = this._history.pop();
      if (moveObj) {
        this._unapplyMove(moveObj);
      }
      return moveObj;
    },

    _isQuantum: function(i) {
      return Array.isArray(this._board[i - 1]);
    },

    _countClassicalPieces: function() {
      var i, classical = 0;
      for (i = 1; i <= 9; ++i) {
        if (!this._isQuantum(i)) {
          ++classical;
        }
      }
      return classical;
    },

    _canMove: function (move) {
      if (!move || move.type !== this._nextType) {
        return false;
      }

      var a, b;
      if (move.type === Board.QUANTUM) {
        a = move.cells[0];
        b = move.cells[1];
        return a && b && this._isQuantum(a) && this._isQuantum(b) && a !== b;
      }
      if (move.type === Board.COLLAPSE) {
        a = move.cells;
        return a && this._isQuantum(a) &&
               last(this._board[a - 1]) === this._placed;
      }
      if (move.type === Board.CLASSICAL) {
        a = move.cells;
        return a && this._isQuantum(a);
      }
      return false;
    },

    _applyMove: function(move) {
      var a, b;
      if (move.type === Board.QUANTUM) {
        a = move.cells[0];
        b = move.cells[1];
        this._placed++;
        if (this._reachable(a, b)) {
            this._nextType = Board.COLLAPSE;
        }
        this._board[a - 1].push(this._placed);
        this._board[b - 1].push(this._placed);
        this._edges[a - 1].push(b);
        this._edges[b - 1].push(a);
      } else if (move.type === Board.COLLAPSE) {
        a = move.cells;
        this._collapseStates.push(arrayCopy(this._board));
        this._collapseCell(this._placed, a);
        this._nextType = this._countClassicalPieces() === 8 ? Board.CLASSICAL
                                                            : Board.QUANTUM;
        this._updateGameStatus();
      } else if (move.type === Board.CLASSICAL) {
        a = move.cells;
        this._placed++;
        this._board[a - 1] = this._placed;
        this._updateGameStatus();
      }
    },

    _unapplyMove: function(move) {
      var a, b, collapseState;
      this._nextType = move.type;
      this._tictactoes = [];
      if (move.type === Board.QUANTUM) {
        a = move.cells[0];
        b = move.cells[1];
        this._placed--;
        this._board[a - 1].pop();
        this._board[b - 1].pop();
        this._edges[a - 1].pop();
        this._edges[b - 1].pop();
      } else if (move.type === Board.COLLAPSE) {
        this._board = this._collapseStates.pop();
      } else if (move.type === Board.CLASSICAL) {
        a = move.cells;
        this._placed--;
        this._board[a - 1] = [];
      }
    },

    _reachable: function(src, dest) {
      var visited = [], edges = this._edges;
      function visit(i) {
        var j, neighbors;
        if (visited.indexOf(i) !== -1) {
          return;
        }
        visited.push(i);
        neighbors = edges[i - 1];
        for (j = 0; j < neighbors.length; ++j) {
          visit(neighbors[j]);
        }
      }

      visit(src);
      return visited.indexOf(dest) !== -1;
    },

    _collapseCell: function(piece, i) {
      /* It seems like the last move will be collapsed into two cells here, but
       * since the moves are ordered, some other move will be collapsed into the
       * other cell before the last move is processed.
       */
      var neighbors = this._edges[i - 1], cells = this._board[i - 1], j;
      if (!this._isQuantum(i)) {
        return;
      }
      this._board[i - 1] = piece;
      for (j = 0; j < neighbors.length; ++j) {
        this._collapseCell(cells[j], neighbors[j]);
      }
    },

    _updateGameStatus: function() {
      var i, j, cells, pieces, player, tictactoes = [],
          minPiece = 9, rowMaxPiece;

      function isX(c) {
        return typeof c === 'number' && c % 2 === 1;
      }

      function isO(c) {
        return typeof c === 'number' && c % 2 === 0;
      }

      function maxPiece(tictactoe) {
        return Math.max.apply(this, tictactoe.pieces);
      }

      // Find tic-tac-toes
      for (i = 0; i < Board.WIN_POSITIONS.length; ++i) {
        cells = Board.WIN_POSITIONS[i];
        pieces = [];
        player = null;
        for (j = 0; j < cells.length; ++j) {
          pieces[j] = this._board[cells[j] - 1];
        }
        if (pieces.every(isX)) {
          player = Board.PLAYERX;
        } else if (pieces.every(isO)) {
          player = Board.PLAYERO;
        }
        if (player) {
          tictactoes.push({
            player: player,
            cells: cells,
            pieces: pieces});
        }
      }

      // Score tic-tac-toes
      for (i = 0; i < tictactoes.length; ++i) {
        rowMaxPiece = maxPiece(tictactoes[i]);
        if (minPiece > rowMaxPiece) {
          minPiece = rowMaxPiece;
        }
      }
      for (i = 0; i < tictactoes.length; ++i) {
        tictactoes[i].score = minPiece === maxPiece(tictactoes[i]) ? 2 : 1;
      }
{'fraction_non_alphanumeric': 0.15717821782178218, 'fraction_numerical': 0.009563456345634564, 'mean_word_length': 1.7471797249265957, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4392987', 'n_tokens_mistral': 6285, 'n_tokens_neox': 6009, 'n_words': 1384}