From c211e8480174d00120a7007efc579da56c60ea84 Mon Sep 17 00:00:00 2001 From: Peery Date: Sat, 24 Sep 2022 19:14:40 +0200 Subject: [PATCH] Added WIP SetupOverlord Added an overlord for the room setup which creates the first creeps and starts harvesting energy. Currently still WIP. --- src/creeps/harvester.js | 40 ++++++++++++++-- src/creeps/role_map.js | 3 +- src/hivemind/hivemind.js | 81 +++++++++++++++++++++++++++++---- src/main.js | 7 ++- src/overlords/overlord.js | 73 ++++++++++++++++++++++++----- src/overlords/setup_overlord.js | 36 +++++++++++++++ 6 files changed, 211 insertions(+), 29 deletions(-) create mode 100644 src/overlords/setup_overlord.js diff --git a/src/creeps/harvester.js b/src/creeps/harvester.js index f56d1eb..1610572 100644 --- a/src/creeps/harvester.js +++ b/src/creeps/harvester.js @@ -1,13 +1,43 @@ +const { sum } = require("lodash"); + var roleHarvester = { minimum_parts: [WORK, MOVE, CARRY], recommended_parts: [WORK, MOVE, CARRY], + min_cost: sum([BODYPART_COST["work"], BODYPART_COST["move"], BODYPART_COST["carry"]]), - /* runs every tick for each creep belonging to the harvester role */ - // creep: name of current creep - run: function(creep) { - console.log("roleHarvester: run() " + creep) - } + /** + * Orders the given spawn to create a creep fitting for this role according to the recommended_parts and if impossible use minimum_parts instead + * @param {spawn} spawn + * @param {string} postfix string to postfix to the creep + * @param {string} owner_id strind id of who shall be entered as owner of the new creep + * + * @return {string} name of the new creep + */ + spawn: function(spawn, postfix, owner_id) { + if (spawn.spawnCreep(this.recommended_parts, "harvester-"+postfix, {dryRun: true}) === OK) { + console.log("roleHarvester: Spawn "+spawn.name+" is creating harvester-"+postfix+" with recommended parts ..."); + spawn.spawnCreep(this.recommended_parts, "harvester-"+postfix, {memory: {"owner": owner_id, "role": "Harv"}}); + } + else if (spawn.spawnCreep(this.minimum_parts, "harvester-"+postfix, {dryRun: true}) === OK) { + console.log("roleHarvester: Spawn "+spawn.name+" is creating harvester-"+postfix+" with minimum parts ..."); + spawn.spawnCreep(this.minimum_parts, "harvester-"+postfix, {memory: {"owner": owner_id, "role": "Harv"}}); + } + else { + console.log("roleHarvester: Spawn \""+spawn.name+"\" couldn't afford a harvester! D:"); + throw "Not enough energy!"; + } + + return "harvester-"+postfix; + }, + + /** + * Runs the logic and actions of the harvester + * @param {string} creep_name + */ + run: function(creep_name) { + console.log("roleHarvester: run() " + creep_name) + }, }; module.exports = roleHarvester; \ No newline at end of file diff --git a/src/creeps/role_map.js b/src/creeps/role_map.js index 2d32361..dff02ef 100644 --- a/src/creeps/role_map.js +++ b/src/creeps/role_map.js @@ -1,5 +1,6 @@ -var harvester_obj = requires('creeps_harvester'); +var harvester_obj = require('creeps_harvester'); +/** Dictionary to map creep roles to their identifier and an object reference */ var roles = { harvester: { ident: "Harv", diff --git a/src/hivemind/hivemind.js b/src/hivemind/hivemind.js index 5c82c01..ebfc9bd 100644 --- a/src/hivemind/hivemind.js +++ b/src/hivemind/hivemind.js @@ -1,31 +1,84 @@ var goals = require('hivemind_goals') -var Overlord = require('overlords_overlord'); +var SetupOverlord = require('overlords_setup_overlord'); +const roles = require('creeps_role_map'); var hivemind = { - /* Lets the hivemind run. That means at the start initializing the hivemind's memory or advancing its state*/ + /** List of references to all overlord objects */ + overlords: [], + + /** Lets the hivemind run. That means at the start initializing the hivemind's memory or advancing its state*/ run: function () { if (Memory.last_tick === undefined) { hivemind.initialize_memory(); } else { + console.log("Hivemind: Loading all overlords ..."); + hivemind.deserialize_overlords(); + + console.log("Hivemind: Advancing state ..."); hivemind.advance_state(); + + console.log("Hivemind: Saving all overlords ..."); + hivemind.serialize_overlords(); + this.overlords = []; // fixing issue where the next tick still had this list when the script kept running } }, - /* Initializes memory variables. Expected to be only called once at the start of the entire script. */ + /** Initializes memory variables. Expected to be only called once at the start of the entire script. */ initialize_memory: function () { - console.log("Initializing memory. Creating overlord \"Adam\"") + console.log("Initializing memory...") Memory.last_tick = 0; - var init_overlord = new Overlord("Adam", goals.INITIAL_SETUP); + Memory.overlords = {}; + + var init_overlord = this.create_new_overlord("Adam", goals.INITIAL_SETUP); - for(var curr_spawn_name in Game.spawns) { // at the very start each spawn (the only spawn) needs to start set up the room. - Game.spawns[curr_spawn_name].memory.owner = init_overlord.id; + for(var curr_spawn_name in Game.spawns) { // at the very start each spawn (the only spawn) needs to get assigned to the only overlord + init_overlord.add_spawn(curr_spawn_name); + } + + console.log("Hivemind: Saving all overlords ..."); + this.serialize_overlords(); + }, + + /** Serializes all overlords into memory */ + create_new_overlord: function (name, goal) { + console.log("Creating overlord \""+name+"\" with goal "+goal+"..."); + if (goal === goals.INITIAL_SETUP) { + var new_overlord = new SetupOverlord(name); + } + else { + throw "Creating overlord with unknown goal!" + } + new_overlord.goal = goal; + this.overlords.push(new_overlord); + + return new_overlord; + }, + + /** Serializes all overlords into memory */ + serialize_overlords: function () { + for (let overlord of this.overlords) { + overlord.serialize(); } }, + /** Deserializes all overlords from memory */ + deserialize_overlords: function () { + for (var overlord_id in Memory.overlords) { + if (Memory.overlords[overlord_id]['goal'] === goals.INITIAL_SETUP) { + var overlord = new SetupOverlord(overlord_id, goals.INITIAL_SETUP) // TODO fix loading correct overlord type + } + else { + throw "Tried to deserialize overlord with unknown goal" + } + overlord.deserialize(); + + this.overlords.push(overlord); + } + }, - /* Starts querying global info Updates the hivemind state to decide on goals */ + /** Starts querying global info Updates the hivemind state to decide on goals */ advance_state: function () { if (Memory.last_tick === 0) { // last_tick is used as a makeshift timestamp to remember if something was this tick or the last. Memory.last_tick = 1; @@ -35,6 +88,18 @@ var hivemind = { Memory.last_tick = 0; //console.log("Tick is now 1"); } + + for (let overlord of this.overlords) { + console.log("Hivemind: Running overlord \""+overlord.id+"\" now ..."); + overlord.run(); + } + + for (let name in Game.creeps) { + let creep = Game.creeps[name]; + let creep_role = creep.memory.role + console.log("Hivemind: Running creep \""+name+"|"+creep_role+"\""); + // TODO run creep's role + } }, }; diff --git a/src/main.js b/src/main.js index 3283b36..1a110c9 100644 --- a/src/main.js +++ b/src/main.js @@ -2,9 +2,8 @@ var harvester = require('creeps_harvester'); var hivemind = require('hivemind_hivemind'); module.exports.loop = function () { + console.log("-------- TICK STARTING --------"); hivemind.run(); - for (let spawn_name in Game.spawns) { - var spawn = Game.spawns[spawn_name]; - - } + console.log("-------- TICK ENDING --------"); + console.log(); } \ No newline at end of file diff --git a/src/overlords/overlord.js b/src/overlords/overlord.js index e02f587..9a13009 100644 --- a/src/overlords/overlord.js +++ b/src/overlords/overlord.js @@ -1,22 +1,73 @@ /** - * Overlord that sets up a room given only a single spawn with a minimum energy to build one harvester. - * - * Setup is considered finished once 3 spawns have been built and at least one creep is maintaining the RCL + * Generic overlord prototype */ -function overlord (name, goal) { // TODO can I do makeshift inheritance? +function overlord (name) { - /* Unique identifier, set at creation or by deserialize() */ + /** Unique identifier, set at creation or by deserialize() */ this.id = name; - /* Goal the overlord follows */ - this.goal = goal; + /** Goal the overlord follows */ + this.goal = undefined; - /* Serializes the overlord state so that it can survive in memory */ - this.serialize = function(memory_key) {}; + this.underlings = { + "spawns": [], + "creeps": [], + }; + + /** Serializes the overlord state so that it can survive in memory */ + this.serialize = function() { + var data = { + "id": this.id, + "goal": this.goal, + "underlings": this.underlings, + }; + Memory.overlords[this.id] = data; + console.log("Overlord: Wrote overlord "+this.id+" to memory!"); + }; + + /** Reconstructs the overlord state from memory given its identifier */ + this.deserialize = function() { + this.goal = Memory.overlords[this.id]["goal"]; + this.underlings = Memory.overlords[this.id]["underlings"]; + + console.log("Overlord: Read overlord "+this.id+" from memory!"); + }; + + /** + * Helper function to add a spawn to the underlings of this overlord + * @param {string} spawn_name + */ + this.add_spawn = function(spawn_name) { + let spawn = Game.spawns[spawn_name]; + if (spawn.memory.owner !== undefined) { // spawn already owned by someone + throw "Spawn already taken!"; + } + spawn.memory.owner = this.id; + this.underlings["spawns"].push(spawn_name); + console.log("Overlord: assigned spawn \""+spawn_name+"\" to overlord \""+this.id+"\"!"); + }; + + /** + * Helper function to add a creep to the underlings of this overlord + * @param {string} creep_name + */ + this.add_creep = function(creep_name) { + let creep = Game.creeps[creep_name]; + if (creep.memory.owner !== undefined) { // creep already owned by someone + console.log("Overlord: ERROR Creep was already taken!"); + throw "Creep already taken!"; + } + creep.memory.owner = this.id; + this.underlings["creeps"].push(creep_name); + console.log("Overlord: assigned creep \""+creep_name+"\" to overlord \""+this.id+"\"!"); + } + + /** + * run function to be implemented by non-generic overlords + */ + //this.run = function () {console.log("Trying to run a generic overlord! Bad!");}; - /* Reconstructs the overlord state from memory given its identifier */ - this.deserialize = function(memory_key) {}; }; module.exports = overlord; \ No newline at end of file diff --git a/src/overlords/setup_overlord.js b/src/overlords/setup_overlord.js new file mode 100644 index 0000000..49dbc8d --- /dev/null +++ b/src/overlords/setup_overlord.js @@ -0,0 +1,36 @@ +var setup_overlord = require('overlords_overlord'); +var harvester = require('creeps_harvester'); + +/** + * Overlord that sets up a room given only a single spawn with a minimum energy to build one harvester. + * + * Setup is considered finished once 3 spawns have been built and at least one creep is maintaining the RCL + */ + + +/** Checks the room and sets out the tasks to achieve the goal */ +setup_overlord.prototype.run = function () { // TODO somehow these aren't changing anything + console.log("SetupOverlord: Running \""+this.id+"\"! :) Chilling for now ..."); + console.log("SetupOverlord: has the following underlings: ", this.underlings['spawns'], this.underlings['creeps']); + + if (this.underlings['creeps'].length === 0 && this.underlings['spawns'].length === 0) { // got NOTHING to work with + console.log("SetupOverlord: ERROR "+this.id+" has nothing! ;W;"); + } + else if (this.underlings['creeps'].length === 0 && this.underlings['spawns'].length > 0) { + console.log("SetupOverlord: \""+this.id+"\" is trying to creat a harvester ..."); + + let spawn_name = null; + for (spawn_name of this.underlings['spawns']) { + let spawn = Game.spawns[this.underlings['spawns']]; + if (spawn.store[RESOURCE_ENERGY] > harvester.min_cost) { // can afford a harvester + console.log("SetupOverlord: Spawn "+spawn.name+" can afford a harvester! ("+harvester.min_cost+") \\o/"); + let new_harvester_name = harvester.spawn(spawn, this.id+"-0", this.id); + this.add_creep(new_harvester_name); + break; + } + } + //spawn = Game.spawns[this.underlings['spawns']] + } +}; + +module.exports = setup_overlord; \ No newline at end of file