<commit_before>var _ = require('underscore'),
  http = require('http'),
  url = require('url'),
  path = require('path'),
  fs = require('fs'),
  WebSocketServer = require('ws').Server;

function Game() {

  _.extend(this, {

    board: [
      {
        type: 'end',
        tries: 0,
        position: {
          x: 0,
          y: 0
        },
      }
    ],

    players: [],
    nextPlayerId: 0,

    sendRPC: function(player, procedure, data) {
      var rpc = {
        procedure: procedure,
        data: data
      };
      player.ws.send(JSON.stringify(rpc));
    },

    broadcastRPC: function(procedure, data) {
      _.each(this.players, _.bind(function(player) {
        this.sendRPC(player, procedure, data);
      }, this));
    },

    onConnection: function(ws) {

      var player = {
        id: this.nextPlayerId++,
        ws: ws,
        moveId: 0,
      };
      this.players.push(player);
      this.sendRPC(player, 'id', player.id);

      while (_.size(this.board) < 10 * _.size(this.players)) {
        this.growBoard();
      }

      _.extend(player, {
        position: { // TODO random spawn position
          x: 0,
          y: 0,
        }
      });
      this.sendRPC(player, 'move', player.position);

      var spawn = this.findBlock(player.position);
      if (spawn !== undefined) {
        spawn.type = 'secured';
        spawn.team = player.id;
      }

      _.each(this.board, _.bind(function(block) {
        this.broadcastRPC('block', block);
      }, this));

      ws.on('message', _.bind(this.onMessage, this, player));
      ws.on('close', _.bind(this.onDisconnection, this, player));

    },

    onDisconnection: function(player) {

      this.players = _.without(this.players, player);

      if (_.size(this.players) === 0) {
        _.extend(this, new Game());
      }

    },

    onMessage: function(player, rpc) {

      var rpc = JSON.parse(rpc);
      var call = rpc.procedure;
      var data = rpc.data;

      if (call === 'move') {
        this.onMoveMessage(player, data);
      } else {
        console.error('unknown RPC', rpc);
      }

    },

    onMoveMessage: function(player, move) {

      if (
        _.indexOf([-1, 0, 1], move.x) === -1
        || _.indexOf([-1, 0, 1], move.y) === -1
      ) {

        console.error('Cheater detected:', player.ws.upgradeReq.connection.remoteAddress);

      } else {

        if (this.findBlock({
          x: player.position.x + move.x,
          y: player.position.y + move.y,
        }) !== undefined) {

          player.position.x += move.x;
          player.position.y += move.y;

          this.sendRPC(player, 'move', move);
          this.onPlayerMove(player);

        }

      }

    },

    onPlayerMove: function(player) {

      ++player.moveId;
      this.startCapture(player);

    },

    findBlock: function(position) {

      return _.find(
        this.board,
        function(block) {
          return _.isEqual(block.position, position);
        }
      );

    },

    startCapture: function(player) {

      var block = this.findBlock(player.position);

      var moveId = player.moveId;

      function register(self, type, delay, callback) {
        if (block.type === type) {
          _.delay(
            _.bind(
              function() {
                if (block.type === type && player.moveId === moveId) {
                  callback();
                  this.broadcastRPC('block', block);
                  this.startCapture(player);
                }
              },
              self
            ),
            delay<commit_msg>Fixed a bug causing captures after disconnection<commit_after>var _ = require('underscore'),
  http = require('http'),
  url = require('url'),
  path = require('path'),
  fs = require('fs'),
  WebSocketServer = require('ws').Server;

function Game() {

  _.extend(this, {

    board: [
      {
        type: 'end',
        tries: 0,
        position: {
          x: 0,
          y: 0
        },
      }
    ],

    players: [],
    nextPlayerId: 0,

    sendRPC: function(player, procedure, data) {
      var rpc = {
        procedure: procedure,
        data: data
      };
      player.ws.send(JSON.stringify(rpc));
    },

    broadcastRPC: function(procedure, data) {
      _.each(this.players, _.bind(function(player) {
        this.sendRPC(player, procedure, data);
      }, this));
    },

    onConnection: function(ws) {

      var player = {
        id: this.nextPlayerId++,
        ws: ws,
        moveId: 0,
      };
      this.players.push(player);
      this.sendRPC(player, 'id', player.id);

      while (_.size(this.board) < 10 * _.size(this.players)) {
        this.growBoard();
      }

      _.extend(player, {
        position: { // TODO random spawn position
          x: 0,
          y: 0,
        }
      });
      this.sendRPC(player, 'move', player.position);

      var spawn = this.findBlock(player.position);
      if (spawn !== undefined) {
        spawn.type = 'secured';
        spawn.team = player.id;
      }

      _.each(this.board, _.bind(function(block) {
        this.broadcastRPC('block', block);
      }, this));

      ws.on('message', _.bind(this.onMessage, this, player));
      ws.on('close', _.bind(this.onDisconnection, this, player));

    },

    onDisconnection: function(player) {

      ++player.moveId;

      this.players = _.without(this.players, player);

      if (_.size(this.players) === 0) {
        _.extend(this, new Game());
      }

    },

    onMessage: function(player, rpc) {

      var rpc = JSON.parse(rpc);
      var call = rpc.procedure;
      var data = rpc.data;

      if (call === 'move') {
        this.onMoveMessage(player, data);
      } else {
        console.error('unknown RPC', rpc);
      }

    },

    onMoveMessage: function(player, move) {

      if (
        _.indexOf([-1, 0, 1], move.x) === -1
        || _.indexOf([-1, 0, 1], move.y) === -1
      ) {

        console.error('Cheater detected:', player.ws.upgradeReq.connection.remoteAddress);

      } else {

        if (this.findBlock({
          x: player.position.x + move.x,
          y: player.position.y + move.y,
        }) !== undefined) {

          player.position.x += move.x;
          player.position.y += move.y;

          this.sendRPC(player, 'move', move);
          this.onPlayerMove(player);

        }

      }

    },

    onPlayerMove: function(player) {

      ++player.moveId;
      this.startCapture(player);

    },

    findBlock: function(position) {

      return _.find(
        this.board,
        function(block) {
          return _.isEqual(block.position, position);
        }
      );

    },

    startCapture: function(player) {

      var block = this.findBlock(player.position);

      if (block === undefined) {
        return;
      }

      var moveId = player.moveId;

      function register(self, type, delay, callback) {
        if (block.type === type) {
          _.delay(
            _.bind(
              function() {
                if (block.type === type && player.moveId === moveId) {
                  callback();
                  this.broadcastRPC('block', block);
                  this.startCapture(player);
                }
              },
              self
            ),
            delay
{'fraction_non_alphanumeric': 0.15120274914089346, 'fraction_numerical': 0.004948453608247422, 'mean_word_length': 1.7088607594936709, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, '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': '6146191', 'n_tokens_mistral': 2315, 'n_tokens_neox': 2181, 'n_words': 436}