LimaxMinion

Limax Bot Minion

// ==UserScript==
// @name         LimaxMinion
// @namespace    LimaxMinion
// @version      0.1
// @description  Limax Bot Minion
// @author       Flammrock
// @match        *://*.limax.io/*
// @run-at       document-end
// @grant        none
// ==/UserScript==

(function() {
  'use strict';

  function inject(src, callback) {
      if (typeof callback != 'function') callback = function() { };

      var el;

      if (typeof src != 'function' && /\.css[^\.]*$/.test(src)) {
          el      = document.createElement('link');
          el.type = 'text/css';
          el.rel  = 'stylesheet';
          el.href = src;
      } else {
          el      = document.createElement('script');
          el.type = 'text/javascript';
      }

      el.class = 'injected';

      if (typeof src == 'function') {
          el.appendChild(document.createTextNode('(' + src + ')();'));
          callback();
      } else {
          el.src   = src;
          el.async = false;
          el.onreadystatechange = el.onload = function() {
              var state = el.readyState;
              if (!callback.done && (!state || /loaded|complete/.test(state))) {
                  callback.done = true;
                  callback();
              }
          };
      }

      var head = document.head || document.getElementsByTagName('head')[0];
      head.insertBefore(el, head.lastChild);
  }

  function dist(a,b) {
    var dx = a.x-b.x;
    var dy = a.y-b.y;
    return Math.sqrt(dx*dx+dy*dy);
  }

  function angle(a,b) {
    return Math.atan2(a.y-b.y,a.x-b.x);
  }

  inject('https://cdnjs.cloudflare.com/ajax/libs/synaptic/1.1.4/synaptic.min.js', function(){


    const { Layer, Network, Architect, Trainer } = window.synaptic;

    var pauseMinion = true;
    var listMinion = [];
    function Minion() {
      this.name = 'Minion Bot';
      this.skin = Math.floor(Math.random() * window.MAX_SKIN);
      listMinion.push(this);
      this.isPause = false;
      this.isAlive = false;
      this.autonom = false;
      this.IA = false;
      this.network = false;
      this.respawn = true;
      this.spawn();
    }
    Minion.prototype.spawn = function () {
      var _this = this;
      this.socket = new WebSocket(window.socket.url);
      this.socket.binaryType = "arraybuffer";
      this.oldtrap = null;
      this.score = 0;
      this.x = 0;
      this.y = 0;
      this.id = -1;
      this.oldmouseangle = null;
      this.mouseangle = 0;
      this.currentplayer = null;
      this.closestFood = {x:0,y:0};
      this.trap = !1;
      this.mouse_update = (new Date).getTime();
      this.d = (new Date).getTime();
      this.socket.onclose = function () {
        clearInterval(_this.interval);
        _this.isAlive = false;
        if (_this.respawn) {
          _this.spawn();
        }
      }
      this.socket.onmessage = function(a) {
        if ("string" == typeof a.data) {
          a = JSON.parse(a.data);
          if (a[0] == 0) {
            _this.id = a[1][0];
            _this.interval = setInterval(function () {
              var player = null;
              for (var i = 0; i < window.players.length; i++) {
                if (window.players[i].id == window.true_id) {
                  player = window.players[i];
                  break;
                }
              }
              if (_this.autonom && _this.IA && _this.network) {


                // Food Distance
                // Food angle
                // Ennemi Distance
                // Ennemi angle
                // Ennemi Size
                // Ennemi Trap
                // Current Bot Size
                var food_d = dist({x:_this.x,y:_this.y},_this.closestFood) / (window.bg_width*window.map_divisor),
                    food_a = angle({x:_this.x,y:_this.y},_this.closestFood),
                    e_d = 0,
                    e_a = 0,
                    e_s = 0,
                    e_t = 0,
                    c_s = 0;
                  //console.log(food_d,food_a);

                var data = _this.network.activate([food_d,food_a/*,e_d,e_a,e_s,e_t,c_s*/]);

                _this.socket.send("[0," + (data[0] * 2 * Math.PI) + "," + (data[1] > 0.5 ? 1 : 0) + "]");

              } else if (player != null && window.socket.readyState == 1 && _this.socket.readyState == 1) {
                if (_this.isPause) {
                  _this.mouseangle = Math.atan2(_this.y-_this.paused_y,_this.x-_this.paused_x);
                } else {
                  _this.mouseangle = Math.atan2(_this.y-player.y,_this.x-player.x);
                }
                if ((new Date).getTime() - _this.mouse_update > window.MOUSE_DELAY_BETWEEN_UPDATE && (_this.trap != _this.oldtrap || _this.mouseangle != _this.oldmouseangle)) {
                  _this.socket.send("[0," + _this.mouseangle + "," + _this.trap + "]");
                  _this.oldtrap = _this.trap;
                  _this.oldmouseangle = _this.mouseangle;
                  _this.mouse_update = (new Date).getTime();
                }
              }
            }, 33);
          }
        } else {
          a = a.data;
          var c, d, f, e, n, l = new Uint8Array(a),
              h = new Uint16Array(a),
              u = new Uint32Array(a),
              q = new Float64Array(a);
          window.game_time = u[0];
          a = l[6] % 2;
          window.kill_score += (l[6] - l[6] % 2) / 2;
          var w = l[7],
              m = h[2],
              v = [];
          d = 0;
          var distt = Infinity;
          for (c = 1; c < m + 1; c++) {d = Math.floor(u[2 * c + 1] / window.BONUS_SKIN_KEY), v[c - 1] = {
              x: 3 * Math.floor(h[4 * c] / 20),
              y: Math.floor(h[4 * c + 1] / 2),
              id: u[2 * c + 1] - d * window.BONUS_SKIN_KEY,
              instantradius: h[4 * c] % 20,
              alive: h[4 * c + 1] % 2,
              skin: d
          };
          _this.closestFood = {x:v[0].x,y:v[0].y};
          if (dist({x:_this.x,y:_this.y},v[c - 1]) < distt) {
            distt = dist({x:_this.x,y:_this.y},v[c - 1]);
            _this.closestFood = {x:v[c - 1].x,y:v[c - 1].y};
          }


          }
          m = [];
          var prev_nb_trap;
          for (d = prev_nb_trap = 0; d < w; d++)
              for (e = c + 4 * d + prev_nb_trap, m[d] = {
                      x: q[e],
                      y: q[e +
                          1],
                      score: q[e + 2],
                      id: u[2 * (e + 3)] % window.PLAYER_INFO_ALPHA,
                      t: [],
                      n: 0
                  }, n = u[2 * (e + 3) + 1], prev_nb_trap += n, e += 4, f = 0; f < n; f++, e++) m[d].t[f] = {
                  x: h[4 * e],
                  y: h[4 * e + 1],
                  radius: h[4 * e + 2],
                  alpha: l[8 * e + 6],
                  lifetime: l[8 * e + 7]
              };
          for (var i = 0; i < m.length; i++) {
            if (m[i] != -1) {
              if (m[i].id == _this.id) {
                _this.x = m[i].x;
                _this.y = m[i].y;
                _this.score = m[i].score;
                if (!_this.isAlive) {
                  _this.paused_x = _this.x;
                  _this.paused_y = _this.y;
                }
                _this.isAlive = true;
                break;
              }
            }
          }
        }
      }
      this.socket.onopen = function() {
          this.send(JSON.stringify([1, _this.name, _this.skin]))
      };
    };
    Minion.prototype.remove = function () {
      clearInterval(this.interval);
      this.respawn = false;
      this.socket.close();
    }
    Minion.prototype.togglepause = function () {
      this.isPause = pauseMinion ? false : true;
      this.paused_x = this.x;
      this.paused_y = this.y;
    }
    Minion.prototype.togglefree = function () {
      this.autonom = this.autonom ? false : true;
    };
    window.next_start = function() {
        if (window.game_mode == window.MASS_MODE) {
            -1 == window.server_try && (window.server_try = 1 + Math.floor((window.server_info_mass.length - 1) * Math.random()));
            var a = window.server_info_mass[0 == window.server_id ? window.server_try : window.server_id].ip,
                c = window.server_info_mass[0 == window.server_id ? window.server_try : window.server_id].port
        } else window.game_mode == window.KILL_MODE ? (-1 == window.server_try && (window.server_try = 1 + Math.floor((window.server_info_kill.length - 1) * Math.random())), a = window.server_info_kill[0 == window.server_id ? window.server_try : window.server_id].ip, c = window.server_info_kill[0 == window.server_id ? window.server_try : window.server_id].port) : window.game_mode == window.TEAM_MODE ?
            (-1 == window.server_try && (window.server_try = 1 + Math.floor((window.server_info_team.length - 1) * Math.random())), a = window.server_info_team[0 == window.server_id ? window.server_try : window.server_id].ip, c = window.server_info_team[0 == window.server_id ? window.server_try : window.server_id].port) : window.game_mode == window.RACE_MODE ? (-1 == window.server_try && (window.server_try = 1 + Math.floor((window.server_info_race.length - 1) * Math.random())), a = window.server_info_race[0 == window.server_id ? window.server_try : window.server_id].ip, c = window.server_info_race[0 == window.server_id ? window.server_try : window.server_id].port) : window.game_mode == window.RUSH_MODE ? (-1 == window.server_try && (window.server_try = 1 + Math.floor((window.server_info_rush.length -
                1) * Math.random())), a = window.server_info_rush[0 == window.server_id ? window.server_try : window.server_id].ip, c = window.server_info_rush[0 == window.server_id ? window.server_try : window.server_id].port) : window.game_mode == window._1V1_MODE ? (-1 == window.server_try && (window.server_try = 1 + Math.floor((window.server_info__1v1.length - 1) * Math.random())), a = window.server_info__1v1[0 == window.server_id ? window.server_try : window.server_id].ip, c = window.server_info__1v1[0 == window.server_id ? window.server_try : window.server_id].port) : window.game_mode == window.ZOMB_MODE && (-1 == window.server_try && (window.server_try = 1 + Math.floor((window.server_info_zomb.length - 1) * Math.random())), a = window.server_info_zomb[0 == window.server_id ? window.server_try :
                window.server_id].ip, c = window.server_info_zomb[0 == window.server_id ? window.server_try : window.server_id].port);
        window.socket = new WebSocket("ws://" + a + ":" + c);
        window.socket.binaryType = "arraybuffer";
        window.current_socket_id++;
        window.socket.sockid = window.current_socket_id;
        window.socket.onmessage = function(a) {
            "string" == typeof a.data ?
              (a = JSON.parse(a.data), 3 == a[0] ?
                (window.players_nickname[a[2]] = a[1], window.players_skin[a[2]] = a[3])
              : 0 == a[0] ?
                window.handshake(a[1])
              : 1 == a[0] ?
                window.set_top10(a[1])
              : 2 == a[0] ?
                window.server_full()
              : 4 == a[0] ?
                window.skin_hack()
              : 5 == a[0] && window.rush_party_end(a[1])) :
                window.broadcast(a.data)
        };
        window.socket.onopen = function() {
            window.send_nickname();
            window.timeout_wait_handshake = setTimeout(window.wait_handshake, window.WAIT_HANDSHAKE_TIME)
        };
        window.socket.onerror = function(a) {};
        window.socket.onclose = function(a) {
            while (listMinion.length) {
              var minion = listMinion.pop();
              minion.remove();
            }
            document.getElementById('botminionnb').innerHTML = listMinion.length > 1 ? listMinion.length + ' Minions' :listMinion.length + ' Minion';
            window.game_is_show && window.current_socket_id == this.sockid && window.quit_game()
        }
    }
    var div = document.createElement('div');
    div.style.cssText = 'min-width: 300px; position: fixed; font-family: Verdana; z-index: 9999; top: 65px; left: 10px; font-size: 20px; background: #fff; opacity: 0.3; padding: 20px; border-radius: 10px;';
    var minioninnerHTML = '<div onclick="var migffd=document.getElementById(\'minioncontentplusmoins\');if (migffd.innerHTML == \'-\') {migffd.innerHTML=\'+\';document.getElementById(\'listoverlayibfominion\').style.display=\'none\';}else{migffd.innerHTML=\'-\';document.getElementById(\'listoverlayibfominion\').style.display=\'block\';}" style="position: absolute; top: 10px; left: 10px; display: inline-block; border-radius: 10px; box-shadow: 0 0 5px 0 #111; width: 32px; height: 32px; background: #111; border: 1px solid #fff; color: #fff; font-size: 40px;"><span style="position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%)" id="minioncontentplusmoins">-</span></div><div style="display: inline-block; text-align: center; width: 100%;"><tt id="botminionnb" style="font-size: 24px;">0 Minion</tt></div><div id="listoverlayibfominion"><br />';
    minioninnerHTML += '<tt>[A] Add a Minion</tt><br />';
    minioninnerHTML += '<tt>[R] Remove a Minion</tt><br />';
    minioninnerHTML += '<tt>[P] Pause all Minion</tt><br />';
    minioninnerHTML += '<tt>[O] Pause all Minion to local location</tt><br />';
    minioninnerHTML += '</div>';
    div.innerHTML = minioninnerHTML;
    document.body.appendChild(div);
    window.addEventListener("mousemove", function(a) {
        window.updateMousePos(a)
    }, !1);
    window.onkeyup = function (e) {
      switch (e.keyCode) {
        case 90: // Z : start ga
          var ga = new GeneticAlgorithm(20, 5);
          ga.createPopulation();
          document.getElementById('botminionnb').innerHTML = listMinion.length > 1 ? listMinion.length + ' Minions' :listMinion.length + ' Minion';
          break;
        case 65: //A - add a minion
          new Minion();
          document.getElementById('botminionnb').innerHTML = listMinion.length > 1 ? listMinion.length + ' Minions' :listMinion.length + ' Minion';
          break;
        case 82: //R - remove a minion
          if (listMinion.length > 0) {
            var minion = listMinion.pop();
            minion.remove();
            document.getElementById('botminionnb').innerHTML = listMinion.length > 1 ? listMinion.length + ' Minions' :listMinion.length + ' Minion';
          }
          break;
        case 75: //K - Autonome Minion
          for (var i = 0; i < listMinion.length; i++) {
            listMinion[i].toggleFree();
          }
          break;
        case 80: //P - pause minion
          pauseMinion = pauseMinion ? false : true;
          for (var i = 0; i < listMinion.length; i++) {
            listMinion[i].togglepause();
          }
          break;
        case 85: //U - remove all minion
          while (listMinion.length > 0) {
            var minion = listMinion.pop();
            minion.remove();
            document.getElementById('botminionnb').innerHTML = listMinion.length > 1 ? listMinion.length + ' Minions' :listMinion.length + ' Minion';
          }
          break;
        case 79: //O
          for (var j = 0; j < listMinion.length; j++) {
            listMinion[j].pause(true);
          }
          break;
        default:

      }
    }






    var getRandomIntInclusive = function(min, max) {
      min = Math.ceil(min);
      max = Math.floor(max);
      return Math.floor(Math.random() * (max - min +1)) + min;
    };
    var time = performance.now(), randomTime = 0, nbw = 0, nbe = 0, ga, pauseText = 'pause', pause = false, tmpp = 0, score = 0, HighScore = 0;


    var GeneticAlgorithm = function(max_units, top_units){
      this.max_units = max_units; // max number of units in population
      this.top_units = top_units; // number of top units (winners) used for evolving population

      var _this = this;

      if (this.max_units < this.top_units) this.top_units = this.max_units;

      this.Population = []; // array of all units in current population
      this.reset();

      setInterval(function () {
        for (var i = 0; i < _this.Population.length; i++) {
          _this.Population[i].object.socket.close();
        }
        console.log('HERE WE GO AGAIN!!!!!');
        //console.log('COUNT:',_this.checkPopulation());
        //if (!_this.checkPopulation()) {
          _this.evolvePopulation();
        //}
        for (var i = 0; i < _this.Population.length; i++) {
          _this.Population[i].object.spawn();
          _this.Population[i].object.respawn = false;
          _this.Population[i].object.IA = true;
          _this.Population[i].object.isAlive = true;
          _this.Population[i].object.autonom = true;
        }
      }, 1000*10);

      console.log('OK!!');
    };
    GeneticAlgorithm.prototype = {
      reset: function() {
        this.iteration = 1;
        this.mutateRate = 1;

        this.best_population = 0;
        this.best_fitness = 0;

        this.temp = false;
      },
      createIndividual: function() {
        this.id = 'MINION_'+nbe;
        this.index = nbe;
        nbe++;

        // Food Distance
        // Food angle
        // Ennemi Distance
        // Ennemi angle
        // Ennemi Size
        // Ennemi Trap
        // Current Bot Size
        this.network = new synaptic.Architect.Perceptron(/*7*/2, 15, 2);

        this.isWinner = false;

        this.object = new Minion();
        this.object.respawn = false;
        this.object.IA = true;
        this.object.isAlive = true;
        this.object.autonom = true;
        this.object.network = this.network;
      },
      createPopulation: function() {
        this.Population.splice(0, this.Population.length);
        for (var i = 0; i < this.max_units; i++) {
          this.Population.push(new this.createIndividual());
        }
      },
      checkPopulation: function() {
        var nbAlive = this.max_units;
        for (var i = 0; i < this.max_units; i++) {
          if (!this.Population[i].object.isAlive) {nbAlive--;}
        }
        //if (nbAlive <= 0) {
        //  while (listMinion.length > 0) {
        //    var minion = listMinion.pop();
        //    minion.remove();
        //    document.getElementById('botminionnb').innerHTML = listMinion.length > 1 ? listMinion.length + ' Minions' :listMinion.length + ' Minion';
        //  }
        //}
        return nbAlive;
      },
      evolvePopulation: function() {
        if (!this.temp) {
          this.temp = true;
          var Winners = this.selection();
          this.iteration++;
          if (this.mutateRate == 1 && Winners[0].object.score < 0){
            this.createPopulation();
          } else {
            this.mutateRate = 0.2;
          }
          for (var i=this.top_units; i<this.max_units; i++){
            var parentA, parentB, offspring;
            if (i == this.top_units){
              parentA = Winners[0].network.toJSON();
              parentB = Winners[1].network.toJSON();
              offspring = this.crossOver(parentA, parentB);
            } else if (i < this.max_units-2){
              parentA = this.getRandomIndividual(Winners).network.toJSON();
              parentB = this.getRandomIndividual(Winners).network.toJSON();
              offspring = this.crossOver(parentA, parentB);
            } else {
              offspring = this.getRandomIndividual(Winners).network.toJSON();
            }
            offspring = this.mutation(offspring);
            var newIndividual = new this.createIndividual();
            newIndividual.network = synaptic.Network.fromJSON(offspring);
            newIndividual.index = this.Population[i].index;
            this.Population[i] = newIndividual;
          }
          if (Winners[0].object.score > this.best_fitness){
            this.best_population = this.iteration;
            this.best_fitness = Winners[0].object.score;
          }
          console.log('FITNESS:',this.best_fitness);
          this.Population.sort(function(a, b){
            return a.index - b.index;
          });
          for (var i = 0; i < this.max_units; i++) {
            this.Population[i].reset();
          }
          nbw = 0;
          time = Date.now();
          this.temp = false;
        }
      },
      selection: function() {
        var sortedPopulation = this.Population.sort(
          function(unitA, unitB){
            return unitB.object.score - unitA.object.score;
          }
        );
        for (var i=0; i<this.top_units; i++) this.Population[i].isWinner = true;
        return sortedPopulation.slice(0, this.top_units);
      },
      crossOver: function(parentA, parentB) {
        var cutPoint = this.random(0, parentA.neurons.length-1);
        for (var i = cutPoint; i < parentA.neurons.length; i++){
          var biasFromParentA = parentA.neurons[i]['bias'];
          parentA.neurons[i]['bias'] = parentB.neurons[i]['bias'];
          parentB.neurons[i]['bias'] = biasFromParentA;
        }
        return this.random(0, 1) == 1 ? parentA : parentB;
      },
      mutation : function (offspring){
        for (var i = 0; i < offspring.neurons.length; i++){
          offspring.neurons[i]['bias'] = this.mutate(offspring.neurons[i]['bias']);
        }
        for (var i = 0; i < offspring.connections.length; i++){
          offspring.connections[i]['weight'] = this.mutate(offspring.connections[i]['weight']);
        }
        return offspring;
      },
      mutate: function(gene) {
        if (Math.random() < this.mutateRate) {
          var mutateFactor = 1 + ((Math.random() - 0.5) * 3 + (Math.random() - 0.5));
          gene *= mutateFactor;
        }
        return gene;
      },
      random: function(min, max){
        return Math.floor(Math.random()*(max-min+1) + min);
      },
      getRandomIndividual: function(array){
        return array[this.random(0, array.length-1)];
      }
    };
    GeneticAlgorithm.prototype.createIndividual.prototype = {
      reset: function () {
        this.isWinner = false;
        this.learningRate = .3;
        this.object = new Minion();
        this.object.respawn = false;
        this.object.IA = true;
        this.object.isAlive = true;
        this.object.autonom = true;
        this.object.network = this.network;
      }
    };




  });


})();