Moved spawning to room, multiple miners working.

This commit is contained in:
2026-07-10 14:17:00 +02:00
parent 3148302aae
commit fb07ab70fc
5 changed files with 183 additions and 149 deletions

View File

@@ -1,17 +1,23 @@
#ifndef DOUWCO_HIVEMIND_ROOM_HPP #ifndef DOUWCO_HIVEMIND_ROOM_HPP
#define DOUWCO_HIVEMIND_ROOM_HPP #define DOUWCO_HIVEMIND_ROOM_HPP
#include "Constants.hpp"
#include <Screeps/Room.hpp> #include <Screeps/Room.hpp>
#include <vector> #include <vector>
namespace DouwcoHivemind { namespace DouwcoHivemind {
class Room { class Room {
public:
protected: Screeps::Room roomJs;
Screeps::Room room;
JSON memory; JSON memory;
std::vector<std::string> sources = {};
std::vector<std::string> sourceContainers = {}; std::vector<std::string> sourceIds = {};
std::vector<std::string> sourceContainerIds = {};
std::vector<std::string> SpawnIds = {};
std::vector<std::string> screepNames = {};
private:
int minerIterator;
public: public:
Room(Screeps::Room rm); Room(Screeps::Room rm);
@@ -20,6 +26,8 @@ public:
void loop(); void loop();
protected: protected:
void manageScreeps();
void manageStructures();
void placeContainers(); void placeContainers();
}; };
} // namespace DouwcoHivemind } // namespace DouwcoHivemind

View File

@@ -9,15 +9,13 @@ namespace DouwcoHivemind
{ {
class Spawn : public StructureBase class Spawn : public StructureBase
{ {
private: public:
Screeps::StructureSpawn spawn; Screeps::StructureSpawn spawnJs;
public: public:
Spawn(Screeps::StructureSpawn spwn) : spawn(spwn), Spawn(Screeps::StructureSpawn spwn) : spawnJs(spwn),
StructureBase() {} StructureBase() {}
~Spawn() {} ~Spawn() {}
void loop() override;
}; };
} }

View File

@@ -36,9 +36,7 @@ DouwcoHivemind::Worker::~Worker() { memory["harvesting"] = harvesting; }
void DouwcoHivemind::Worker::loop() { void DouwcoHivemind::Worker::loop() {
if (harvesting) { if (harvesting) {
JS::console.log(std::string("worker: harvesting"));
if (creep.store().getFreeCapacity(Screeps::RESOURCE_ENERGY) == 0) { if (creep.store().getFreeCapacity(Screeps::RESOURCE_ENERGY) == 0) {
JS::console.log(std::string("worker: harvesting full"));
harvesting = false; harvesting = false;
targetId.clear(); targetId.clear();
} else { } else {
@@ -55,20 +53,15 @@ void DouwcoHivemind::Worker::loop() {
} }
void DouwcoHivemind::Worker::getEnergy() { void DouwcoHivemind::Worker::getEnergy() {
JS::console.log(std::string("worker: get energy"));
if (targetId.empty()) { if (targetId.empty()) {
JS::console.log(std::string("worker: No target search energy"));
searchEnergySource(); searchEnergySource();
} else { } else {
JS::console.log(std::string("worker: has target with energy"));
auto target = getRoomObjectTarget(); auto target = getRoomObjectTarget();
if (!target) if (!target)
return; return;
if (isNearTo(target->pos(), 1)) { if (isNearTo(target->pos(), 1)) {
JS::console.log(std::string("worker: collect energy"));
extractEnergyFromTarget(); extractEnergyFromTarget();
} else { } else {
JS::console.log(std::string("worker: go to energy"));
moveToTarget(1); moveToTarget(1);
} }
} }
@@ -95,6 +88,10 @@ void DouwcoHivemind::Worker::searchEnergySource() {
.value_or(0); .value_or(0);
if (availableEnergy == 0) if (availableEnergy == 0)
continue; continue;
if (container->pos().inRangeTo(creep.pos(), 3)) {
targetId = container->id();
return;
}
if (fullestContents < availableEnergy) { if (fullestContents < availableEnergy) {
fullestContents = availableEnergy; fullestContents = availableEnergy;
containerID = container->id(); containerID = container->id();
@@ -103,6 +100,11 @@ void DouwcoHivemind::Worker::searchEnergySource() {
} }
} }
// If no storage go for the containers
if (!containerID.empty()) {
targetId = containerID;
}
// Search for loose resources // Search for loose resources
auto resourceObjects = creep.room().find(Screeps::FIND_DROPPED_RESOURCES); auto resourceObjects = creep.room().find(Screeps::FIND_DROPPED_RESOURCES);
if (resourceObjects.size() > 0) { if (resourceObjects.size() > 0) {
@@ -113,6 +115,10 @@ void DouwcoHivemind::Worker::searchEnergySource() {
if (resource->resourceType() != Screeps::RESOURCE_ENERGY) if (resource->resourceType() != Screeps::RESOURCE_ENERGY)
continue; continue;
int amount = resource->amount(); int amount = resource->amount();
if (resource->pos().inRangeTo(creep.pos(), 3)) {
targetId = resource->id();
return;
}
if (amount < 100) if (amount < 100)
continue; continue;
if (amount > highestAmount) { if (amount > highestAmount) {
@@ -137,6 +143,10 @@ void DouwcoHivemind::Worker::searchEnergySource() {
continue; continue;
int amount = int amount =
ruin->store().getUsedCapacity(Screeps::RESOURCE_ENERGY).value_or(0); ruin->store().getUsedCapacity(Screeps::RESOURCE_ENERGY).value_or(0);
if (ruin->pos().inRangeTo(creep.pos(), 3) && amount > 0) {
targetId = ruin->id();
return;
}
if (amount > highestAmount) { if (amount > highestAmount) {
highestAmount = amount; highestAmount = amount;
ruinID = ruin->id(); ruinID = ruin->id();
@@ -160,6 +170,10 @@ void DouwcoHivemind::Worker::searchEnergySource() {
int amount = tombstone->store() int amount = tombstone->store()
.getUsedCapacity(Screeps::RESOURCE_ENERGY) .getUsedCapacity(Screeps::RESOURCE_ENERGY)
.value_or(0); .value_or(0);
if (tombstone->pos().inRangeTo(creep.pos(), 3) && amount > 0) {
targetId = tombstone->id();
return;
}
if (amount > highestAmount) { if (amount > highestAmount) {
highestAmount = amount; highestAmount = amount;
TombstoneID = tombstone->id(); TombstoneID = tombstone->id();
@@ -171,13 +185,8 @@ void DouwcoHivemind::Worker::searchEnergySource() {
} }
} }
// If still nothing found take the earlier found container.
if (!containerID.empty()) {
targetId = containerID;
}
// If still nothing found, there is no target and search should start again. // If still nothing found, there is no target and search should start again.
targetId = std::string(); targetId.clear();
} }
void DouwcoHivemind::Worker::extractEnergyFromTarget() { void DouwcoHivemind::Worker::extractEnergyFromTarget() {

View File

@@ -1,5 +1,6 @@
#include "Entity/Room.hpp" #include "Entity/Room.hpp"
#include "Engine.hpp"
#include "Screeps/Constants.hpp" #include "Screeps/Constants.hpp"
#include "Screeps/Game.hpp" #include "Screeps/Game.hpp"
#include "Screeps/Room.hpp" #include "Screeps/Room.hpp"
@@ -12,39 +13,158 @@
#include "Screeps/StructureController.hpp" #include "Screeps/StructureController.hpp"
#include "Constants.hpp" #include "Constants.hpp"
#include "Screeps/StructureSpawn.hpp"
#include "Structures/Spawn.hpp"
#include <cstdint> #include <cstdint>
DouwcoHivemind::Room::Room(Screeps::Room rm) : room(rm), memory(rm.memory()) { DouwcoHivemind::Room::Room(Screeps::Room rm) : roomJs(rm), memory(rm.memory()) {
if (memory.contains("sources")) if (memory.contains("sources"))
sources = static_cast<std::vector<std::string>>(memory["sources"]); sourceIds = static_cast<std::vector<std::string>>(memory["sources"]);
if (memory.contains("sourceContainers")) if (memory.contains("sourceContainers"))
sourceContainers = sourceContainerIds =
static_cast<std::vector<std::string>>(memory["sourceContainers"]); static_cast<std::vector<std::string>>(memory["sourceContainers"]);
minerIterator = memory.contains("minerIterator")
? static_cast<int>(memory["minerIterator"])
: 0;
} }
DouwcoHivemind::Room::~Room() { DouwcoHivemind::Room::~Room() {
memory["sources"] = sources; memory["sources"] = sourceIds;
memory["sourceContainers"] = sourceContainers; memory["sourceContainers"] = sourceContainerIds;
room.setMemory(memory); memory["minerIterator"] = minerIterator;
roomJs.setMemory(memory);
} }
void DouwcoHivemind::Room::loop() { void DouwcoHivemind::Room::loop() {
if (sources.size() == 0) { manageStructures();
auto sources_ = room.find(Screeps::FIND_SOURCES); manageScreeps();
for (auto &source : sources_) { }
sources.push_back(static_cast<Screeps::Source *>(source.get())->id());
void DouwcoHivemind::Room::manageStructures() { placeContainers(); }
void DouwcoHivemind::Room::manageScreeps() {
// Get energy data
int energyAvailable = roomJs.energyAvailable();
int energyCapacityAvailable = roomJs.energyCapacityAvailable();
// Calculate needed creep roles
int required_upgraders = 1;
int required_suppliers = 2;
int required_maintainers = 1;
int required_builders =
roomJs.find(Screeps::FIND_MY_CONSTRUCTION_SITES).size() > 0 ? 1 : 0;
int required_miners = sourceIds.size();
// Count existing roles
int existing_upgraders = 0;
int existing_suppliers = 0;
int existing_maintainers = 0;
int existing_builders = 0;
int existing_miners = 0;
for (auto &creep : Engine::getInstance()->Creeps) {
CreepRole role = creep.second->role;
if (role == CreepRole::SUPPLIER)
existing_suppliers++;
else if (role == CreepRole::UPGRADER)
existing_upgraders++;
else if (role == CreepRole::MAINTAINER)
existing_maintainers++;
else if (role == CreepRole::BUILDER)
existing_builders++;
else if (role == CreepRole::MINER)
existing_miners++;
}
// Check if max energy used
if (energyAvailable < energyCapacityAvailable && 0 < existing_suppliers)
return;
// Set creep properties
std::string name;
JSON opts;
CreepRole role = CreepRole::UNEMPLOYED;
if (required_miners > existing_miners) {
role = CreepRole::MINER;
opts["memory"]["sourceId"] = sourceIds[minerIterator];
minerIterator = (minerIterator + 1) % sourceIds.size();
name = "Miner: ";
} else if (required_suppliers > existing_suppliers) {
role = CreepRole::SUPPLIER;
name = "Supplier: ";
} else if (required_upgraders > existing_upgraders) {
role = CreepRole::UPGRADER;
name = "Upgrader: ";
} else if (required_builders > existing_builders) {
role = CreepRole::BUILDER;
name = "Builder: ";
} else if (required_maintainers > existing_maintainers) {
role = CreepRole::MAINTAINER;
name = "Maintainer: ";
} else
return;
opts["memory"]["role"] = role;
// Build creep body
std::vector<std::string> body;
// Miner body with up to 5 work (10 en/s) bits for 3000 source mining in 300
// tick regen.
if (role == CreepRole::MINER) {
body.push_back("move");
body.push_back("work");
for (int i = 0; i < (energyAvailable - 150) / 100 && i < 5; i++) {
body.push_back("work");
} }
} }
placeContainers(); // Supplier body with only move and carry to move energy around
else if (role == SUPPLIER) {
for (int i = 0; i < energyAvailable / 100; i++) {
body.push_back("move");
body.push_back("carry");
}
}
// Worker body with balanced parts.
else {
for (int i = 0; i < energyAvailable / 200; i++) {
body.push_back("work");
body.push_back("carry");
body.push_back("move");
}
}
// If no spawns stored yet
if (SpawnIds.size() == 0) {
auto spawnStructures = roomJs.find(Screeps::FIND_MY_SPAWNS);
for (auto &spawnStructure : spawnStructures) {
SpawnIds.push_back(
static_cast<Screeps::StructureSpawn *>(spawnStructure.get())->id());
}
}
// Create creep
auto spawn = static_cast<Spawn *>(
Engine::getInstance()->Structures[SpawnIds[0]].get());
std::string unique_name = name + std::to_string(Screeps::Game.time());
spawn->spawnJs.spawnCreep(body, unique_name, opts);
screepNames.push_back(unique_name);
} }
void DouwcoHivemind::Room::placeContainers() { void DouwcoHivemind::Room::placeContainers() {
// If no sources stored yet
if (sourceIds.size() == 0) {
auto sources_ = roomJs.find(Screeps::FIND_SOURCES);
for (auto &source : sources_) {
sourceIds.push_back(static_cast<Screeps::Source *>(source.get())->id());
}
}
// No containers planned or build, planning now // No containers planned or build, planning now
if (sourceContainers.size() < sources.size()) { if (sourceContainerIds.size() < sourceIds.size()) {
int controller_x = room.controller().value().pos().x(); int controller_x = roomJs.controller().value().pos().x();
int controller_y = room.controller().value().pos().y(); int controller_y = roomJs.controller().value().pos().y();
for (auto sourceId : sources) { for (auto sourceId : sourceIds) {
auto roomObj = Screeps::Game.getObjectById(sourceId); auto roomObj = Screeps::Game.getObjectById(sourceId);
int source_x = roomObj->pos().x(); int source_x = roomObj->pos().x();
int source_y = roomObj->pos().y(); int source_y = roomObj->pos().y();
@@ -58,7 +178,7 @@ void DouwcoHivemind::Room::placeContainers() {
continue; continue;
int x = source_x + dx; int x = source_x + dx;
int y = source_y + dy; int y = source_y + dy;
int terrainType = room.getTerrain().get(x, y); int terrainType = roomJs.getTerrain().get(x, y);
if (terrainType != Screeps::TERRAIN_MASK_WALL) { if (terrainType != Screeps::TERRAIN_MASK_WALL) {
int cost = std::abs(x - controller_x) + std::abs(y - controller_y); int cost = std::abs(x - controller_x) + std::abs(y - controller_y);
if (cost < lowest_cost) { if (cost < lowest_cost) {
@@ -69,30 +189,31 @@ void DouwcoHivemind::Room::placeContainers() {
} }
} }
} }
room.createConstructionSite(best_x, best_y, Screeps::STRUCTURE_CONTAINER); roomJs.createConstructionSite(best_x, best_y,
sourceContainers.push_back("under_construction"); Screeps::STRUCTURE_CONTAINER);
sourceContainerIds.push_back("under_construction");
} }
return; return;
} }
// Check if construction container is done. // Check if construction container is done.
for (auto entry : sourceContainers) { for (auto entry : sourceContainerIds) {
if (entry != "under_construction") if (entry != "under_construction")
continue; continue;
auto structures = room.find(Screeps::FIND_STRUCTURES); auto structures = roomJs.find(Screeps::FIND_STRUCTURES);
int index = 0; int index = 0;
for (auto &structure : structures) { for (auto &structure : structures) {
auto str = dynamic_cast<Screeps::Structure *>(structure.get()); auto str = dynamic_cast<Screeps::Structure *>(structure.get());
if (str->structureType() == Screeps::STRUCTURE_CONTAINER) { if (str->structureType() == Screeps::STRUCTURE_CONTAINER) {
sourceContainers[index] = str->id(); sourceContainerIds[index] = str->id();
index++; index++;
} }
} }
return; return;
} }
// Check if containers still exist // Check if containers still exist
for (int i = 0; i < sourceContainers.size(); i++) { for (int i = 0; i < sourceContainerIds.size(); i++) {
auto roomObj = Screeps::Game.getObjectById(sourceContainers[i]); auto roomObj = Screeps::Game.getObjectById(sourceContainerIds[i]);
if (!roomObj) if (!roomObj)
sourceContainers.erase(sourceContainers.begin() + i); sourceContainerIds.erase(sourceContainerIds.begin() + i);
} }
} }

View File

@@ -1,103 +1 @@
#include <Screeps/Game.hpp>
#include <Screeps/Room.hpp>
#include <Screeps/StructureController.hpp>
#include "Creeps/CreepBase.hpp"
#include "Engine.hpp"
#include "Structures/Spawn.hpp" #include "Structures/Spawn.hpp"
void DouwcoHivemind::Spawn::loop() {
// Get energy data
int energyAvailable = spawn.room().energyAvailable();
int energyCapacityAvailable = spawn.room().energyCapacityAvailable();
// Calculate needed creep roles
int required_upgraders = 1;
int required_suppliers = 2;
int required_maintainers = 1;
int required_builders =
spawn.room().find(Screeps::FIND_MY_CONSTRUCTION_SITES).size() > 0 ? 1 : 0;
int required_miners = 1; // spawn.room().memory()["sources"].size();
// Count existing roles
int existing_upgraders = 0;
int existing_suppliers = 0;
int existing_maintainers = 0;
int existing_builders = 0;
int existing_miners = 0;
for (auto &creep : Screeps::Game.creeps()) {
CreepRole role = creep.second.memory()["role"];
if (role == CreepRole::SUPPLIER)
existing_suppliers++;
else if (role == CreepRole::UPGRADER)
existing_upgraders++;
else if (role == CreepRole::MAINTAINER)
existing_maintainers++;
else if (role == CreepRole::BUILDER)
existing_builders++;
else if (role == CreepRole::MINER)
existing_miners++;
}
// Check if max energy used
if (energyAvailable < energyCapacityAvailable && 0 < existing_suppliers)
return;
// Set creep properties
std::string name;
JSON opts;
CreepRole role = CreepRole::UNEMPLOYED;
if (required_miners > existing_miners) {
role = CreepRole::MINER;
opts["memory"]["sourceId"] =
spawn.room().memory()["sources"][0]; // make logic for more
name = "Miner: ";
} else if (required_suppliers > existing_suppliers) {
role = CreepRole::SUPPLIER;
name = "Supplier: ";
} else if (required_upgraders > existing_upgraders) {
role = CreepRole::UPGRADER;
name = "Upgrader: ";
} else if (required_builders > existing_builders) {
role = CreepRole::BUILDER;
name = "Builder: ";
} else if (required_maintainers > existing_maintainers) {
role = CreepRole::MAINTAINER;
name = "Maintainer: ";
} else
return;
opts["memory"]["role"] = role;
// Build creep body
std::vector<std::string> body;
// Miner body with up to 5 work (10 en/s) bits for 3000 source mining in 300
// tick regen.
if (role == CreepRole::MINER) {
body.push_back("move");
body.push_back("work");
for (int i = 0; i < (energyAvailable - 150) / 100 && i < 5; i++) {
body.push_back("work");
}
}
// Supplier body with only move and carry to move energy around
else if (role == SUPPLIER) {
for (int i = 0; i < energyAvailable / 100; i++) {
body.push_back("move");
body.push_back("carry");
}
}
// Worker body with balanced parts.
else {
for (int i = 0; i < energyAvailable / 200; i++) {
body.push_back("work");
body.push_back("carry");
body.push_back("move");
}
}
// Create creep
spawn.spawnCreep(body, name + std::to_string(Screeps::Game.time()), opts);
}