TooAngel/screeps

View on GitHub
src/brain_stats.js

Summary

Maintainability
A
3 hrs
Test Coverage
'use strict';

brain.stats.init = function() {
  const userName = Memory.username;
  if (!config.stats.enabled || !userName) {
    return false;
  }
  Memory.stats = {[userName]: {roles: {}, room: {}}};
  const rolesNames = _(Game.creeps).map((c) => c.memory.role).countBy((r) => {
    return r;
  }).value();
  _.each(rolesNames, (element, index) => {
    Memory.stats[userName].roles[index] = element;
  });

  if (config.cpuStats.enabled) {
    const startCpuWith = {load: global.load, time: Game.time, bucket: Game.cpu.bucket, tickLimit: global.tickLimit};
    Memory.cpuStats = {
      start: startCpuWith,
      last: startCpuWith,
      summary: {maxBucket: Game.cpu.bucket, maxLoad: global.load, minBucket: Game.cpu.bucket, runTime: 0},
    };
  }
};

brain.stats.modifyRoleAmount = function(role, diff) {
  const userName = Memory.username;
  if (!config.stats.enabled || !userName) {
    return false;
  }
  if (Memory.stats && Memory.stats[userName] && Memory.stats[userName].roles) {
    const roleStat = Memory.stats[userName].roles[role];
    const previousAmount = roleStat ? roleStat : 0;
    const amount = (diff < 0 && previousAmount < -diff) ? 0 : previousAmount + diff;
    brain.stats.add(['roles', role], amount);
  } else {
    brain.stats.init();
  }
};

/**
 * stats.add use for push anything into Memory.stats at a given place.
 *
 * @param {Array} path Sub stats path.
 * @param {Any} newContent The value to push into stats.
 * @return {boolean}
 */
brain.stats.add = function(path, newContent) {
  if (!config.stats.enabled || Game.time % 3) {
    return false;
  }

  const userName = Memory.username;
  Memory.stats = Memory.stats || {};
  Memory.stats[userName] = Memory.stats[userName] || {};

  let current = Memory.stats[userName];
  for (const item of path) {
    if (!current[item]) {
      current[item] = {};
    }
    current = current[item];
  }

  _.merge(current, newContent);
  return true;
};

/**
 * stats.addRoot sets the root values, cpu, exec, gcl
 *
 * @return {boolean}
 */
brain.stats.addRoot = function() {
  if (!config.stats.enabled || Game.time % 3) {
    return false;
  }
  brain.stats.add([], {
    cpu: {
      limit: Game.cpu.limit,
      tickLimit: Game.cpu.tickLimit,
      bucket: Game.cpu.bucket,
    },
    exec: {
      halt: Game.cpu.bucket < Game.cpu.tickLimit * 2,
    },
    gcl: {
      level: Game.gcl.level,
      progress: Game.gcl.progress,
      progressTotal: Game.gcl.progressTotal,
    },
  });
  return true;
};

/**
 * stats.addRoom call stats.add with given values and given sub room path.
 *
 * @param {String} roomName The room which from we will save stats.
 * @param {Number} previousCpu
 * @return {boolean}
 */
brain.stats.addRoom = function(roomName, previousCpu) {
  if (!config.stats.enabled || Game.time % 3) {
    return false;
  }

  const room = Game.rooms[roomName];
  if (!room) {
    return false;
  }
  brain.stats.add(['room', roomName], {
    energy: {
      available: room.energyAvailable,
      capacity: room.energyCapacityAvailable,
      sources: _.sum(_.map(room.findSources(), 'energy')),
    },
    controller: {
      progress: room.controller.progress,
      progressTotal: room.controller.progressTotal,
    },
    creeps: {
      into: room.find(FIND_CREEPS).length,
      queue: Memory[room.name].queue.length,
    },
    cpu: Game.cpu.getUsed() - previousCpu,
  });

  if (room.storage) {
    const storage = room.storage;
    brain.stats.add(['room', roomName, 'storage'], {
      energy: storage.store.energy,
      power: storage.store.power,
    });
  }
  if (room.terminal) {
    const terminal = room.terminal;
    brain.stats.add(['room', roomName, 'terminal'], {
      energy: terminal.store.energy,
      minerals: _.sum(terminal.store) - terminal.store.energy,
    });
  }
  return true;
};

/**
 * cpuLimit
 * sigmoid on Game.cpu.limit + Game.cpu.bucket
 *
 * @return {number}
 */
function cpuLimit() {
  // https://en.wikipedia.org/wiki/Sigmoid_function
  const sigmoid = (x) => 1 + Math.tanh((2 * x) - 1);
  return _.ceil(Game.cpu.limit * sigmoid(Game.cpu.bucket / 10000));
}
module.exports.cpuLimit = cpuLimit;

brain.stats.updateCpuStats = function() {
  if (config.cpuStats.enabled) {
    Memory.cpuStats.last = {
      load: _.round(Game.cpu.getUsed()),
      time: Game.time,
      bucket: Game.cpu.bucket,
      tickLimit: cpuLimit(),
    };
    Memory.cpuStats.summary = {
      maxBucket: Math.max(Memory.cpuStats.summary.maxBucket, Memory.cpuStats.last.bucket),
      maxLoad: Math.max(Memory.cpuStats.summary.maxLoad, Memory.cpuStats.last.load),
      minBucket: Math.min(Memory.cpuStats.summary.minBucket, Memory.cpuStats.last.bucket),
      runTime: Memory.cpuStats.last.time - Memory.cpuStats.start.time,
    };
  }
};