diff --git a/douwco_hivemind/include/Creeps/CreepBase.hpp b/douwco_hivemind/include/Creeps/CreepBase.hpp index 237e13c..124836b 100644 --- a/douwco_hivemind/include/Creeps/CreepBase.hpp +++ b/douwco_hivemind/include/Creeps/CreepBase.hpp @@ -15,7 +15,7 @@ namespace DouwcoHivemind { class CreepBase { public: CreepRole role; - std::string target_id; + std::string targetId; protected: Screeps::Creep creep; diff --git a/douwco_hivemind/include/Creeps/Miner.hpp b/douwco_hivemind/include/Creeps/Miner.hpp index f9afb35..482b586 100644 --- a/douwco_hivemind/include/Creeps/Miner.hpp +++ b/douwco_hivemind/include/Creeps/Miner.hpp @@ -9,7 +9,8 @@ namespace DouwcoHivemind class Miner : public CreepBase { private: - bool arrivedAtContainer; + std::string sourceId; + bool arrived; public: Miner(Screeps::Creep crp); diff --git a/douwco_hivemind/include/Creeps/Supplier.hpp b/douwco_hivemind/include/Creeps/Supplier.hpp index 247d299..695c080 100644 --- a/douwco_hivemind/include/Creeps/Supplier.hpp +++ b/douwco_hivemind/include/Creeps/Supplier.hpp @@ -3,20 +3,18 @@ #include "Creeps/Worker.hpp" -namespace DouwcoHivemind -{ - class Supplier : public Worker - { - public: - Supplier(Screeps::Creep creep) : Worker(creep) {} +namespace DouwcoHivemind { +class Supplier : public Worker { +public: + Supplier(Screeps::Creep creep) : Worker(creep) { ignoreStorage = true; } - protected: - void depositEnergy() override; - - private: - std::unique_ptr getEnergyStructureTarget(); - void searchEnergyStructure(); - }; -} +protected: + void depositEnergy() override; + +private: + std::unique_ptr getEnergyStructureTarget(); + void searchEnergyStructure(); +}; +} // namespace DouwcoHivemind #endif // DOUWCO_HIVEMIND_SUPPLIER_HPP \ No newline at end of file diff --git a/douwco_hivemind/include/Creeps/Worker.hpp b/douwco_hivemind/include/Creeps/Worker.hpp index 47b1b9c..8647d39 100644 --- a/douwco_hivemind/include/Creeps/Worker.hpp +++ b/douwco_hivemind/include/Creeps/Worker.hpp @@ -4,32 +4,28 @@ #include "Creeps/CreepBase.hpp" #include "Screeps/StructureContainer.hpp" -namespace DouwcoHivemind -{ - class Worker : public CreepBase - { - private: - bool harvesting; - bool foundContainer; +namespace DouwcoHivemind { +class Worker : public CreepBase { +protected: + bool ignoreStorage = false; - public: - Worker(Screeps::Creep crp); - ~Worker() override; +private: + bool harvesting; - void loop() override; +public: + Worker(Screeps::Creep crp); + ~Worker() override; - protected: - virtual void depositEnergy(){} - - private: - void getEnergy(); - void harvestSource(); - void collectEnergyFromContainers(); - std::unique_ptr getSourceTarget(); - std::unique_ptr getContainerTarget(); - void searchSource(); - void searchContainer(); - }; -} + void loop() override; + +protected: + virtual void depositEnergy() {} + +private: + void getEnergy(); + void searchEnergySource(); + void extractEnergyFromTarget(); +}; +} // namespace DouwcoHivemind #endif // DOUWCO_HIVEMIND_HARVESTER_HPP \ No newline at end of file diff --git a/douwco_hivemind/include/Entity/Room.hpp b/douwco_hivemind/include/Entity/Room.hpp index 5704977..170082a 100644 --- a/douwco_hivemind/include/Entity/Room.hpp +++ b/douwco_hivemind/include/Entity/Room.hpp @@ -10,6 +10,7 @@ class Room { protected: Screeps::Room room; JSON memory; + std::vector sources = {}; std::vector sourceContainers = {}; public: diff --git a/douwco_hivemind/src/Creeps/Builder.cpp b/douwco_hivemind/src/Creeps/Builder.cpp index 4590c02..0833a67 100644 --- a/douwco_hivemind/src/Creeps/Builder.cpp +++ b/douwco_hivemind/src/Creeps/Builder.cpp @@ -77,7 +77,7 @@ void DouwcoHivemind::Builder::searchConstructionSite() } if (selectedConstructionSite) - target_id = selectedConstructionSite->id(); + targetId = selectedConstructionSite->id(); else - target_id.clear(); + targetId.clear(); } diff --git a/douwco_hivemind/src/Creeps/CreepBase.cpp b/douwco_hivemind/src/Creeps/CreepBase.cpp index 679239d..9dd6f5b 100644 --- a/douwco_hivemind/src/Creeps/CreepBase.cpp +++ b/douwco_hivemind/src/Creeps/CreepBase.cpp @@ -16,14 +16,14 @@ DouwcoHivemind::CreepBase::CreepBase(Screeps::Creep crp) : creep(crp), memory(crp.memory()) { role = memory.contains("role") ? static_cast(memory["role"]) : CreepRole::UNEMPLOYED; - target_id = memory.contains("target_id") - ? static_cast(memory["target_id"]) - : std::string(); + targetId = memory.contains("targetId") + ? static_cast(memory["targetId"]) + : std::string(); } DouwcoHivemind::CreepBase::~CreepBase() { memory["role"] = role; - memory["target_id"] = target_id; + memory["targetId"] = targetId; creep.setMemory(memory); } @@ -127,13 +127,13 @@ void DouwcoHivemind::CreepBase::moveToTarget(int dist) { std::unique_ptr DouwcoHivemind::CreepBase::getRoomObjectTarget() { // Check if any target is present - if (target_id.empty()) + if (targetId.empty()) return nullptr; // Check if game can find target - auto roomObj = Screeps::Game.getObjectById(target_id); + auto roomObj = Screeps::Game.getObjectById(targetId); if (!roomObj) { - JS::console.log(creep.name() + - ": Game can\'t find target id: " + target_id); + JS::console.log(creep.name() + ": Game can\'t find target id: " + targetId); + targetId.clear(); return nullptr; } return std::move(roomObj); diff --git a/douwco_hivemind/src/Creeps/Maintainer.cpp b/douwco_hivemind/src/Creeps/Maintainer.cpp index ffec34c..a9919da 100644 --- a/douwco_hivemind/src/Creeps/Maintainer.cpp +++ b/douwco_hivemind/src/Creeps/Maintainer.cpp @@ -85,7 +85,7 @@ void DouwcoHivemind::Maintainer::searchDamagedStructure() } if (selectedStructure && selectedStructure->hits() != selectedStructure->hitsMax()) - target_id = selectedStructure->id(); + targetId = selectedStructure->id(); else - target_id.clear(); + targetId.clear(); } diff --git a/douwco_hivemind/src/Creeps/Miner.cpp b/douwco_hivemind/src/Creeps/Miner.cpp index 0722278..87bb6ca 100644 --- a/douwco_hivemind/src/Creeps/Miner.cpp +++ b/douwco_hivemind/src/Creeps/Miner.cpp @@ -2,39 +2,63 @@ #include "Creeps/CreepBase.hpp" #include "Screeps/Constants.hpp" #include "Screeps/Creep.hpp" +#include "Screeps/Game.hpp" #include "Screeps/Room.hpp" #include "Screeps/RoomPosition.hpp" #include "Screeps/Source.hpp" +#include "Screeps/Structure.hpp" #include DouwcoHivemind::Miner::Miner(Screeps::Creep crp) : CreepBase(crp) { - arrivedAtContainer = memory.contains("arrivedAtContainer") - ? static_cast(memory["arrivedAtContainer"]) - : false; + sourceId = memory.contains("sourceId") + ? static_cast(memory["sourceId"]) + : ""; + arrived = + memory.contains("arrived") ? static_cast(memory["arrived"]) : false; } DouwcoHivemind::Miner::~Miner() { - memory["arrivedAtContainer"] = arrivedAtContainer; + memory["sourceId"] = sourceId; + memory["arrived"] = arrived; } void DouwcoHivemind::Miner::loop() { - if (arrivedAtContainer) { - auto source = - static_cast(getRoomObjectTarget().release()); + // Find assigned source + auto source = static_cast( + Screeps::Game.getObjectById(sourceId).release()); + if (!source) + return; + // If arrived just harvest the source + if (arrived) { creep.harvest(*source); - } else { - auto container = getRoomObjectTarget(); - if (!container) - return; - if (isNearTo(container->pos(), 0)) { - arrivedAtContainer = true; - int x = creep.pos().x(); - int y = creep.pos().y(); - auto roomObjs = creep.pos().findClosestByRange(Screeps::FIND_SOURCES, 2); - auto source = static_cast(roomObjs.release()); - target_id = source->id(); - } else { - moveToTarget(0); + } + // Otherwise move towards the source or a container near it + else { + auto target = getRoomObjectTarget(); + // If target is set move to it or detect if you arrive + if (target) { + bool targetIsSource = target->pos().isEqualTo(source->pos()); + int closenessToTarget = targetIsSource ? 1 : 0; + if (isNearTo(target->pos(), closenessToTarget)) { + arrived = true; + } else { + moveToTarget(closenessToTarget); + } + } + // if no target look if there are containers near the source otherwise go to source directly. + else { + auto structureRoomObjs = + source->pos().findInRange(Screeps::FIND_STRUCTURES, 2); + for (auto &structureRoomObj : structureRoomObjs) { + auto structure = + static_cast(structureRoomObj.get()); + if (Screeps::STRUCTURE_CONTAINER == structure->structureType()) { + targetId = structure->id(); + break; + } + } + if (targetId.empty()) + targetId = sourceId; } } } \ No newline at end of file diff --git a/douwco_hivemind/src/Creeps/Supplier.cpp b/douwco_hivemind/src/Creeps/Supplier.cpp index 7f798da..d4e3a3c 100644 --- a/douwco_hivemind/src/Creeps/Supplier.cpp +++ b/douwco_hivemind/src/Creeps/Supplier.cpp @@ -116,7 +116,7 @@ void DouwcoHivemind::Supplier::searchEnergyStructure() { selectedStructureId = storageStructureId; if (selectedStructureId.empty()) - target_id.clear(); + targetId.clear(); else - target_id = selectedStructureId; + targetId = selectedStructureId; } diff --git a/douwco_hivemind/src/Creeps/Upgrader.cpp b/douwco_hivemind/src/Creeps/Upgrader.cpp index 814e6d7..6cb9507 100644 --- a/douwco_hivemind/src/Creeps/Upgrader.cpp +++ b/douwco_hivemind/src/Creeps/Upgrader.cpp @@ -21,7 +21,7 @@ void DouwcoHivemind::Upgrader::depositEnergy() { auto controller = creep.room().controller().value(); - target_id = controller.id(); + targetId = controller.id(); if (isNearTo(controller.pos(), 3)) { int resp = creep.upgradeController(controller); diff --git a/douwco_hivemind/src/Creeps/Worker.cpp b/douwco_hivemind/src/Creeps/Worker.cpp index 09c4431..886bd41 100644 --- a/douwco_hivemind/src/Creeps/Worker.cpp +++ b/douwco_hivemind/src/Creeps/Worker.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -17,159 +18,179 @@ #include #include +#include "Constants.hpp" #include "Creeps/Worker.hpp" +#include "Screeps/Resource.hpp" +#include "Screeps/Ruin.hpp" #include "Screeps/StructureContainer.hpp" +#include "Screeps/StructureStorage.hpp" +#include "Screeps/Tombstone.hpp" DouwcoHivemind::Worker::Worker(Screeps::Creep crp) : CreepBase(crp) { harvesting = memory.contains("harvesting") ? static_cast(memory["harvesting"]) : false; - foundContainer = memory.contains("foundContainer") - ? static_cast(memory["foundContainer"]) - : false; } -DouwcoHivemind::Worker::~Worker() { - memory["harvesting"] = harvesting; - memory["foundContainer"] = foundContainer; -} +DouwcoHivemind::Worker::~Worker() { memory["harvesting"] = harvesting; } void DouwcoHivemind::Worker::loop() { if (harvesting) { + JS::console.log(std::string("worker: harvesting")); if (creep.store().getFreeCapacity(Screeps::RESOURCE_ENERGY) == 0) { + JS::console.log(std::string("worker: harvesting full")); harvesting = false; - target_id.clear(); + targetId.clear(); + } else { + getEnergy(); } - getEnergy(); } else { if (creep.store().getUsedCapacity(Screeps::RESOURCE_ENERGY) == 0) { harvesting = true; - target_id.clear(); + targetId.clear(); + } else { + depositEnergy(); } - depositEnergy(); } } void DouwcoHivemind::Worker::getEnergy() { - if (foundContainer || Screeps::Game.time()%100==0) collectEnergyFromContainers(); - else harvestSource(); -} - -void DouwcoHivemind::Worker::collectEnergyFromContainers() { - auto container = getContainerTarget(); - if (!container) - return; - - if (isNearTo(container->pos(), 1)) { - int resp = creep.withdraw(*container, Screeps::RESOURCE_ENERGY); + JS::console.log(std::string("worker: get energy")); + if (targetId.empty()) { + JS::console.log(std::string("worker: No target search energy")); + searchEnergySource(); } else { - moveToTarget(); + JS::console.log(std::string("worker: has target with energy")); + auto target = getRoomObjectTarget(); + if (!target) + return; + if (isNearTo(target->pos(), 1)) { + JS::console.log(std::string("worker: collect energy")); + extractEnergyFromTarget(); + } else { + JS::console.log(std::string("worker: go to energy")); + moveToTarget(1); + } } } -void DouwcoHivemind::Worker::harvestSource() { - auto source = getSourceTarget(); - if (!source) - return; - - if (isNearTo(source->pos(), 1)) { - int resp = creep.harvest(*source); - } else { - moveToTarget(); - } -} - -std::unique_ptr -DouwcoHivemind::Worker::getContainerTarget() { - auto roomObj = getRoomObjectTarget(); - if (!roomObj) { - searchContainer(); - return nullptr; - } - - // Check if found roomobject is an actual source - auto container = std::unique_ptr( - dynamic_cast(roomObj.release())); - if (!container) { - // EM_ASM({console.log($0 + ': Can\'t cast target to Source')}, - // creep.name().c_str()); - searchContainer(); - return nullptr; - } - - // Check if the source still has energy to harvest - if (container->store().getUsedCapacity(Screeps::RESOURCE_ENERGY) == 0) { - searchContainer(); - return nullptr; - } - - return std::move(container); -} - -std::unique_ptr DouwcoHivemind::Worker::getSourceTarget() { - auto roomObj = getRoomObjectTarget(); - if (!roomObj) { - searchSource(); - return nullptr; - } - - // Check if found roomobject is an actual source - auto source = std::unique_ptr( - dynamic_cast(roomObj.release())); - if (!source) { - // EM_ASM({console.log($0 + ': Can\'t cast target to Source')}, - // creep.name().c_str()); - searchSource(); - return nullptr; - } - - // Check if the source still has energy to harvest - if (source->energy() == 0) { - searchSource(); - return nullptr; - } - - return std::move(source); -} - -void DouwcoHivemind::Worker::searchSource() { - target_id.clear(); - auto sourceObject = creep.pos().findClosestByRange(Screeps::FIND_SOURCES); - if (!sourceObject) - return; - auto source = dynamic_cast(sourceObject.release()); - target_id = source->id(); -} - -void DouwcoHivemind::Worker::searchContainer() { - target_id.clear(); - +void DouwcoHivemind::Worker::searchEnergySource() { + // Search for storage and containers + std::string containerID = std::string(); auto structureObjects = creep.room().find(Screeps::FIND_STRUCTURES); - if (structureObjects.size() == 0) - return; - - int fullestContents = 0; - Screeps::StructureContainer *selectedContainer; - for (auto &structureObject : structureObjects) { - auto structure = - dynamic_cast(structureObject.release()); - if (structure->structureType() != Screeps::STRUCTURE_CONTAINER) - continue; - auto container = dynamic_cast(structure); - int availableEnergy = - container->store().getUsedCapacity(Screeps::RESOURCE_ENERGY).value(); - if (availableEnergy == 0) - continue; - if (fullestContents < availableEnergy) { - fullestContents = availableEnergy; - selectedContainer = container; + if (structureObjects.size() > 0) { + int fullestContents = 0; + for (auto &structureObject : structureObjects) { + auto structure = static_cast(structureObject.get()); + auto structureType = structure->structureType(); + if (structureType == Screeps::STRUCTURE_STORAGE) { + if (ignoreStorage) + continue; + targetId = structure->id(); + return; + } else if (structureType == Screeps::STRUCTURE_CONTAINER) { + auto container = static_cast(structure); + int availableEnergy = container->store() + .getUsedCapacity(Screeps::RESOURCE_ENERGY) + .value_or(0); + if (availableEnergy == 0) + continue; + if (fullestContents < availableEnergy) { + fullestContents = availableEnergy; + containerID = container->id(); + } + } } } - if (!selectedContainer) { - foundContainer = false; - } else { - foundContainer = true; - target_id = selectedContainer->id(); + // Search for loose resources + auto resourceObjects = creep.room().find(Screeps::FIND_DROPPED_RESOURCES); + if (resourceObjects.size() > 0) { + int highestAmount = 0; + std::string resourceID = std::string(); + for (auto &resourceObject : resourceObjects) { + auto resource = static_cast(resourceObject.get()); + if (resource->resourceType() != Screeps::RESOURCE_ENERGY) + continue; + int amount = resource->amount(); + if (amount < 100) + continue; + if (amount > highestAmount) { + highestAmount = amount; + resourceID = resource->id(); + } + } + if (!resourceID.empty()) { + targetId = resourceID; + return; + } } -} \ No newline at end of file + + // Search for existing ruins + auto ruinObjects = creep.room().find(Screeps::FIND_RUINS); + if (ruinObjects.size() > 0) { + int highestAmount = 0; + std::string ruinID = std::string(); + for (auto &ruinObject : ruinObjects) { + auto ruin = static_cast(ruinObject.get()); + if (ruin->ticksToDecay() < 100) + continue; + int amount = + ruin->store().getUsedCapacity(Screeps::RESOURCE_ENERGY).value_or(0); + if (amount > highestAmount) { + highestAmount = amount; + ruinID = ruin->id(); + } + } + if (!ruinID.empty()) { + targetId = ruinID; + return; + } + } + + // Search for existing tombstones + auto tombstoneObjects = creep.room().find(Screeps::FIND_TOMBSTONES); + if (tombstoneObjects.size() > 0) { + int highestAmount = 0; + std::string TombstoneID = std::string(); + for (auto &tombstoneObject : tombstoneObjects) { + auto tombstone = static_cast(tombstoneObject.get()); + if (tombstone->ticksToDecay() < 100) + continue; + int amount = tombstone->store() + .getUsedCapacity(Screeps::RESOURCE_ENERGY) + .value_or(0); + if (amount > highestAmount) { + highestAmount = amount; + TombstoneID = tombstone->id(); + } + } + if (!TombstoneID.empty()) { + targetId = TombstoneID; + return; + } + } + + // 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. + targetId = std::string(); +} + +void DouwcoHivemind::Worker::extractEnergyFromTarget() { + auto roomObj = getRoomObjectTarget(); + if (!roomObj) { + targetId.clear(); + return; + } + + auto resource = dynamic_cast(roomObj.get()); + if (resource) + creep.pickup(*resource); + else + creep.withdraw(*roomObj.get(), Screeps::RESOURCE_ENERGY); + targetId.clear(); +} diff --git a/douwco_hivemind/src/Entity/Room.cpp b/douwco_hivemind/src/Entity/Room.cpp index f049525..2506a05 100644 --- a/douwco_hivemind/src/Entity/Room.cpp +++ b/douwco_hivemind/src/Entity/Room.cpp @@ -6,42 +6,50 @@ #include "Screeps/RoomObject.hpp" #include "Screeps/RoomPosition.hpp" #include "Screeps/RoomTerrain.hpp" +#include "Screeps/Source.hpp" #include "Screeps/Structure.hpp" #include "Screeps/StructureContainer.hpp" #include "Screeps/StructureController.hpp" #include "Constants.hpp" +#include DouwcoHivemind::Room::Room(Screeps::Room rm) : room(rm), memory(rm.memory()) { + if (memory.contains("sources")) + sources = static_cast>(memory["sources"]); if (memory.contains("sourceContainers")) sourceContainers = static_cast>(memory["sourceContainers"]); } DouwcoHivemind::Room::~Room() { + memory["sources"] = sources; memory["sourceContainers"] = sourceContainers; room.setMemory(memory); } -void DouwcoHivemind::Room::loop() { - // Check on building setup - if(Screeps::Game.time()%1000!=0) return; +void DouwcoHivemind::Room::loop() { + if (sources.size() == 0) { + auto sources_ = room.find(Screeps::FIND_SOURCES); + for (auto &source : sources_) { + sources.push_back(static_cast(source.get())->id()); + } + } placeContainers(); } void DouwcoHivemind::Room::placeContainers() { - auto sources = room.find(Screeps::FIND_SOURCES); - // No containers planned or build, planning now if (sourceContainers.size() < sources.size()) { int controller_x = room.controller().value().pos().x(); int controller_y = room.controller().value().pos().y(); - for (auto &source : sources) { - int source_x = source->pos().x(); - int source_y = source->pos().y(); + for (auto sourceId : sources) { + auto roomObj = Screeps::Game.getObjectById(sourceId); + int source_x = roomObj->pos().x(); + int source_y = roomObj->pos().y(); - int lowest_cost = 1000; + int lowest_cost = INT16_MAX; int best_x; int best_y; for (int dx = -1; dx < 2; dx++) { @@ -82,8 +90,9 @@ void DouwcoHivemind::Room::placeContainers() { return; } // Check if containers still exist - for(int i = 0; i < sourceContainers.size(); i++){ + for (int i = 0; i < sourceContainers.size(); i++) { auto roomObj = Screeps::Game.getObjectById(sourceContainers[i]); - if(!roomObj) sourceContainers.erase(sourceContainers.begin() + i); + if (!roomObj) + sourceContainers.erase(sourceContainers.begin() + i); } } diff --git a/douwco_hivemind/src/Structures/Spawn.cpp b/douwco_hivemind/src/Structures/Spawn.cpp index 672bccc..3745f6c 100644 --- a/douwco_hivemind/src/Structures/Spawn.cpp +++ b/douwco_hivemind/src/Structures/Spawn.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "Creeps/CreepBase.hpp" #include "Structures/Spawn.hpp" @@ -16,13 +17,10 @@ void DouwcoHivemind::Spawn::loop() { // Calculate needed creep roles int required_upgraders = 1; int required_suppliers = 2; - int required_maintainers = - spawn.room().find(Screeps::FIND_STRUCTURES).size() <= 2 ? 0 : 1; - ; + int required_maintainers = 1; int required_builders = - spawn.room().find(Screeps::FIND_MY_CONSTRUCTION_SITES).size() == 0 ? 0 - : 1; - int required_miners = 1; // spawn.room().memory()["sourceContainers"].size(); + 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; @@ -56,8 +54,8 @@ void DouwcoHivemind::Spawn::loop() { CreepRole role = CreepRole::UNEMPLOYED; if (required_miners > existing_miners) { role = CreepRole::MINER; - opts["memory"]["target_id"] = - spawn.room().memory()["sourceContainers"][0]; // make logic for more + opts["memory"]["sourceId"] = + spawn.room().memory()["sources"][0]; // make logic for more name = "Miner: "; } else if (required_suppliers > existing_suppliers) { role = CreepRole::SUPPLIER; @@ -78,21 +76,24 @@ void DouwcoHivemind::Spawn::loop() { // Build creep body std::vector 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"); } - } else if (role == SUPPLIER) { - body.push_back("move"); - body.push_back("work"); - body.push_back("carry"); - for (int i = 0; i < (energyAvailable - 200) / 100 && i * 50 < energyCapacityAvailable; i++) { + } + // 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"); } - } else { + } + // Worker body with balanced parts. + else { for (int i = 0; i < energyAvailable / 200; i++) { body.push_back("work"); body.push_back("carry");