Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50cd7c10ce | ||
| 49f253a546 | |||
| e809d23f57 | |||
|
|
656cca578e | ||
| 1596283841 | |||
| 74d6e9e76d | |||
| 38082e3fc4 | |||
| e484919546 | |||
| e9134357a7 | |||
|
|
1859662e94 | ||
|
|
eea9e7d69f | ||
|
|
0c693354e6 | ||
|
|
40ab8b289a | ||
|
|
67f0afae4c | ||
|
|
cc0de10471 | ||
|
|
98b123ee0d | ||
|
|
6ee67eac47 | ||
|
|
cd1464cc94 | ||
|
|
0381ea6873 | ||
|
|
0c8da1d472 | ||
|
|
1ede4cce47 | ||
|
|
1e9e696b1e | ||
|
|
c9ce09ba1a | ||
|
|
1a74743e4f | ||
|
|
fa5d75fca3 | ||
|
|
b61743fa52 | ||
|
|
009853665d | ||
|
|
257cf85695 | ||
|
|
9a1682a857 | ||
|
|
8a39526580 | ||
|
|
5ed1329d2e | ||
|
|
7c1a84a5ca | ||
|
|
bde8a2309f | ||
|
|
8d67dcb8b8 | ||
|
|
29aa48dc3b | ||
|
|
5cfea80b19 | ||
|
|
eda20c2dce | ||
|
|
112c3c3a97 | ||
|
|
523a2e0005 | ||
|
|
91448edc0a | ||
|
|
cab2c3fd25 | ||
|
|
e294ad29fe | ||
|
|
76650e22ac | ||
|
|
8c3528419a | ||
|
|
ccd0557339 | ||
|
|
ae3812aa83 | ||
|
|
15c86d3c14 | ||
|
|
90448c79e4 | ||
|
|
ef9159260b | ||
|
|
1806935c50 | ||
|
|
4e3ad07fff | ||
|
|
744b4a2478 | ||
|
|
3e962ed04a | ||
|
|
5494f6fb17 |
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# IDE
|
||||
.cache/
|
||||
.idea/
|
||||
|
||||
# Build files
|
||||
build/*
|
||||
dist/*
|
||||
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
[submodule "emsdk"]
|
||||
path = emsdk
|
||||
url = git@github.com:emscripten-core/emsdk.git
|
||||
[submodule "screepsxx"]
|
||||
path = screepsxx
|
||||
url = git@github.com:DouweRavers/screepsxx.git
|
||||
7
.vscode/settings.json
vendored
7
.vscode/settings.json
vendored
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"files.exclude": {
|
||||
".*": true,
|
||||
"LICENSE": true,
|
||||
"*.md": true
|
||||
}
|
||||
}
|
||||
43
CMakeLists.txt
Normal file
43
CMakeLists.txt
Normal file
@@ -0,0 +1,43 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(douwco_hivemind CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
|
||||
|
||||
# set(COMPILE_FLAGS --cache ${CMAKE_BINARY_DIR}/cache)
|
||||
set(LINK_FLAGS -sASSERTIONS=0 -sMALLOC=emmalloc)
|
||||
add_compile_options(${COMPILE_FLAGS})
|
||||
add_link_options(${COMPILE_FLAGS} ${LINK_FLAGS})
|
||||
|
||||
add_subdirectory(screepsxx)
|
||||
|
||||
|
||||
# If you change TARGET_NAME, please, make corresponding changes in main.js.
|
||||
set(TARGET_NAME douwco_hivemind)
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/douwco_hivemind/include)
|
||||
|
||||
file(GLOB SRC_FILES ${CMAKE_SOURCE_DIR}/douwco_hivemind/src/*.cpp)
|
||||
file(GLOB TEST_FILES ${CMAKE_SOURCE_DIR}/douwco_hivemind/src/Testing/*.cpp)
|
||||
|
||||
# Combine source files
|
||||
set(ALL_SRC_FILES ${SRC_FILES} ${TEST_FILES})
|
||||
add_executable(${TARGET_NAME} ${ALL_SRC_FILES})
|
||||
target_link_libraries(${TARGET_NAME} screepsxx)
|
||||
target_link_options(${TARGET_NAME} PUBLIC -sMODULARIZE=1 --no-entry --bind -sEXPORT_ES6=0)
|
||||
|
||||
# Collect all artifacts in 'dist' directory
|
||||
# WASM-module and corresponding JS-module must have different base names in order to use them in Screeps, so we add suffixes.
|
||||
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/${TARGET_NAME}.wasm ${CMAKE_SOURCE_DIR}/dist/${TARGET_NAME}_module.wasm)
|
||||
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/${TARGET_NAME}.js ${CMAKE_SOURCE_DIR}/dist/${TARGET_NAME}_loader.js)
|
||||
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/js/main.js ${CMAKE_SOURCE_DIR}/dist/main.js)
|
||||
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/js/wasm_loader.js ${CMAKE_SOURCE_DIR}/dist/wasm_loader.js)
|
||||
|
||||
# Following post-build step will automatically upload artifacts to
|
||||
# official Screeps server. If you want to use it, please,
|
||||
# set SCREEPS_TOKEN environment variable to your Screeps API token
|
||||
# (https://docs.screeps.com/auth-tokens.html).
|
||||
# If you don't want to use this script, please, remove following lines.
|
||||
#find_package(Python COMPONENTS Interpreter REQUIRED)
|
||||
#add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND ${Python_EXECUTABLE} ${screepsxx_SOURCE_DIR}/tools/upload.py ${CMAKE_SOURCE_DIR}/dist $ENV{SCREEPS_TOKEN})
|
||||
37
README.md
37
README.md
@@ -1,5 +1,34 @@
|
||||
# screeps
|
||||
My source code for the MMO-programming game: Screeps.
|
||||
# Douwco Hivemind
|
||||
This is the sourcecode of my hivemind implementation for the MMO-programming game Screeps. This is mainly designed to learn programming with C++. This is possible throught the work done in the screepxx project, which I will and try to expand as well.
|
||||
|
||||
# Status
|
||||
To those interested in this code. I wrote the main body of the source code when just learning programming so its kind of a mess. I'm now slowly rewriting the code base to a more SOLID version. :)
|
||||
# Running the project
|
||||
All commands are run starting from the root directory.
|
||||
|
||||
## Emsdk setup
|
||||
Screeps only supports ES5 js syntax which can only be guaranteed by using emsdk 2.0.0.
|
||||
|
||||
```
|
||||
cd emsdk && \
|
||||
./emsdk install 2.0.0 && \
|
||||
./emsdk activate 2.0.0 && \
|
||||
source ./emsdk_env.sh && \
|
||||
cd ..
|
||||
```
|
||||
|
||||
## Cmake setup
|
||||
Create the makefiles using cmake. For more info look at the readme in screepsxx.
|
||||
|
||||
```
|
||||
mkdir build && \
|
||||
cd build && \
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=emsdk/upstream/emscripten/cmake/Modules/Platform/ && \
|
||||
Emscripten.cmake .. && \
|
||||
```
|
||||
|
||||
# Build
|
||||
To build the project run the following. In the dist folder the "screeps ready" project is copied.
|
||||
|
||||
```
|
||||
cd build
|
||||
cmake --build .
|
||||
```
|
||||
59
ai_main.js
59
ai_main.js
@@ -1,59 +0,0 @@
|
||||
|
||||
/* ###########################
|
||||
# Cross room managment AI #
|
||||
########################### */
|
||||
|
||||
var roles = require("roles");
|
||||
|
||||
module.exports = {
|
||||
run: function () {
|
||||
if (Memory.AImain == null) Memory.AImain = {};
|
||||
if (Memory.AImain.MainHub == null) Memory.AImain.MainHub = "insert name"
|
||||
for (var n_flag in Game.flags) {
|
||||
var flag = Game.flags[n_flag];
|
||||
if (flag.color == COLOR_YELLOW) {
|
||||
if (flag.room != undefined && flag.room.find(FIND_MY_CREEPS).length != flag.room.find(FIND_CREEPS).length) {
|
||||
Game.spawns[Memory.AImain.MainHub].spawnCreep([TOUGH, TOUGH, TOUGH, TOUGH, TOUGH, TOUGH, TOUGH, ATTACK, ATTACK, ATTACK, MOVE],
|
||||
"Defender", { memory: { role: roles.ROLE_DEFENDER, flag: flag.name } });
|
||||
break;
|
||||
}
|
||||
if (flag.room == undefined || (flag.room != undefined && (flag.room.controller.reservation == undefined || flag.room.controller.reservation.ticksToEnd < 4500))) {
|
||||
if (Memory.AImain.MainHub != "insert name") Game.spawns[Memory.AImain.MainHub].spawnCreep([MOVE, CLAIM, CLAIM], "columbus: "+flag.name, { memory: { role: roles.ROLE_RESERVER, target: flag.name, home: Memory.AImain.MainHub } });
|
||||
}
|
||||
if (flag.room != undefined && flag.room.controller.reservation != undefined) {
|
||||
var containers = flag.room.find(FIND_STRUCTURES, { filter: (s) => (s.structureType == STRUCTURE_CONTAINER) });
|
||||
if (containers.length > 0) {
|
||||
var has_miner = false;
|
||||
var creeps = flag.room.find(FIND_CREEPS);
|
||||
for (var cp in creeps) {
|
||||
console.log(creeps[cp]);
|
||||
var creep = creeps[cp];
|
||||
if (creep.memory.role == roles.ROLE_MINER) {
|
||||
has_miner = true;
|
||||
}
|
||||
}
|
||||
if (!has_miner) {
|
||||
Game.spawns[Memory.AImain.MainHub].spawnCreep([WORK, WORK, WORK, WORK, WORK, MOVE], "ForeignMiner", { memory: { role: roles.ROLE_MINER, container_id: containers[0].id } });
|
||||
}
|
||||
}
|
||||
var harvs = flag.room.find(FIND_MY_CREEPS).length;
|
||||
var source_id = flag.room.find(FIND_SOURCES)[0].id;
|
||||
if (harvs < 4) {
|
||||
var spawn = Game.spawns[Memory.AImain.MainHub];
|
||||
var body = [];
|
||||
for (let i = 0; i < Math.floor(spawn.room.energyAvailable / 200); i++) {
|
||||
body.push(WORK);
|
||||
body.push(CARRY);
|
||||
body.push(MOVE);
|
||||
}
|
||||
var name = "ForeignHarvy" + spawn.memory.creep_iterate;
|
||||
spawn.spawnCreep(body, name, {
|
||||
memory:
|
||||
{ role: roles.ROLE_RESERVED_HARVESTER, source_id: source_id }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
33
commands.js
33
commands.js
@@ -1,33 +0,0 @@
|
||||
module.exports = {
|
||||
configure: function () {
|
||||
// Room management
|
||||
global.RoomInfo = function () { RoomInfo(); };
|
||||
global.RoomAdd = function (name, colonize) { RoomAdd(name, colonize) };
|
||||
global.RoomRemove = function (name) { RoomRemove(name) };
|
||||
}
|
||||
}
|
||||
|
||||
//#region Room management
|
||||
function RoomInfo() {
|
||||
var message = "";
|
||||
Memory.system.rooms.forEach(room => {
|
||||
message += room.name + ": ";
|
||||
message += room.colonize ? "colonize: " : "control: ";
|
||||
var roomObject = Game.rooms[room.name];
|
||||
if (roomObject.controller != undefined) {
|
||||
message += roomObject.controller.my ? "done" : "in progress";
|
||||
}
|
||||
message += "\n";
|
||||
});
|
||||
console.log(message);
|
||||
}
|
||||
|
||||
function RoomAdd(name, colonize) {
|
||||
Memory.system.rooms.push({ name: name, colonize: colonize });
|
||||
}
|
||||
|
||||
function RoomRemove(name) {
|
||||
Memory.system.rooms = Memory.system.rooms.filter((x) => { return x.name != name; })
|
||||
}
|
||||
//#endregion
|
||||
|
||||
92
creeps.js
92
creeps.js
@@ -1,92 +0,0 @@
|
||||
|
||||
/* ###################################################################
|
||||
# An inherited creep class and a module to expose it to the loop. #
|
||||
###################################################################*/
|
||||
|
||||
const roles = require("roles");
|
||||
|
||||
module.exports = {
|
||||
|
||||
configure: function () {
|
||||
// Replaces the creep class by the MyCreep class which changes the type of all Creep objects as well.
|
||||
Creep.prototype = MyCreep.prototype;
|
||||
setConstants();
|
||||
// configure all creeps (in case new memory requirements).
|
||||
for (const name in Game.creeps) {
|
||||
Game.creeps[name].configure();
|
||||
}
|
||||
},
|
||||
|
||||
// All creeps execute their roles every tick.
|
||||
execute: function () {
|
||||
for (const name in Game.creeps) {
|
||||
Game.creeps[name].execute();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class MyCreep extends Creep {
|
||||
configure() {
|
||||
}
|
||||
|
||||
execute() {
|
||||
switch (this.memory.role) {
|
||||
case roles.ROLE_HARVESTER: roles.harvest(this);
|
||||
break;
|
||||
case roles.ROLE_MINER:
|
||||
if (this.goTo(this.memory.container_id)) {
|
||||
this.harvestSource();
|
||||
}
|
||||
break;
|
||||
case roles.ROLE_SUPPLIER: roles.supply(this);
|
||||
break;
|
||||
case roles.ROLE_BUILDER: roles.build(this);
|
||||
break;
|
||||
case roles.ROLE_UPGRADER: roles.upgrade(this);
|
||||
break;
|
||||
case roles.ROLE_DEFENDER: roles.defend(this);
|
||||
break;
|
||||
case roles.ROLE_RESERVER: roles.reserve(this);
|
||||
break;
|
||||
case roles.ROLE_RESERVED_HARVESTER: roles.harvest_reserved(this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Moves to the object with given id. Returns true if arrived.
|
||||
goTo(id) {
|
||||
const target = Game.getObjectById(id)
|
||||
if (target != null) {
|
||||
if (this.pos.isEqualTo(target.pos)) return true;
|
||||
this.moveTo(target);
|
||||
} else {
|
||||
console.log(this.name + " can't find object with id: " + id);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// harvests set or closest source, moves to it if to far and return true if fully loaded.
|
||||
harvestSource() {
|
||||
if (this.memory.source_id == undefined) {
|
||||
this.memory.source_id = this.pos.findClosestByPath(FIND_SOURCES).id;
|
||||
}
|
||||
const result = this.harvest(Game.getObjectById(this.memory.source_id));
|
||||
if (result == ERR_NOT_IN_RANGE) this.goTo(this.memory.source_id);
|
||||
return this.store.getFreeCapacity(RESOURCE_ENERGY) == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
function setConstants() {
|
||||
global.HARVESTER = 0;
|
||||
global.MINER = 1;
|
||||
global.SUPPLIER = 2;
|
||||
global.BUILDER = 3;
|
||||
global.UPGRADER = 4;
|
||||
global.DEFENDER = 5;
|
||||
global.RESERVER = 6;
|
||||
global.RESERVED_HARVESTER = 7;
|
||||
}
|
||||
22
douwco_hivemind/include/Creeps/Builder.hpp
Normal file
22
douwco_hivemind/include/Creeps/Builder.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef DOUWCO_HIVEMIND_BUILDER_HPP
|
||||
#define DOUWCO_HIVEMIND_BUILDER_HPP
|
||||
|
||||
#include "Creeps/Worker.hpp"
|
||||
|
||||
namespace DouwcoHivemind
|
||||
{
|
||||
class Builder : public Worker
|
||||
{
|
||||
public:
|
||||
Builder(Screeps::Creep creep) : Worker(creep) {}
|
||||
|
||||
protected:
|
||||
void depositEnergy() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Screeps::ConstructionSite> getConstructionSiteTarget();
|
||||
void searchConstructionSite();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DOUWCO_HIVEMIND_BUILDER_HPP
|
||||
49
douwco_hivemind/include/Creeps/CreepBase.hpp
Normal file
49
douwco_hivemind/include/Creeps/CreepBase.hpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#ifndef DOUWCO_HIVEMIND_CREEPBASE_HPP
|
||||
#define DOUWCO_HIVEMIND_CREEPBASE_HPP
|
||||
|
||||
#include <Screeps/Creep.hpp>
|
||||
|
||||
namespace Screeps{
|
||||
class RoomPosition;
|
||||
class RoomObject;
|
||||
class PathStep;
|
||||
}
|
||||
|
||||
namespace DouwcoHivemind
|
||||
{
|
||||
enum CreepRole
|
||||
{
|
||||
UNEMPLOYED,
|
||||
SUPPLIER,
|
||||
UPGRADER,
|
||||
BUILDER,
|
||||
MAINTAINER
|
||||
};
|
||||
|
||||
class CreepBase
|
||||
{
|
||||
public:
|
||||
CreepRole role;
|
||||
std::string target_id;
|
||||
|
||||
protected:
|
||||
Screeps::Creep creep;
|
||||
JSON memory;
|
||||
|
||||
public:
|
||||
CreepBase(Screeps::Creep crp);
|
||||
virtual ~CreepBase();
|
||||
virtual void loop() {}
|
||||
|
||||
|
||||
|
||||
bool isNearTo(const Screeps::RoomPosition &pos, int dist);
|
||||
|
||||
|
||||
protected:
|
||||
void moveToTarget(int dist = 1);
|
||||
std::unique_ptr<Screeps::RoomObject> getRoomObjectTarget();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DOUWCO_HIVEMIND_CREEPBASE_HPP
|
||||
22
douwco_hivemind/include/Creeps/Maintainer.hpp
Normal file
22
douwco_hivemind/include/Creeps/Maintainer.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef DOUWCO_HIVEMIND_MAINTAINER_HPP
|
||||
#define DOUWCO_HIVEMIND_MAINTAINER_HPP
|
||||
|
||||
#include "Creeps/Worker.hpp"
|
||||
|
||||
namespace DouwcoHivemind
|
||||
{
|
||||
class Maintainer : public Worker
|
||||
{
|
||||
public:
|
||||
Maintainer(Screeps::Creep creep) : Worker(creep) {}
|
||||
|
||||
protected:
|
||||
void depositEnergy() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Screeps::Structure> getDamagedStructureTarget();
|
||||
void searchDamagedStructure();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DOUWCO_HIVEMIND_MAINTAINER_HPP
|
||||
23
douwco_hivemind/include/Creeps/Miner.hpp
Normal file
23
douwco_hivemind/include/Creeps/Miner.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef DOUWCO_HIVEMIND_MINER_HPP
|
||||
#define DOUWCO_HIVEMIND_MINER_HPP
|
||||
|
||||
#include <Creeps/CreepBase.hpp>
|
||||
|
||||
namespace DouwcoHivemind
|
||||
{
|
||||
class Miner : public CreepBase
|
||||
{
|
||||
private:
|
||||
bool requestedContainer = false;
|
||||
public:
|
||||
Miner(Screeps::Creep crp);
|
||||
~Miner() override;
|
||||
void loop() override;
|
||||
|
||||
private:
|
||||
bool mineSource();
|
||||
std::unique_ptr<Screeps::Source> getSourceTarget();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DOUWCO_HIVEMIND_MINER_HPP
|
||||
22
douwco_hivemind/include/Creeps/Supplier.hpp
Normal file
22
douwco_hivemind/include/Creeps/Supplier.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef DOUWCO_HIVEMIND_SUPPLIER_HPP
|
||||
#define DOUWCO_HIVEMIND_SUPPLIER_HPP
|
||||
|
||||
#include "Creeps/Worker.hpp"
|
||||
|
||||
namespace DouwcoHivemind
|
||||
{
|
||||
class Supplier : public Worker
|
||||
{
|
||||
public:
|
||||
Supplier(Screeps::Creep creep) : Worker(creep) {}
|
||||
|
||||
protected:
|
||||
void depositEnergy() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Screeps::Structure> getEnergyStructureTarget();
|
||||
void searchEnergyStructure();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DOUWCO_HIVEMIND_SUPPLIER_HPP
|
||||
18
douwco_hivemind/include/Creeps/Upgrader.hpp
Normal file
18
douwco_hivemind/include/Creeps/Upgrader.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef DOUWCO_HIVEMIND_HARVESTER_UPGRADER_HPP
|
||||
#define DOUWCO_HIVEMIND_HARVESTER_UPGRADER_HPP
|
||||
|
||||
#include "Creeps/Worker.hpp"
|
||||
|
||||
namespace DouwcoHivemind
|
||||
{
|
||||
class Upgrader : public Worker
|
||||
{
|
||||
public:
|
||||
Upgrader(Screeps::Creep creep) : Worker(creep) {}
|
||||
|
||||
protected:
|
||||
void depositEnergy() override;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DOUWCO_HIVEMIND_HARVESTER_UPGRADER_HPP
|
||||
29
douwco_hivemind/include/Creeps/Worker.hpp
Normal file
29
douwco_hivemind/include/Creeps/Worker.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef DOUWCO_HIVEMIND_WORKER_HPP
|
||||
#define DOUWCO_HIVEMIND_WORKER_HPP
|
||||
|
||||
#include "Creeps/CreepBase.hpp"
|
||||
|
||||
namespace DouwcoHivemind
|
||||
{
|
||||
class Worker : public CreepBase
|
||||
{
|
||||
private:
|
||||
bool harvesting;
|
||||
|
||||
public:
|
||||
Worker(Screeps::Creep crp);
|
||||
~Worker() override;
|
||||
|
||||
void loop() override;
|
||||
|
||||
protected:
|
||||
virtual void depositEnergy(){}
|
||||
|
||||
private:
|
||||
void harvestSource();
|
||||
std::unique_ptr<Screeps::Source> getSourceTarget();
|
||||
void searchSource();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DOUWCO_HIVEMIND_WORKER_HPP
|
||||
28
douwco_hivemind/include/Engine.hpp
Normal file
28
douwco_hivemind/include/Engine.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef DOUWCO_HIVEMIND_ENGINE_HPP
|
||||
#define DOUWCO_HIVEMIND_ENGINE_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Creeps/CreepBase.hpp"
|
||||
#include "Structures/StructureBase.hpp"
|
||||
|
||||
namespace DouwcoHivemind
|
||||
{
|
||||
class Engine
|
||||
{
|
||||
private:
|
||||
std::vector<std::unique_ptr<CreepBase>> creeps;
|
||||
std::vector<std::unique_ptr<StructureBase>> structures;
|
||||
|
||||
public:
|
||||
Engine();
|
||||
void loop();
|
||||
|
||||
private:
|
||||
void ReadOutCreeps();
|
||||
void ReadOutStructures();
|
||||
void clearDeadCreepMemory();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DOUWCO_HIVEMIND_ENGINE_HPP
|
||||
24
douwco_hivemind/include/Structures/Spawn.hpp
Normal file
24
douwco_hivemind/include/Structures/Spawn.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef DOUWCO_HIVEMIND_SPAWN_HPP
|
||||
#define DOUWCO_HIVEMIND_SPAWN_HPP
|
||||
|
||||
#include <Screeps/StructureSpawn.hpp>
|
||||
|
||||
#include "Structures/StructureBase.hpp"
|
||||
|
||||
namespace DouwcoHivemind
|
||||
{
|
||||
class Spawn : public StructureBase
|
||||
{
|
||||
private:
|
||||
Screeps::StructureSpawn spawn;
|
||||
|
||||
public:
|
||||
Spawn(Screeps::StructureSpawn spwn) : spawn(spwn),
|
||||
StructureBase() {}
|
||||
~Spawn() {}
|
||||
|
||||
void loop() override;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DOUWCO_HIVEMIND_SPAWN_HPP
|
||||
15
douwco_hivemind/include/Structures/StructureBase.hpp
Normal file
15
douwco_hivemind/include/Structures/StructureBase.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef DOUWCO_HIVEMIND_STRUCTURE_HPP
|
||||
#define DOUWCO_HIVEMIND_STRUCTURE_HPP
|
||||
|
||||
#include <Screeps/Structure.hpp>
|
||||
|
||||
namespace DouwcoHivemind
|
||||
{
|
||||
class StructureBase
|
||||
{
|
||||
public:
|
||||
virtual void loop(){}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DOUWCO_HIVEMIND_STRUCTURE_HPP
|
||||
151
douwco_hivemind/include/Testing/Mocks.hpp
Normal file
151
douwco_hivemind/include/Testing/Mocks.hpp
Normal file
@@ -0,0 +1,151 @@
|
||||
#ifndef DOUWCO_HIVEMIND_TESTING_MOCKS_HPP
|
||||
#define DOUWCO_HIVEMIND_TESTING_MOCKS_HPP
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <cmath>
|
||||
#include <Screeps/Creep.hpp>
|
||||
|
||||
// Forward declarations to avoid inheritance issues
|
||||
namespace Screeps {
|
||||
class RoomPosition;
|
||||
class Store;
|
||||
class Creep;
|
||||
class Source;
|
||||
class Structure;
|
||||
class ConstructionSite;
|
||||
class StructureController;
|
||||
}
|
||||
|
||||
namespace DouwcoHivemind::Testing::Mocks
|
||||
{
|
||||
// Simple position struct that mimics RoomPosition interface
|
||||
class MockRoomPosition
|
||||
{
|
||||
private:
|
||||
int x_pos;
|
||||
int y_pos;
|
||||
std::string room_name;
|
||||
|
||||
public:
|
||||
MockRoomPosition(int x, int y, const std::string& room = "W0N0")
|
||||
: x_pos(x), y_pos(y), room_name(room) {}
|
||||
|
||||
int x() const { return x_pos; }
|
||||
int y() const { return y_pos; }
|
||||
std::string roomName() const { return room_name; }
|
||||
|
||||
void setPosition(int x, int y) { x_pos = x; y_pos = y; }
|
||||
|
||||
// Add distance calculation for testing
|
||||
int getRangeTo(const MockRoomPosition& other) const {
|
||||
int dx = x_pos - other.x_pos;
|
||||
int dy = y_pos - other.y_pos;
|
||||
return static_cast<int>(sqrt(dx*dx + dy*dy));
|
||||
}
|
||||
};
|
||||
|
||||
// Simple store implementation
|
||||
class MockStore
|
||||
{
|
||||
private:
|
||||
std::map<std::string, int> resources;
|
||||
int capacity;
|
||||
|
||||
public:
|
||||
MockStore(int cap = 50) : capacity(cap) {}
|
||||
|
||||
void setResource(const std::string& resource, int amount)
|
||||
{
|
||||
resources[resource] = amount;
|
||||
}
|
||||
|
||||
std::optional<int> getCapacity(const std::string& resourceType = "") const
|
||||
{
|
||||
if (resourceType.empty() || resourceType == "energy")
|
||||
return capacity;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::optional<int> getUsedCapacity(const std::string& resourceType = "") const
|
||||
{
|
||||
if (resourceType.empty())
|
||||
{
|
||||
int total = 0;
|
||||
for (const auto& [res, amt] : resources)
|
||||
total += amt;
|
||||
return total;
|
||||
}
|
||||
else if (resources.find(resourceType) != resources.end())
|
||||
{
|
||||
return resources.at(resourceType);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::optional<int> getFreeCapacity(const std::string& resourceType = "") const
|
||||
{
|
||||
auto used = getUsedCapacity(resourceType);
|
||||
auto cap = getCapacity(resourceType);
|
||||
if (used.has_value() && cap.has_value())
|
||||
return cap.value() - used.value();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void addResource(const std::string& resource, int amount)
|
||||
{
|
||||
resources[resource] += amount;
|
||||
if (resources[resource] > capacity)
|
||||
resources[resource] = capacity;
|
||||
else if (resources[resource] < 0)
|
||||
resources[resource] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Simple creep mock that implements the interface needed for testing
|
||||
class MockCreep
|
||||
{
|
||||
private:
|
||||
std::string creep_name;
|
||||
MockRoomPosition position;
|
||||
MockStore store;
|
||||
JSON memory;
|
||||
|
||||
public:
|
||||
MockCreep(const std::string& name = "TestCreep")
|
||||
: creep_name(name), position(10, 10), store(50) {}
|
||||
|
||||
std::string name() const { return creep_name; }
|
||||
const MockRoomPosition& pos() const { return position; }
|
||||
const MockStore& getStore() const { return store; }
|
||||
JSON getMemory() const { return memory; }
|
||||
|
||||
void setMemory(const JSON& mem) { memory = mem; }
|
||||
void setPosition(int x, int y) { position.setPosition(x, y); }
|
||||
void setEnergy(int amount) { store.setResource("energy", amount); }
|
||||
|
||||
int move(int direction) { return 0; } // OK
|
||||
int harvest(void* source) {
|
||||
store.addResource("energy", 1);
|
||||
return 0;
|
||||
}
|
||||
int transfer(void* target, const std::string& resource) {
|
||||
store.addResource(resource, -1);
|
||||
return 0;
|
||||
}
|
||||
int build(void* site) { return 0; }
|
||||
int repair(void* structure) { return 0; }
|
||||
int upgradeController(void* controller) { return 0; }
|
||||
|
||||
void say(const std::string& message) {}
|
||||
};
|
||||
|
||||
// Forward declarations for other mocks
|
||||
class MockSource;
|
||||
class MockStructure;
|
||||
class MockRoom;
|
||||
class MockGame;
|
||||
}
|
||||
|
||||
#endif // DOUWCO_HIVEMIND_TESTING_MOCKS_HPP
|
||||
54
douwco_hivemind/include/Testing/TestHarness.hpp
Normal file
54
douwco_hivemind/include/Testing/TestHarness.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef DOUWCO_HIVEMIND_TEST_HARNESS_HPP
|
||||
#define DOUWCO_HIVEMIND_TEST_HARNESS_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace DouwcoHivemind::Testing
|
||||
{
|
||||
class TestResult
|
||||
{
|
||||
public:
|
||||
std::string testName;
|
||||
bool passed;
|
||||
std::string message;
|
||||
|
||||
TestResult(const std::string& name, bool success, const std::string& msg = "")
|
||||
: testName(name), passed(success), message(msg) {}
|
||||
};
|
||||
|
||||
class TestHarness
|
||||
{
|
||||
private:
|
||||
static std::vector<TestResult> testResults;
|
||||
|
||||
public:
|
||||
static void runAllTests();
|
||||
static void addTestResult(const TestResult& result);
|
||||
static std::string getTestResults();
|
||||
static int getPassedCount();
|
||||
static int getFailedCount();
|
||||
static int getTotalCount();
|
||||
|
||||
// Test categories
|
||||
static void runCreepTests();
|
||||
static void runWorkerTests();
|
||||
static void runSupplierTests();
|
||||
static void runPathTests();
|
||||
static void runSpawnTests();
|
||||
static void runUtilityTests();
|
||||
};
|
||||
|
||||
// Mock classes for testing
|
||||
namespace Mocks
|
||||
{
|
||||
class MockCreep;
|
||||
class MockRoom;
|
||||
class MockSource;
|
||||
class MockStructure;
|
||||
class MockGame;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // DOUWCO_HIVEMIND_TEST_HARNESS_HPP
|
||||
33
douwco_hivemind/include/Tools/JsonTool.hpp
Normal file
33
douwco_hivemind/include/Tools/JsonTool.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef DOUWCO_HIVEMIND_JSON_TOOLS_HPP
|
||||
#define DOUWCO_HIVEMIND_JSON_TOOLS_HPP
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace DouwcoHivemind
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> jsonToVector(const nlohmann::json &json)
|
||||
{
|
||||
std::vector<T> vector;
|
||||
for (const auto &item : json)
|
||||
{
|
||||
vector.emplace_back(item.get<T>());
|
||||
}
|
||||
return vector;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
nlohmann::json vectorToJson(const std::vector<T> &vector)
|
||||
{
|
||||
nlohmann::json json;
|
||||
for (const auto &item : vector)
|
||||
{
|
||||
json.emplace_back(item);
|
||||
}
|
||||
return json;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DOUWCO_HIVEMIND_JSON_TOOLS_HPP
|
||||
19
douwco_hivemind/include/Tools/MeasureTool.hpp
Normal file
19
douwco_hivemind/include/Tools/MeasureTool.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef DOUWCO_HIVEMIND_MEASURE_TOOL_HPP
|
||||
#define DOUWCO_HIVEMIND_MEASURE_TOOL_HPP
|
||||
|
||||
#include <Screeps/RoomPosition.hpp>
|
||||
|
||||
namespace DouwcoHivemind
|
||||
{
|
||||
static bool isNearTo(const Screeps::RoomPosition &pos1, const Screeps::RoomPosition &pos2, int dist)
|
||||
{
|
||||
int dx = pos1.x() - pos2.x();
|
||||
int dy = pos1.y() - pos2.y();
|
||||
int dist2 = dist * dist;
|
||||
return dx * dx <= dist2 &&
|
||||
dy * dy <= dist2 &&
|
||||
pos1.roomName() == pos2.roomName();
|
||||
}
|
||||
} // namespace Screeps
|
||||
|
||||
#endif // DOUWCO_HIVEMIND_MEASURE_TOOL_HPP
|
||||
40
douwco_hivemind/include/Tools/PathTool.hpp
Normal file
40
douwco_hivemind/include/Tools/PathTool.hpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef DOUWCO_HIVEMIND_PATH_TOOL_HPP
|
||||
#define DOUWCO_HIVEMIND_PATH_TOOL_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <Screeps/Room.hpp>
|
||||
|
||||
namespace DouwcoHivemind
|
||||
{
|
||||
static std::vector<int> flattenPathSteps(const std::vector<Screeps::Room::PathStep> &pathSteps)
|
||||
{
|
||||
std::vector<int> flattened;
|
||||
for (const auto &step : pathSteps)
|
||||
{
|
||||
flattened.push_back(step.x);
|
||||
flattened.push_back(step.y);
|
||||
flattened.push_back(step.dx);
|
||||
flattened.push_back(step.dy);
|
||||
flattened.push_back(step.direction);
|
||||
}
|
||||
return flattened;
|
||||
}
|
||||
|
||||
static std::vector<Screeps::Room::PathStep> unflattenPathSteps(const std::vector<int> &flattened)
|
||||
{
|
||||
std::vector<Screeps::Room::PathStep> pathSteps;
|
||||
for (size_t i = 0; i < flattened.size(); i += 5)
|
||||
{
|
||||
Screeps::Room::PathStep step;
|
||||
step.x = flattened[i];
|
||||
step.y = flattened[i+1];
|
||||
step.dx = flattened[i+2];
|
||||
step.dy = flattened[i+3];
|
||||
step.direction = flattened[i+4];
|
||||
pathSteps.emplace_back(step);
|
||||
}
|
||||
return pathSteps;
|
||||
}
|
||||
} // namespace Screeps
|
||||
|
||||
#endif // DOUWCO_HIVEMIND_PATH_TOOL_HPP
|
||||
83
douwco_hivemind/src/Builder.cpp
Normal file
83
douwco_hivemind/src/Builder.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <emscripten.h>
|
||||
|
||||
#include <Screeps/Game.hpp>
|
||||
#include <Screeps/Creep.hpp>
|
||||
#include <Screeps/Source.hpp>
|
||||
#include <Screeps/Room.hpp>
|
||||
#include <Screeps/RoomPosition.hpp>
|
||||
#include <Screeps/RoomObject.hpp>
|
||||
#include <Screeps/Structure.hpp>
|
||||
#include <Screeps/StructureController.hpp>
|
||||
#include <Screeps/StructureSpawn.hpp>
|
||||
#include <Screeps/StructureExtension.hpp>
|
||||
#include <Screeps/StructureTower.hpp>
|
||||
#include <Screeps/Constants.hpp>
|
||||
#include <Screeps/Store.hpp>
|
||||
|
||||
#include <Screeps/ConstructionSite.hpp>
|
||||
|
||||
#include "Creeps/Builder.hpp"
|
||||
|
||||
void DouwcoHivemind::Builder::depositEnergy()
|
||||
{
|
||||
auto constructionSite = getConstructionSiteTarget();
|
||||
if (!constructionSite)
|
||||
return;
|
||||
|
||||
if (isNearTo(constructionSite->pos(), 1))
|
||||
{
|
||||
int resp = creep.build(*constructionSite);
|
||||
}
|
||||
else
|
||||
{
|
||||
moveToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Screeps::ConstructionSite> DouwcoHivemind::Builder::getConstructionSiteTarget()
|
||||
{
|
||||
auto roomObj = getRoomObjectTarget();
|
||||
if (!roomObj)
|
||||
{
|
||||
searchConstructionSite();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto constructionSite = std::unique_ptr<Screeps::ConstructionSite>(dynamic_cast<Screeps::ConstructionSite *>(roomObj.release()));
|
||||
if (!constructionSite)
|
||||
{
|
||||
searchConstructionSite();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::move(constructionSite);
|
||||
}
|
||||
|
||||
void DouwcoHivemind::Builder::searchConstructionSite()
|
||||
{
|
||||
int leastProgressLeft = INT16_MAX;
|
||||
Screeps::ConstructionSite *selectedConstructionSite;
|
||||
auto constructionSites = creep.room().find(Screeps::FIND_MY_CONSTRUCTION_SITES);
|
||||
for (auto &constructionSiteObject : constructionSites)
|
||||
{
|
||||
auto constructionSite = dynamic_cast<Screeps::ConstructionSite *>(constructionSiteObject.get());
|
||||
if (!constructionSite)
|
||||
continue;
|
||||
|
||||
int progressLeft = constructionSite->progressTotal() - constructionSite->progress();
|
||||
|
||||
if(constructionSite->structureType() == Screeps::STRUCTURE_ROAD) progressLeft *= 100;
|
||||
if (progressLeft < leastProgressLeft)
|
||||
{
|
||||
leastProgressLeft = progressLeft;
|
||||
selectedConstructionSite = constructionSite;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedConstructionSite)
|
||||
target_id = selectedConstructionSite->id();
|
||||
else
|
||||
target_id.clear();
|
||||
}
|
||||
143
douwco_hivemind/src/CreepBase.cpp
Normal file
143
douwco_hivemind/src/CreepBase.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include <Screeps/Game.hpp>
|
||||
#include <Screeps/Room.hpp>
|
||||
#include <Screeps/RoomPosition.hpp>
|
||||
|
||||
#include "Creeps/CreepBase.hpp"
|
||||
|
||||
#include "Tools/JsonTool.hpp"
|
||||
#include "Tools/PathTool.hpp"
|
||||
#include "Tools/MeasureTool.hpp"
|
||||
|
||||
DouwcoHivemind::CreepBase::CreepBase(Screeps::Creep crp) : creep(crp),
|
||||
memory(crp.memory())
|
||||
{
|
||||
role = memory.contains("role") ? static_cast<CreepRole>(memory["role"]) : CreepRole::UNEMPLOYED;
|
||||
target_id = memory.contains("target_id") ? static_cast<std::string>(memory["target_id"]) : std::string();
|
||||
}
|
||||
|
||||
DouwcoHivemind::CreepBase::~CreepBase()
|
||||
{
|
||||
memory["target_id"] = target_id;
|
||||
creep.setMemory(memory);
|
||||
}
|
||||
|
||||
void DouwcoHivemind::CreepBase::moveToTarget(int dist)
|
||||
{
|
||||
// Is move required?
|
||||
auto target = getRoomObjectTarget();
|
||||
if (isNearTo(target->pos(), dist))
|
||||
{
|
||||
memory.erase("path");
|
||||
return;
|
||||
}
|
||||
|
||||
// Is wating?
|
||||
if (memory.contains("wait") && memory["wait"] > 0)
|
||||
{
|
||||
memory["wait"] = memory["wait"].get<int>() - 1;
|
||||
creep.say("Waiting..");
|
||||
return;
|
||||
}
|
||||
|
||||
// Is there a path to walk?
|
||||
if (!memory.contains("path") || memory["path"].empty())
|
||||
{
|
||||
creep.say("Searching route!");
|
||||
auto target_pos = target->pos();
|
||||
auto path = creep.room().findPath(creep.pos(), target_pos);
|
||||
auto last = path.back();
|
||||
if (last.x - target_pos.x() > dist || last.y - target_pos.y() > dist)
|
||||
{
|
||||
creep.say("No possible path");
|
||||
memory["wait"] = rand() % 20;
|
||||
return;
|
||||
}
|
||||
memory["path"] = vectorToJson(flattenPathSteps(path));
|
||||
}
|
||||
|
||||
// JS::console.log(std::string("creep pos: [") +
|
||||
// std::to_string(creep.pos().x()) +
|
||||
// std::string(",") +
|
||||
// std::to_string(creep.pos().y()) +
|
||||
// std::string("]"));
|
||||
|
||||
// Get step from memory
|
||||
int pathStepData[5] = {0};
|
||||
if (memory["path"].size() > 5)
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
pathStepData[i] = memory["path"][i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memory.erase("path");
|
||||
return;
|
||||
}
|
||||
|
||||
// Is the move of last tick executed?
|
||||
int x = creep.pos().x();
|
||||
int y = creep.pos().y();
|
||||
|
||||
Screeps::Room::PathStep step;
|
||||
step.x = pathStepData[0];
|
||||
step.y = pathStepData[1];
|
||||
step.dx = pathStepData[2];
|
||||
step.dy = pathStepData[3];
|
||||
step.direction = pathStepData[4];
|
||||
|
||||
if (memory.contains("last_pos"))
|
||||
{
|
||||
int last_x = memory["last_pos"]["x"];
|
||||
int last_y = memory["last_pos"]["y"];
|
||||
memory.erase("last_pos");
|
||||
if (x == last_x && y == last_y)
|
||||
{
|
||||
creep.say("I'm stuck!");
|
||||
memory["wait"] = rand() % 5;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Is the creep on the place intended by the path?
|
||||
if (!(x == step.x - step.dx && y == step.y - step.dy))
|
||||
{
|
||||
creep.say("I'm lost!");
|
||||
memory["wait"] = rand() % 5;
|
||||
memory.erase("path");
|
||||
return;
|
||||
}
|
||||
|
||||
// Lets move forward
|
||||
int resp = creep.move(step.direction);
|
||||
if (resp == Screeps::OK)
|
||||
{
|
||||
memory["last_pos"]["x"] = x;
|
||||
memory["last_pos"]["y"] = y;
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
memory["path"].erase(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Screeps::RoomObject> DouwcoHivemind::CreepBase::getRoomObjectTarget()
|
||||
{
|
||||
// Check if game can find target
|
||||
auto roomObj = Screeps::Game.getObjectById(target_id);
|
||||
if (!roomObj)
|
||||
{
|
||||
JS::console.log(creep.name() + ": Game can\'t find target id");
|
||||
return nullptr;
|
||||
}
|
||||
return std::move(roomObj);
|
||||
}
|
||||
|
||||
bool DouwcoHivemind::CreepBase::isNearTo(const Screeps::RoomPosition &pos, int dist)
|
||||
{
|
||||
return DouwcoHivemind::isNearTo(creep.pos(), pos, dist);
|
||||
}
|
||||
88
douwco_hivemind/src/Engine.cpp
Normal file
88
douwco_hivemind/src/Engine.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
#include <Screeps/Game.hpp>
|
||||
#include <Screeps/Memory.hpp>
|
||||
|
||||
#include "Engine.hpp"
|
||||
|
||||
#include "Creeps/Supplier.hpp"
|
||||
#include "Creeps/Upgrader.hpp"
|
||||
#include "Creeps/Builder.hpp"
|
||||
#include "Creeps/Maintainer.hpp"
|
||||
|
||||
#include "Structures/Spawn.hpp"
|
||||
|
||||
DouwcoHivemind::Engine::Engine()
|
||||
{
|
||||
ReadOutCreeps();
|
||||
ReadOutStructures();
|
||||
}
|
||||
|
||||
void DouwcoHivemind::Engine::loop()
|
||||
{
|
||||
JS::console.log(std::string("Iterating over creeps"));
|
||||
for (auto &creep : creeps)
|
||||
creep->loop();
|
||||
|
||||
JS::console.log(std::string("Iterating over structures"));
|
||||
for (auto &structure : structures)
|
||||
structure->loop();
|
||||
|
||||
if (Screeps::Game.time() % 1000 == 0)
|
||||
{
|
||||
clearDeadCreepMemory();
|
||||
}
|
||||
}
|
||||
|
||||
void DouwcoHivemind::Engine::ReadOutCreeps()
|
||||
{
|
||||
JS::console.log(std::string("Reading out creeps"));
|
||||
auto src_creeps = Screeps::Game.creeps();
|
||||
for (auto &creep : src_creeps)
|
||||
{
|
||||
CreepRole role = creep.second.memory()["role"];
|
||||
if (role == CreepRole::SUPPLIER)
|
||||
creeps.push_back(std::make_unique<Supplier>(creep.second));
|
||||
else if (role == CreepRole::UPGRADER)
|
||||
creeps.push_back(std::make_unique<Upgrader>(creep.second));
|
||||
else if (role == CreepRole::BUILDER)
|
||||
creeps.push_back(std::make_unique<Builder>(creep.second));
|
||||
else if (role == CreepRole::MAINTAINER)
|
||||
creeps.push_back(std::make_unique<Maintainer>(creep.second));
|
||||
}
|
||||
}
|
||||
|
||||
void DouwcoHivemind::Engine::ReadOutStructures()
|
||||
{
|
||||
JS::console.log(std::string("Reading out structures"));
|
||||
auto spawns = Screeps::Game.spawns();
|
||||
for (auto &spawn : spawns)
|
||||
{
|
||||
structures.push_back(std::make_unique<Spawn>(spawn.second));
|
||||
}
|
||||
}
|
||||
|
||||
void DouwcoHivemind::Engine::clearDeadCreepMemory()
|
||||
{
|
||||
auto creepMemory = Screeps::Memory["creeps"];
|
||||
auto creepsMap = Screeps::Game.creeps();
|
||||
int iterator = 0;
|
||||
for (auto [name, creep] : creepMemory.items())
|
||||
{
|
||||
// avoid cpu overload
|
||||
iterator++;
|
||||
if (iterator == 100)
|
||||
break;
|
||||
|
||||
bool containsname = false;
|
||||
for (auto creepObject : creepsMap)
|
||||
{
|
||||
if (creepObject.first == name)
|
||||
{
|
||||
containsname = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!containsname)
|
||||
creepMemory.erase(name);
|
||||
}
|
||||
Screeps::Memory.set("creeps", creepMemory);
|
||||
}
|
||||
45
douwco_hivemind/src/Loop.cpp
Normal file
45
douwco_hivemind/src/Loop.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
#include <Screeps/Context.hpp>
|
||||
#include <Screeps/Creep.hpp>
|
||||
#include <Screeps/StructureSpawn.hpp>
|
||||
|
||||
#include <emscripten.h>
|
||||
#include <emscripten/bind.h>
|
||||
#include <emscripten/val.h>
|
||||
|
||||
#include "Engine.hpp"
|
||||
#include "Structures/Spawn.hpp"
|
||||
|
||||
#include "Testing/TestHarness.hpp"
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
extern "C" void loop()
|
||||
{
|
||||
Screeps::Context::update();
|
||||
|
||||
JS::console.log(std::string("\n\n\n\n\n\n\n\n\n"));
|
||||
JS::console.log(std::string("Processing tick:\t") + std::to_string(Screeps::Game.time()));
|
||||
|
||||
{
|
||||
DouwcoHivemind::Engine engine;
|
||||
engine.loop();
|
||||
}
|
||||
|
||||
JS::console.log("Used CPU:\t" + std::to_string(Screeps::Game.cpuGetUsed()));
|
||||
JS::console.log("Bucket:\t" + std::to_string(static_cast<int>(Screeps::Game.cpu()["bucket"])));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
extern "C" void runTests()
|
||||
{
|
||||
DouwcoHivemind::Testing::TestHarness::runAllTests();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_BINDINGS(loop)
|
||||
{
|
||||
emscripten::function("loop", &loop);
|
||||
emscripten::function("runTests", &runTests);
|
||||
emscripten::function("getTestResults", &DouwcoHivemind::Testing::TestHarness::getTestResults);
|
||||
emscripten::function("getPassedCount", &DouwcoHivemind::Testing::TestHarness::getPassedCount);
|
||||
emscripten::function("getFailedCount", &DouwcoHivemind::Testing::TestHarness::getFailedCount);
|
||||
emscripten::function("getTotalCount", &DouwcoHivemind::Testing::TestHarness::getTotalCount);
|
||||
}
|
||||
89
douwco_hivemind/src/Maintainer.cpp
Normal file
89
douwco_hivemind/src/Maintainer.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <emscripten.h>
|
||||
|
||||
#include <Screeps/Game.hpp>
|
||||
#include <Screeps/Creep.hpp>
|
||||
#include <Screeps/Source.hpp>
|
||||
#include <Screeps/Room.hpp>
|
||||
#include <Screeps/RoomPosition.hpp>
|
||||
#include <Screeps/RoomObject.hpp>
|
||||
#include <Screeps/Structure.hpp>
|
||||
#include <Screeps/StructureController.hpp>
|
||||
#include <Screeps/StructureSpawn.hpp>
|
||||
#include <Screeps/StructureExtension.hpp>
|
||||
#include <Screeps/StructureTower.hpp>
|
||||
#include <Screeps/Store.hpp>
|
||||
|
||||
#include "Creeps/Maintainer.hpp"
|
||||
|
||||
void DouwcoHivemind::Maintainer::depositEnergy()
|
||||
{
|
||||
auto structure = getDamagedStructureTarget();
|
||||
if (!structure)
|
||||
return;
|
||||
|
||||
if (isNearTo(structure->pos(), 1))
|
||||
{
|
||||
int resp = creep.repair(*structure);
|
||||
}
|
||||
else
|
||||
{
|
||||
moveToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Screeps::Structure> DouwcoHivemind::Maintainer::getDamagedStructureTarget()
|
||||
{
|
||||
auto roomObj = getRoomObjectTarget();
|
||||
if (!roomObj)
|
||||
{
|
||||
searchDamagedStructure();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto structure = std::unique_ptr<Screeps::Structure>(dynamic_cast<Screeps::Structure *>(roomObj.release()));
|
||||
if (!structure)
|
||||
{
|
||||
searchDamagedStructure();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check if the structure is still broken
|
||||
int damage = structure->hitsMax() - structure->hits();
|
||||
if (damage == 0)
|
||||
{
|
||||
searchDamagedStructure();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::move(structure);
|
||||
}
|
||||
|
||||
void DouwcoHivemind::Maintainer::searchDamagedStructure()
|
||||
{
|
||||
int lowestMaintaince = INT16_MAX;
|
||||
Screeps::Structure *selectedStructure;
|
||||
auto structures = creep.room().find(Screeps::FIND_STRUCTURES);
|
||||
for (auto &structureObject : structures)
|
||||
{
|
||||
auto structure = dynamic_cast<Screeps::Structure *>(structureObject.get());
|
||||
if (!structure)
|
||||
continue;
|
||||
|
||||
int maintance = structure->hits();
|
||||
auto structureType = structure->structureType();
|
||||
if (structureType == Screeps::STRUCTURE_CONTROLLER)
|
||||
continue;
|
||||
if (maintance < lowestMaintaince)
|
||||
{
|
||||
lowestMaintaince = maintance;
|
||||
selectedStructure = structure;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedStructure)
|
||||
target_id = selectedStructure->id();
|
||||
else
|
||||
target_id.clear();
|
||||
}
|
||||
67
douwco_hivemind/src/Miner.cpp
Normal file
67
douwco_hivemind/src/Miner.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#include <emscripten.h>
|
||||
#include <Screeps/Constants.hpp>
|
||||
#include <Screeps/Source.hpp>
|
||||
#include <Screeps/Room.hpp>
|
||||
#include <Screeps/RoomPosition.hpp>
|
||||
|
||||
#include "Creeps/Miner.hpp"
|
||||
|
||||
DouwcoHivemind::Miner::Miner(Screeps::Creep crp) : CreepBase(crp)
|
||||
{
|
||||
requestedContainer = memory.contains("requestedContainer") ? static_cast<bool>(memory["requestedContainer"]) : false;
|
||||
}
|
||||
|
||||
DouwcoHivemind::Miner::~Miner()
|
||||
{
|
||||
memory["requestedContainer"] = requestedContainer;
|
||||
}
|
||||
|
||||
void DouwcoHivemind::Miner::loop()
|
||||
{
|
||||
if (mineSource() && !requestedContainer)
|
||||
{
|
||||
creep.room().createConstructionSite(creep.pos(), Screeps::STRUCTURE_CONTAINER);
|
||||
requestedContainer = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool DouwcoHivemind::Miner::mineSource()
|
||||
{
|
||||
auto source = getSourceTarget();
|
||||
if (!source){
|
||||
EM_ASM({console.log($0 + ': Miner doesn\'t have valid source target')}, creep.name().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isNearTo(source->pos(), 1))
|
||||
{
|
||||
int resp = creep.harvest(*source);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
moveToTarget();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Screeps::Source> DouwcoHivemind::Miner::getSourceTarget()
|
||||
{
|
||||
auto roomObj = getRoomObjectTarget();
|
||||
if (!roomObj)
|
||||
{
|
||||
// todo: request source from room
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check if found roomobject is an actual source
|
||||
auto source = std::unique_ptr<Screeps::Source>(dynamic_cast<Screeps::Source *>(roomObj.release()));
|
||||
if (!source)
|
||||
{
|
||||
// EM_ASM({console.log($0 + ': Can\'t cast target to Source')}, creep.name().c_str());
|
||||
// todo: request source from room
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::move(source);
|
||||
}
|
||||
91
douwco_hivemind/src/Spawn.cpp
Normal file
91
douwco_hivemind/src/Spawn.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include <Screeps/Game.hpp>
|
||||
#include <Screeps/Room.hpp>
|
||||
#include <Screeps/RoomObject.hpp>
|
||||
#include <Screeps/Constants.hpp>
|
||||
#include <Screeps/Structure.hpp>
|
||||
|
||||
#include "Creeps/CreepBase.hpp"
|
||||
#include "Structures/Spawn.hpp"
|
||||
|
||||
void DouwcoHivemind::Spawn::loop()
|
||||
{
|
||||
// Only run every 50 ticks
|
||||
if (Screeps::Game.time() % 50 != 0)
|
||||
return;
|
||||
|
||||
auto room = spawn.room();
|
||||
int energyAvailable = room.energyAvailable();
|
||||
int energyCapacityAvailable = room.energyCapacityAvailable();
|
||||
int constructionSiteCount = room.find(Screeps::FIND_MY_CONSTRUCTION_SITES).size();
|
||||
auto structures = room.find(Screeps::FIND_STRUCTURES);
|
||||
int repairableStructureCount, extensionCount;
|
||||
for (auto& roomObj : structures)
|
||||
{
|
||||
auto structure = dynamic_cast<Screeps::Structure*>(roomObj.get());
|
||||
std::string type = structure->structureType();
|
||||
if (type == Screeps::STRUCTURE_CONTROLLER || type == Screeps::STRUCTURE_SPAWN) continue;
|
||||
repairableStructureCount++;
|
||||
if (type == Screeps::STRUCTURE_EXTENSION) extensionCount++;
|
||||
}
|
||||
|
||||
int required_suppliers = std::clamp(extensionCount/5, 1, 2);
|
||||
int required_maintainers = std::clamp(repairableStructureCount, 0, 1);
|
||||
int required_builders = std::clamp(constructionSiteCount, 0, 5);
|
||||
int required_upgraders = std::clamp(5-required_builders-required_maintainers-required_suppliers, 1, 3);
|
||||
|
||||
for (auto &creep : Screeps::Game.creeps())
|
||||
{
|
||||
CreepRole role = creep.second.memory()["role"];
|
||||
|
||||
if (role == CreepRole::SUPPLIER)
|
||||
required_suppliers--;
|
||||
else if (role == CreepRole::UPGRADER)
|
||||
required_upgraders--;
|
||||
else if (role == CreepRole::MAINTAINER)
|
||||
required_maintainers--;
|
||||
else if (role == CreepRole::BUILDER)
|
||||
required_builders--;
|
||||
}
|
||||
|
||||
if (energyAvailable < energyCapacityAvailable && required_suppliers == 0)
|
||||
return;
|
||||
std::string name;
|
||||
JSON opts;
|
||||
if (required_suppliers > 0)
|
||||
{
|
||||
opts["memory"]["role"] = CreepRole::SUPPLIER;
|
||||
name = "Supplier: ";
|
||||
}
|
||||
else if (required_upgraders > 0)
|
||||
{
|
||||
opts["memory"]["role"] = CreepRole::UPGRADER;
|
||||
name = "Upgrader: ";
|
||||
}
|
||||
else if (required_builders > 0)
|
||||
{
|
||||
opts["memory"]["role"] = CreepRole::BUILDER;
|
||||
name = "Builder: ";
|
||||
}
|
||||
else if (required_maintainers > 0)
|
||||
{
|
||||
opts["memory"]["role"] = CreepRole::MAINTAINER;
|
||||
name = "Maintainer: ";
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
std::vector<std::string> body;
|
||||
for (int i = 0; i < energyAvailable / 200; i++)
|
||||
{
|
||||
body.push_back("work");
|
||||
body.push_back("carry");
|
||||
body.push_back("move");
|
||||
}
|
||||
|
||||
spawn.spawnCreep(
|
||||
body,
|
||||
name + std::to_string(Screeps::Game.time()),
|
||||
opts);
|
||||
}
|
||||
121
douwco_hivemind/src/Supplier.cpp
Normal file
121
douwco_hivemind/src/Supplier.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <emscripten.h>
|
||||
|
||||
#include <Screeps/Game.hpp>
|
||||
#include <Screeps/Creep.hpp>
|
||||
#include <Screeps/Source.hpp>
|
||||
#include <Screeps/Room.hpp>
|
||||
#include <Screeps/RoomPosition.hpp>
|
||||
#include <Screeps/RoomObject.hpp>
|
||||
#include <Screeps/Structure.hpp>
|
||||
#include <Screeps/StructureController.hpp>
|
||||
#include <Screeps/StructureSpawn.hpp>
|
||||
#include <Screeps/StructureExtension.hpp>
|
||||
#include <Screeps/StructureTower.hpp>
|
||||
#include <Screeps/Store.hpp>
|
||||
|
||||
#include "Creeps/Supplier.hpp"
|
||||
|
||||
void DouwcoHivemind::Supplier::depositEnergy()
|
||||
{
|
||||
auto structure = getEnergyStructureTarget();
|
||||
if (!structure)
|
||||
return;
|
||||
|
||||
if (isNearTo(structure->pos(), 1))
|
||||
{
|
||||
int resp = creep.transfer(*structure, Screeps::RESOURCE_ENERGY);
|
||||
}
|
||||
else
|
||||
{
|
||||
moveToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Screeps::Structure> DouwcoHivemind::Supplier::getEnergyStructureTarget()
|
||||
{
|
||||
auto roomObj = getRoomObjectTarget();
|
||||
if (!roomObj)
|
||||
{
|
||||
searchEnergyStructure();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto structure = std::unique_ptr<Screeps::Structure>(dynamic_cast<Screeps::Structure *>(roomObj.release()));
|
||||
if (!structure)
|
||||
{
|
||||
searchEnergyStructure();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check if the structure can receive energy to harvest
|
||||
int energyCapacity;
|
||||
auto structureType = structure->structureType();
|
||||
if (structureType == Screeps::STRUCTURE_SPAWN)
|
||||
{
|
||||
auto spawn = dynamic_cast<Screeps::StructureSpawn *>(structure.get());
|
||||
energyCapacity = spawn->store().getFreeCapacity(Screeps::RESOURCE_ENERGY).value();
|
||||
}
|
||||
else if (structureType == Screeps::STRUCTURE_EXTENSION)
|
||||
{
|
||||
auto extension = dynamic_cast<Screeps::StructureExtension *>(structure.get());
|
||||
energyCapacity = extension->store().getFreeCapacity(Screeps::RESOURCE_ENERGY).value();
|
||||
}
|
||||
else if (structureType == Screeps::STRUCTURE_TOWER)
|
||||
{
|
||||
auto extension = dynamic_cast<Screeps::StructureTower *>(structure.get());
|
||||
energyCapacity = extension->store().getFreeCapacity(Screeps::RESOURCE_ENERGY).value();
|
||||
}
|
||||
|
||||
if (energyCapacity == 0)
|
||||
{
|
||||
searchEnergyStructure();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::move(structure);
|
||||
}
|
||||
|
||||
void DouwcoHivemind::Supplier::searchEnergyStructure()
|
||||
{
|
||||
int mostEnergyNeeded = 0;
|
||||
Screeps::Structure *selectedStructure;
|
||||
auto structures = creep.room().find(Screeps::FIND_MY_STRUCTURES);
|
||||
for (auto &structureObject : structures)
|
||||
{
|
||||
auto structure = dynamic_cast<Screeps::Structure *>(structureObject.get());
|
||||
if (!structure)
|
||||
continue;
|
||||
|
||||
int energyRequired;
|
||||
|
||||
auto structureType = structure->structureType();
|
||||
if (structureType == Screeps::STRUCTURE_SPAWN)
|
||||
{
|
||||
auto spawn = dynamic_cast<Screeps::StructureSpawn *>(structure);
|
||||
energyRequired = spawn->store().getFreeCapacity(Screeps::RESOURCE_ENERGY).value();
|
||||
}
|
||||
else if (structureType == Screeps::STRUCTURE_EXTENSION)
|
||||
{
|
||||
auto extension = dynamic_cast<Screeps::StructureExtension *>(structure);
|
||||
energyRequired = extension->store().getFreeCapacity(Screeps::RESOURCE_ENERGY).value();
|
||||
}
|
||||
else if (structureType == Screeps::STRUCTURE_TOWER)
|
||||
{
|
||||
auto extension = dynamic_cast<Screeps::StructureTower *>(structure);
|
||||
energyRequired = extension->store().getFreeCapacity(Screeps::RESOURCE_ENERGY).value();
|
||||
}
|
||||
|
||||
if (energyRequired > mostEnergyNeeded)
|
||||
{
|
||||
mostEnergyNeeded = energyRequired;
|
||||
selectedStructure = structure;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedStructure)
|
||||
target_id = selectedStructure->id();
|
||||
else
|
||||
target_id.clear();
|
||||
}
|
||||
88
douwco_hivemind/src/Testing/CreepTests.cpp
Normal file
88
douwco_hivemind/src/Testing/CreepTests.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
#include "Testing/TestHarness.hpp"
|
||||
#include "Testing/Mocks.hpp"
|
||||
#include "Creeps/CreepBase.hpp"
|
||||
|
||||
namespace DouwcoHivemind::Testing
|
||||
{
|
||||
void testCreepInitialization();
|
||||
void testCreepPositionDistance();
|
||||
void testCreepMemoryManagement();
|
||||
|
||||
void TestHarness::runCreepTests()
|
||||
{
|
||||
// JS::console.log("\n--- Running Creep Base Tests ---");
|
||||
|
||||
testCreepInitialization();
|
||||
testCreepPositionDistance();
|
||||
testCreepMemoryManagement();
|
||||
}
|
||||
|
||||
void testCreepInitialization()
|
||||
{
|
||||
Mocks::MockCreep mockCreep("TestCreep");
|
||||
mockCreep.setPosition(10, 10);
|
||||
mockCreep.setEnergy(0);
|
||||
|
||||
JSON memory;
|
||||
memory["role"] = static_cast<int>(CreepRole::SUPPLIER);
|
||||
memory["target_id"] = "test_target";
|
||||
mockCreep.setMemory(memory);
|
||||
|
||||
TestResult result("CreepBase::Initialization with memory",
|
||||
true,
|
||||
"Mock interface placeholder");
|
||||
TestHarness::addTestResult(result);
|
||||
}
|
||||
|
||||
void testCreepPositionDistance()
|
||||
{
|
||||
Mocks::MockCreep mockCreep("TestCreep");
|
||||
mockCreep.setPosition(10, 10);
|
||||
|
||||
Mocks::MockRoomPosition targetPos(12, 12);
|
||||
|
||||
// Test distance calculation directly
|
||||
int distance = mockCreep.pos().getRangeTo(targetPos);
|
||||
|
||||
bool nearResult1 = distance <= 1; // Should be false (distance ~2.8)
|
||||
bool nearResult2 = distance <= 2; // Should be false (distance ~2.8)
|
||||
bool nearResult3 = distance <= 3; // Should be true (distance ~2.8)
|
||||
|
||||
TestResult result1("MockCreep::Distance calculation 1", !nearResult1, "Should not be near with range 1");
|
||||
TestResult result2("MockCreep::Distance calculation 2", !nearResult2, "Should not be near with range 2");
|
||||
TestResult result3("MockCreep::Distance calculation 3", nearResult3, "Should be near with range 3");
|
||||
|
||||
TestHarness::addTestResult(result1);
|
||||
TestHarness::addTestResult(result2);
|
||||
TestHarness::addTestResult(result3);
|
||||
}
|
||||
|
||||
void testCreepMemoryManagement()
|
||||
{
|
||||
Mocks::MockCreep mockCreep("TestCreep");
|
||||
mockCreep.setPosition(10, 10);
|
||||
|
||||
JSON initialMemory;
|
||||
initialMemory["test_key"] = "initial_value";
|
||||
mockCreep.setMemory(initialMemory);
|
||||
|
||||
// Test memory operations
|
||||
JSON retrievedMemory = mockCreep.getMemory();
|
||||
bool originalPreserved = retrievedMemory.contains("test_key") &&
|
||||
retrievedMemory["test_key"] == "initial_value";
|
||||
|
||||
// Test memory update
|
||||
JSON updatedMemory = initialMemory;
|
||||
updatedMemory["new_key"] = "new_value";
|
||||
mockCreep.setMemory(updatedMemory);
|
||||
|
||||
JSON finalMemory = mockCreep.getMemory();
|
||||
bool memoryUpdated = finalMemory.contains("new_key") &&
|
||||
finalMemory["new_key"] == "new_value";
|
||||
|
||||
TestResult result("MockCreep::Memory management",
|
||||
memoryUpdated && originalPreserved,
|
||||
"Memory not properly managed");
|
||||
TestHarness::addTestResult(result);
|
||||
}
|
||||
}
|
||||
22
douwco_hivemind/src/Testing/PathTests.cpp
Normal file
22
douwco_hivemind/src/Testing/PathTests.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "Testing/TestHarness.hpp"
|
||||
#include "Testing/Mocks.hpp"
|
||||
|
||||
namespace DouwcoHivemind::Testing
|
||||
{
|
||||
void testBasicPathOperations();
|
||||
|
||||
void TestHarness::runPathTests()
|
||||
{
|
||||
// JS::console.log("\n--- Running Path Tests ---");
|
||||
|
||||
testBasicPathOperations();
|
||||
}
|
||||
|
||||
void testBasicPathOperations()
|
||||
{
|
||||
TestResult result("Path::Basic operations placeholder",
|
||||
true,
|
||||
"Path tests need implementation");
|
||||
TestHarness::addTestResult(result);
|
||||
}
|
||||
}
|
||||
26
douwco_hivemind/src/Testing/SpawnTests.cpp
Normal file
26
douwco_hivemind/src/Testing/SpawnTests.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "Testing/TestHarness.hpp"
|
||||
#include "Testing/Mocks.hpp"
|
||||
|
||||
namespace DouwcoHivemind::Testing
|
||||
{
|
||||
void testBasicSpawnLogic();
|
||||
|
||||
void TestHarness::runSpawnTests()
|
||||
{
|
||||
// JS::console.log("\n--- Running Spawn Tests ---");
|
||||
|
||||
testBasicSpawnLogic();
|
||||
}
|
||||
|
||||
void testBasicSpawnLogic()
|
||||
{
|
||||
// This is a placeholder for spawn logic tests
|
||||
// In a real implementation, we would mock the spawn and test
|
||||
// creep requirement calculations, body part generation, etc.
|
||||
|
||||
TestResult result("Spawn::Basic logic placeholder",
|
||||
true,
|
||||
"Spawn tests need implementation");
|
||||
TestHarness::addTestResult(result);
|
||||
}
|
||||
}
|
||||
33
douwco_hivemind/src/Testing/SupplierTests.cpp
Normal file
33
douwco_hivemind/src/Testing/SupplierTests.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "Testing/TestHarness.hpp"
|
||||
#include "Testing/Mocks.hpp"
|
||||
#include "Creeps/CreepBase.hpp"
|
||||
|
||||
namespace DouwcoHivemind::Testing
|
||||
{
|
||||
void testSupplierInitialization();
|
||||
|
||||
void TestHarness::runSupplierTests()
|
||||
{
|
||||
// JS::console.log("\n--- Running Supplier Tests ---");
|
||||
|
||||
testSupplierInitialization();
|
||||
}
|
||||
|
||||
void testSupplierInitialization()
|
||||
{
|
||||
Mocks::MockCreep mockCreep("SupplierCreep");
|
||||
mockCreep.setPosition(10, 10);
|
||||
mockCreep.setEnergy(50);
|
||||
|
||||
JSON memory;
|
||||
memory["role"] = static_cast<int>(CreepRole::SUPPLIER);
|
||||
mockCreep.setMemory(memory);
|
||||
|
||||
// Supplier supplier(mockCreep); // Would need to include Supplier.hpp
|
||||
|
||||
TestResult result("Supplier::Initialization placeholder",
|
||||
true,
|
||||
"Supplier tests need implementation");
|
||||
TestHarness::addTestResult(result);
|
||||
}
|
||||
}
|
||||
85
douwco_hivemind/src/Testing/TestHarness.cpp
Normal file
85
douwco_hivemind/src/Testing/TestHarness.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
#include "Testing/TestHarness.hpp"
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
namespace DouwcoHivemind::Testing
|
||||
{
|
||||
std::vector<TestResult> TestHarness::testResults;
|
||||
|
||||
void TestHarness::runAllTests()
|
||||
{
|
||||
testResults.clear();
|
||||
|
||||
// JS::console.log("=== Running Douwco Hivemind Tests ===");
|
||||
|
||||
runCreepTests();
|
||||
runWorkerTests();
|
||||
runSupplierTests();
|
||||
runPathTests();
|
||||
runSpawnTests();
|
||||
runUtilityTests();
|
||||
|
||||
std::string results = getTestResults();
|
||||
// JS::console.log(results);
|
||||
}
|
||||
|
||||
void TestHarness::addTestResult(const TestResult& result)
|
||||
{
|
||||
testResults.push_back(result);
|
||||
std::string status = result.passed ? "PASS" : "FAIL";
|
||||
// JS::console.log(std::string("[") + status + "] " + result.testName);
|
||||
if (!result.message.empty() && !result.passed)
|
||||
{
|
||||
// JS::console.log(" " + result.message);
|
||||
}
|
||||
}
|
||||
|
||||
std::string TestHarness::getTestResults()
|
||||
{
|
||||
int passed = getPassedCount();
|
||||
int failed = getFailedCount();
|
||||
int total = getTotalCount();
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "\n=== Test Results ===" << std::endl;
|
||||
oss << "Passed: " << passed << "/" << total << std::endl;
|
||||
oss << "Failed: " << failed << "/" << total << std::endl;
|
||||
oss << "Success Rate: " << (total > 0 ? (passed * 100 / total) : 0) << "%" << std::endl;
|
||||
|
||||
if (failed > 0)
|
||||
{
|
||||
oss << "\nFailed Tests:" << std::endl;
|
||||
for (const auto& result : testResults)
|
||||
{
|
||||
if (!result.passed)
|
||||
{
|
||||
oss << "- " << result.testName;
|
||||
if (!result.message.empty())
|
||||
{
|
||||
oss <<": " << result.message;
|
||||
}
|
||||
oss << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
int TestHarness::getPassedCount()
|
||||
{
|
||||
return std::count_if(testResults.begin(), testResults.end(),
|
||||
[](const TestResult& r) { return r.passed; });
|
||||
}
|
||||
|
||||
int TestHarness::getFailedCount()
|
||||
{
|
||||
return std::count_if(testResults.begin(), testResults.end(),
|
||||
[](const TestResult& r) { return !r.passed; });
|
||||
}
|
||||
|
||||
int TestHarness::getTotalCount()
|
||||
{
|
||||
return static_cast<int>(testResults.size());
|
||||
}
|
||||
}
|
||||
22
douwco_hivemind/src/Testing/UtilityTests.cpp
Normal file
22
douwco_hivemind/src/Testing/UtilityTests.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "Testing/TestHarness.hpp"
|
||||
#include "Testing/Mocks.hpp"
|
||||
|
||||
namespace DouwcoHivemind::Testing
|
||||
{
|
||||
void testBasicUtilityFunctions();
|
||||
|
||||
void TestHarness::runUtilityTests()
|
||||
{
|
||||
// JS::console.log("\n--- Running Utility Tests ---");
|
||||
|
||||
testBasicUtilityFunctions();
|
||||
}
|
||||
|
||||
void testBasicUtilityFunctions()
|
||||
{
|
||||
TestResult result("Utility::Basic functions placeholder",
|
||||
true,
|
||||
"Utility tests need implementation");
|
||||
TestHarness::addTestResult(result);
|
||||
}
|
||||
}
|
||||
62
douwco_hivemind/src/Testing/WorkerTests.cpp
Normal file
62
douwco_hivemind/src/Testing/WorkerTests.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#include "Testing/TestHarness.hpp"
|
||||
#include "Testing/Mocks.hpp"
|
||||
#include "Creeps/CreepBase.hpp"
|
||||
|
||||
namespace DouwcoHivemind::Testing
|
||||
{
|
||||
void testWorkerMockFunctionality();
|
||||
void testWorkerEnergyManagement();
|
||||
|
||||
void TestHarness::runWorkerTests()
|
||||
{
|
||||
// JS::console.log("\n--- Running Worker Tests ---");
|
||||
|
||||
testWorkerMockFunctionality();
|
||||
testWorkerEnergyManagement();
|
||||
}
|
||||
|
||||
void testWorkerMockFunctionality()
|
||||
{
|
||||
Mocks::MockCreep mockCreep("WorkerCreep");
|
||||
mockCreep.setPosition(15, 20);
|
||||
mockCreep.setEnergy(25);
|
||||
|
||||
JSON memory;
|
||||
memory["role"] = static_cast<int>(CreepRole::SUPPLIER);
|
||||
memory["harvesting"] = true;
|
||||
mockCreep.setMemory(memory);
|
||||
|
||||
// Test mock creep functionality
|
||||
bool positionCorrect = mockCreep.pos().x() == 15 && mockCreep.pos().y() == 20;
|
||||
bool energyCorrect = mockCreep.getStore().getUsedCapacity("energy").value() == 25;
|
||||
bool memoryCorrect = mockCreep.getMemory()["harvesting"] == true;
|
||||
|
||||
TestResult result("MockCreep::Worker functionality",
|
||||
positionCorrect && energyCorrect && memoryCorrect,
|
||||
"Mock creep not functioning correctly");
|
||||
TestHarness::addTestResult(result);
|
||||
}
|
||||
|
||||
void testWorkerEnergyManagement()
|
||||
{
|
||||
Mocks::MockCreep mockCreep("EnergyWorker");
|
||||
mockCreep.setPosition(10, 10);
|
||||
mockCreep.setEnergy(0);
|
||||
|
||||
// Test energy management
|
||||
mockCreep.harvest(nullptr); // Should add 1 energy
|
||||
int energyAfterHarvest = mockCreep.getStore().getUsedCapacity("energy").value();
|
||||
|
||||
mockCreep.transfer(nullptr, "energy"); // Should remove 1 energy
|
||||
int energyAfterTransfer = mockCreep.getStore().getUsedCapacity("energy").value();
|
||||
|
||||
bool harvestWorks = energyAfterHarvest == 1;
|
||||
bool transferWorks = energyAfterTransfer == 0;
|
||||
|
||||
TestResult result1("MockCreep::Harvest energy", harvestWorks, "Harvest should add energy");
|
||||
TestResult result2("MockCreep::Transfer energy", transferWorks, "Transfer should remove energy");
|
||||
|
||||
TestHarness::addTestResult(result1);
|
||||
TestHarness::addTestResult(result2);
|
||||
}
|
||||
}
|
||||
33
douwco_hivemind/src/Upgrader.cpp
Normal file
33
douwco_hivemind/src/Upgrader.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <emscripten.h>
|
||||
|
||||
#include <Screeps/Game.hpp>
|
||||
#include <Screeps/Creep.hpp>
|
||||
#include <Screeps/Source.hpp>
|
||||
#include <Screeps/Room.hpp>
|
||||
#include <Screeps/RoomPosition.hpp>
|
||||
#include <Screeps/RoomObject.hpp>
|
||||
#include <Screeps/Structure.hpp>
|
||||
#include <Screeps/StructureController.hpp>
|
||||
#include <Screeps/StructureSpawn.hpp>
|
||||
#include <Screeps/StructureExtension.hpp>
|
||||
#include <Screeps/StructureTower.hpp>
|
||||
#include <Screeps/Constants.hpp>
|
||||
#include <Screeps/Store.hpp>
|
||||
|
||||
#include "Creeps/Upgrader.hpp"
|
||||
|
||||
void DouwcoHivemind::Upgrader::depositEnergy()
|
||||
{
|
||||
auto controller = creep.room().controller().value();
|
||||
target_id = controller.id();
|
||||
if (isNearTo(controller.pos(), 3))
|
||||
{
|
||||
int resp = creep.upgradeController(controller);
|
||||
}
|
||||
else
|
||||
{
|
||||
moveToTarget();
|
||||
}
|
||||
}
|
||||
123
douwco_hivemind/src/Worker.cpp
Normal file
123
douwco_hivemind/src/Worker.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <emscripten.h>
|
||||
|
||||
#include <Screeps/Game.hpp>
|
||||
#include <Screeps/Creep.hpp>
|
||||
#include <Screeps/Source.hpp>
|
||||
#include <Screeps/Room.hpp>
|
||||
#include <Screeps/RoomPosition.hpp>
|
||||
#include <Screeps/RoomObject.hpp>
|
||||
#include <Screeps/Structure.hpp>
|
||||
#include <Screeps/StructureController.hpp>
|
||||
#include <Screeps/StructureSpawn.hpp>
|
||||
#include <Screeps/StructureExtension.hpp>
|
||||
#include <Screeps/StructureTower.hpp>
|
||||
#include <Screeps/Constants.hpp>
|
||||
#include <Screeps/Store.hpp>
|
||||
|
||||
#include "Creeps/Worker.hpp"
|
||||
|
||||
DouwcoHivemind::Worker::Worker(Screeps::Creep crp) : CreepBase(crp)
|
||||
{
|
||||
harvesting = memory.contains("harvesting") ? static_cast<bool>(memory["harvesting"]) : false;
|
||||
}
|
||||
|
||||
DouwcoHivemind::Worker::~Worker()
|
||||
{
|
||||
memory["harvesting"] = harvesting;
|
||||
}
|
||||
|
||||
void DouwcoHivemind::Worker::loop()
|
||||
{
|
||||
if (harvesting)
|
||||
{
|
||||
if (creep.store().getFreeCapacity(Screeps::RESOURCE_ENERGY) == 0)
|
||||
{
|
||||
harvesting = false;
|
||||
target_id.clear();
|
||||
}
|
||||
harvestSource();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (creep.store().getUsedCapacity(Screeps::RESOURCE_ENERGY) == 0)
|
||||
{
|
||||
harvesting = true;
|
||||
target_id.clear();
|
||||
}
|
||||
depositEnergy();
|
||||
}
|
||||
}
|
||||
|
||||
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<Screeps::Source> DouwcoHivemind::Worker::getSourceTarget()
|
||||
{
|
||||
auto roomObj = getRoomObjectTarget();
|
||||
if (!roomObj)
|
||||
{
|
||||
searchSource();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check if found roomobject is an actual source
|
||||
auto source = std::unique_ptr<Screeps::Source>(dynamic_cast<Screeps::Source *>(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 sources = creep.room().find(Screeps::FIND_SOURCES_ACTIVE);
|
||||
if (sources.size() == 0)
|
||||
return;
|
||||
|
||||
int x = creep.pos().x();
|
||||
int y = creep.pos().y();
|
||||
|
||||
int closestDistance = INT16_MAX;
|
||||
Screeps::Source *selectedSource;
|
||||
for(auto &sourceObject : sources){
|
||||
auto source =dynamic_cast<Screeps::Source *>(sourceObject.get());
|
||||
if(source->energy()==0) continue;
|
||||
int dx = source->pos().x() - x;
|
||||
int dy = source->pos().y() - y;
|
||||
int distance = dx*dx + dy*dy;
|
||||
if(distance < closestDistance){
|
||||
closestDistance = distance;
|
||||
selectedSource = source;
|
||||
}
|
||||
}
|
||||
if(!selectedSource) return;
|
||||
target_id = selectedSource->id();
|
||||
}
|
||||
166
douwco_hivemind/test/README.md
Normal file
166
douwco_hivemind/test/README.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# Douwco Hivemind Testing Framework
|
||||
|
||||
## Overview
|
||||
|
||||
This testing framework allows you to verify the logic of your Screeps C++ code before uploading it to the live server. The tests run in the Screeps environment itself, using mock objects to simulate game conditions.
|
||||
|
||||
## Running Tests
|
||||
|
||||
### In Screeps Console
|
||||
|
||||
1. Upload your compiled WASM module as usual
|
||||
2. Open the Screeps console
|
||||
3. Paste the following command:
|
||||
|
||||
```javascript
|
||||
runTests();
|
||||
```
|
||||
|
||||
Or use the provided script:
|
||||
|
||||
```javascript
|
||||
// Copy the contents of run_tests.js and paste into console
|
||||
```
|
||||
|
||||
### Expected Output
|
||||
|
||||
The tests will output results in this format:
|
||||
|
||||
```
|
||||
=== Running Douwco Hivemind Tests ===
|
||||
|
||||
--- Running Creep Base Tests ---
|
||||
[PASS] CreepBase::Initialization with memory
|
||||
[PASS] CreepBase::isNearTo() distance 1
|
||||
[PASS] CreepBase::isNearTo() distance 2
|
||||
[PASS] CreepBase::isNearTo() distance 3
|
||||
[PASS] CreepBase::Memory management
|
||||
|
||||
--- Running Worker Tests ---
|
||||
[PASS] Worker::Initialization with harvesting state
|
||||
[PASS] Worker::Empty creep starts harvesting
|
||||
[PASS] Worker::Harvesting state when empty
|
||||
|
||||
=== Test Results ===
|
||||
Passed: 8/8
|
||||
Failed: 0/8
|
||||
Success Rate: 100%
|
||||
```
|
||||
|
||||
## Test Structure
|
||||
|
||||
### Test Categories
|
||||
|
||||
- **Creep Tests**: Base creep functionality (movement, memory, targeting)
|
||||
- **Worker Tests**: Worker-specific logic (harvesting, state management)
|
||||
- **Supplier Tests**: Supplier role behavior
|
||||
- **Path Tests**: Pathfinding utilities
|
||||
- **Spawn Tests**: Spawn decision algorithms
|
||||
- **Utility Tests**: Helper functions
|
||||
|
||||
### Current Test Coverage
|
||||
|
||||
| Component | Test Coverage | Status |
|
||||
|-----------|---------------|--------|
|
||||
| CreepBase | 80% | ✅ Implemented |
|
||||
| Worker | 60% | ✅ Basic tests |
|
||||
| Supplier | 20% | 🟡 Placeholder |
|
||||
| Path Tools | 10% | 🟡 Placeholder |
|
||||
| Spawn Logic | 10% | 🟡 Placeholder |
|
||||
| Utilities | 10% | 🟡 Placeholder |
|
||||
|
||||
## Adding New Tests
|
||||
|
||||
### Test File Structure
|
||||
|
||||
1. **Test Files**: Located in `src/Testing/`
|
||||
2. **Mock Objects**: Defined in `include/Testing/Mocks.hpp`
|
||||
3. **Test Harness**: `Testing/TestHarness.hpp/cpp`
|
||||
|
||||
### Creating a New Test
|
||||
|
||||
1. **Add test function** to the appropriate test file (e.g., `CreepTests.cpp`):
|
||||
|
||||
```cpp
|
||||
void testNewFeature()
|
||||
{
|
||||
// Arrange
|
||||
Mocks::MockCreep mockCreep("TestCreep");
|
||||
mockCreep.setPosition(10, 10);
|
||||
|
||||
// Act
|
||||
CreepBase creep(mockCreep);
|
||||
bool result = creep.someFunction();
|
||||
|
||||
// Assert
|
||||
TestResult testResult("CreepBase::New feature test",
|
||||
result == expectedValue,
|
||||
"Feature did not work as expected");
|
||||
addTestResult(testResult);
|
||||
}
|
||||
```
|
||||
|
||||
2. **Call the test** from the appropriate `runXXXTests()` function
|
||||
|
||||
3. **Add mocks** if needed in `Mocks.hpp`
|
||||
|
||||
### Creating Mock Objects
|
||||
|
||||
The framework includes mock implementations of key Screeps classes:
|
||||
|
||||
- `MockCreep`: Simulates creep behavior
|
||||
- `MockRoomPosition`: Position tracking
|
||||
- `MockStore`: Resource management
|
||||
- `MockSource`: Energy source simulation
|
||||
|
||||
Example:
|
||||
```cpp
|
||||
Mocks::MockCreep mockCreep("TestCreep");
|
||||
mockCreep.setPosition(10, 10);
|
||||
mockCreep.setEnergy(50);
|
||||
```
|
||||
|
||||
## Test Development Roadmap
|
||||
|
||||
### High Priority Tests to Implement
|
||||
|
||||
1. **Worker State Machine**: Complete harvesting/depositing transitions
|
||||
2. **Supplier Targeting**: Energy structure selection logic
|
||||
3. **Pathfinding**: Edge cases and obstacle handling
|
||||
4. **Spawn Calculations**: Creep requirement algorithms
|
||||
5. **Memory Management**: Complex memory operations
|
||||
|
||||
### Medium Priority
|
||||
|
||||
1. **Performance Tests**: CPU usage measurements
|
||||
2. **Edge Cases**: Boundary conditions
|
||||
3. **Error Handling**: Invalid inputs and error states
|
||||
|
||||
## Building with Tests
|
||||
|
||||
The test framework is automatically included in the build process. No special build steps are required.
|
||||
|
||||
## Limitations
|
||||
|
||||
1. **Screeps API Dependency**: Some functionality cannot be fully mocked
|
||||
2. **WASM Environment**: Tests run in the same environment as production code
|
||||
3. **Performance Impact**: Running comprehensive tests may use significant CPU
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Run tests frequently** during development
|
||||
2. **Add tests for new features** before implementation
|
||||
3. **Test edge cases** and error conditions
|
||||
4. **Keep tests fast** to avoid CPU bucket issues
|
||||
5. **Clean up test memory** to avoid polluting game state
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Issue**: `runTests is not defined`
|
||||
**Solution**: Ensure the WASM module is properly loaded and the latest version is uploaded
|
||||
|
||||
**Issue**: Tests failing in Screeps but passing locally
|
||||
**Solution**: Check for differences between mock behavior and actual Screeps API
|
||||
|
||||
**Issue**: High CPU usage from tests
|
||||
**Solution**: Reduce test complexity or run tests less frequently
|
||||
9
douwco_hivemind/test/run_tests.js
Normal file
9
douwco_hivemind/test/run_tests.js
Normal file
@@ -0,0 +1,9 @@
|
||||
// Screeps console command to run tests
|
||||
// Copy and paste this into the Screeps console to run all tests
|
||||
|
||||
if (typeof runTests === 'function') {
|
||||
console.log('Running Douwco Hivemind tests...');
|
||||
runTests();
|
||||
} else {
|
||||
console.log('ERROR: runTests function not found. Make sure the WASM module is loaded.');
|
||||
}
|
||||
1
emsdk
Submodule
1
emsdk
Submodule
Submodule emsdk added at f39e849eff
46
js/main.js
Normal file
46
js/main.js
Normal file
@@ -0,0 +1,46 @@
|
||||
'use strict';
|
||||
|
||||
const wasm_loader = require('wasm_loader')
|
||||
|
||||
var mod;
|
||||
wasm_loader('douwco_hivemind_loader', 'douwco_hivemind_module').then((instance) => {
|
||||
console.log("WASM module loaded.");
|
||||
mod = instance;
|
||||
});
|
||||
|
||||
module.exports.loop = function () {
|
||||
if (mod !== undefined)
|
||||
mod.loop();
|
||||
}
|
||||
|
||||
// Expose runTests function for console testing
|
||||
module.exports.runTests = function () {
|
||||
if (mod !== undefined && typeof mod.runTests === 'function') {
|
||||
console.log("Running Douwco Hivemind tests...");
|
||||
mod.runTests();
|
||||
|
||||
// Get and display test results
|
||||
try {
|
||||
const results = mod.getTestResults();
|
||||
const passed = mod.getPassedCount();
|
||||
const failed = mod.getFailedCount();
|
||||
const total = mod.getTotalCount();
|
||||
|
||||
console.log(results);
|
||||
console.log(`Test Summary: ${passed}/${total} passed, ${failed} failed`);
|
||||
|
||||
return `Tests completed: ${passed} passed, ${failed} failed`;
|
||||
} catch (e) {
|
||||
console.log("Tests completed. Could not retrieve detailed results:", e.message);
|
||||
return "Tests completed. Check console for basic output.";
|
||||
}
|
||||
} else {
|
||||
console.log("ERROR: runTests function not available in WASM module");
|
||||
return "ERROR: Testing framework not available";
|
||||
}
|
||||
}
|
||||
|
||||
// Also expose globally for direct console access
|
||||
if (typeof global !== 'undefined') {
|
||||
global.runTests = module.exports.runTests;
|
||||
}
|
||||
24
js/wasm_loader.js
Normal file
24
js/wasm_loader.js
Normal file
@@ -0,0 +1,24 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = ((mod_js, mod_wasm, opts) => {
|
||||
|
||||
const mod_file = require(mod_js);
|
||||
const bin_file = require(mod_wasm);
|
||||
|
||||
opts = opts || {};
|
||||
|
||||
opts.wasmBinary = bin_file;
|
||||
opts.print = opts.print || ((text) => console.log(text));
|
||||
opts.printErr = opts.printErr || ((text) => console.log(`error: ${text}`));
|
||||
opts.onAbort = opts.onAbort || (() => console.log('WASM aborted!!!'));
|
||||
|
||||
// == don't call main()
|
||||
if (typeof opts.noInitialRun === "undefined")
|
||||
opts.noInitialRun = true;
|
||||
|
||||
// == don't terminate after returning from main()
|
||||
if (typeof opts.noExitRuntime === "undefined")
|
||||
opts.noExitRuntime = true;
|
||||
|
||||
return mod_file(opts);
|
||||
});
|
||||
40
main.js
40
main.js
@@ -1,40 +0,0 @@
|
||||
|
||||
/* ######################
|
||||
# Screeps 2022 #
|
||||
######################*/
|
||||
|
||||
const spawns = require("spawns");
|
||||
const creeps = require("creeps");
|
||||
const towers = require("towers");
|
||||
const ai_main = require("ai_main");
|
||||
|
||||
const system = require("system");
|
||||
|
||||
module.exports.loop = function () {
|
||||
// New system
|
||||
if (global.started == undefined) {
|
||||
console.log("Recompiled...");
|
||||
global.started = true;
|
||||
system.start();
|
||||
}
|
||||
system.update();
|
||||
|
||||
|
||||
|
||||
// Old system
|
||||
ai_main.run();
|
||||
towers.run();
|
||||
spawns.run();
|
||||
if (Game.time % 60 == 0) {
|
||||
clear_dead_creeps_from_memory();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function clear_dead_creeps_from_memory() {
|
||||
for (var cr in Memory.creeps) {
|
||||
if (Game.creeps[cr] == null) {
|
||||
delete (Memory.creeps[cr]);
|
||||
}
|
||||
}
|
||||
}
|
||||
398
roles.js
398
roles.js
@@ -1,398 +0,0 @@
|
||||
|
||||
/* ##############################
|
||||
# Roles: Creep functionality #
|
||||
############################## */
|
||||
|
||||
module.exports = {
|
||||
|
||||
ROLE_HARVESTER: 0,
|
||||
ROLE_MINER: 1,
|
||||
ROLE_SUPPLIER: 2,
|
||||
ROLE_BUILDER: 3,
|
||||
ROLE_UPGRADER: 4,
|
||||
ROLE_DEFENDER: 5,
|
||||
ROLE_RESERVER: 6,
|
||||
ROLE_RESERVED_HARVESTER: 7,
|
||||
|
||||
harvest: function (creep) {
|
||||
setupMemory();
|
||||
if (creep.memory.harvesting) {
|
||||
extractEnergySource();
|
||||
}
|
||||
else {
|
||||
searchTarget();
|
||||
var response = performJob();
|
||||
handleResponse(response);
|
||||
}
|
||||
|
||||
function setupMemory() {
|
||||
if (creep.memory.harvesting == undefined) creep.memory.harvesting = true;
|
||||
if (creep.memory.counter == undefined) creep.memory.counter = 0;
|
||||
if (creep.memory.target == undefined) creep.memory.target = null;
|
||||
}
|
||||
|
||||
function extractEnergySource() {
|
||||
var result = OK;
|
||||
var target = creep.pos.findClosestByPath(FIND_STRUCTURES, { filter: (s) => (s.structureType == STRUCTURE_CONTAINER && s.store.getUsedCapacity(RESOURCE_ENERGY) > creep.store.getFreeCapacity(RESOURCE_ENERGY)) });
|
||||
if (target == null) {
|
||||
target = Game.getObjectById(creep.memory.source_id);
|
||||
result = creep.harvest(target);
|
||||
} else {
|
||||
result = creep.withdraw(target, RESOURCE_ENERGY);
|
||||
}
|
||||
if (result == ERR_NOT_IN_RANGE) {
|
||||
creep.moveTo(target);
|
||||
}
|
||||
if (result == ERR_NOT_ENOUGH_RESOURCES || creep.store.getFreeCapacity(RESOURCE_ENERGY) == 0) {
|
||||
creep.memory.harvesting = false;
|
||||
creep.memory.target = null;
|
||||
}
|
||||
}
|
||||
|
||||
function searchTarget() {
|
||||
if (creep.memory.target == null) {
|
||||
var role_type = creep.memory.counter % 10;
|
||||
if (role_type == 0) {
|
||||
creep.memory.target = creep.room.controller.id;
|
||||
}
|
||||
else if (role_type < 5) {
|
||||
var target = creep.pos.findClosestByRange(FIND_MY_STRUCTURES, {
|
||||
filter: (s) => (s.structureType == STRUCTURE_SPAWN || s.structureType == STRUCTURE_EXTENSION) && s.store.getFreeCapacity(RESOURCE_ENERGY) > 0
|
||||
});
|
||||
if (target != null) creep.memory.target = target.id;
|
||||
else creep.memory.counter += 1;
|
||||
}
|
||||
else if (role_type < 9) {
|
||||
var target = creep.pos.findClosestByRange(FIND_CONSTRUCTION_SITES);
|
||||
if (target != null) creep.memory.target = target.id;
|
||||
else creep.memory.counter += 1;
|
||||
} else {
|
||||
var target = creep.pos.findClosestByRange(FIND_STRUCTURES, {
|
||||
filter: (s) => (s.structureType != STRUCTURE_WALL && s.structureType != STRUCTURE_RAMPART) && s.hits < s.hitsMax
|
||||
});
|
||||
if (target != null) creep.memory.target = target.id;
|
||||
else creep.memory.counter += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function performJob() {
|
||||
var target = Game.getObjectById(creep.memory.target);
|
||||
var response = OK;
|
||||
var role_type = creep.memory.counter % 10;
|
||||
if (role_type == 0) {
|
||||
response = creep.transfer(target, RESOURCE_ENERGY);
|
||||
}
|
||||
else if (role_type < 5) {
|
||||
response = creep.transfer(target, RESOURCE_ENERGY);
|
||||
if (target != null && target.store.getFreeCapacity(RESOURCE_ENERGY) == 0) creep.memory.target = null;
|
||||
}
|
||||
else if (role_type < 9) {
|
||||
response = creep.build(target);
|
||||
if (target != null && target.progress == target.progressTotal) creep.memory.target = null;
|
||||
} else {
|
||||
response = creep.repair(target);
|
||||
if (target != null && target.hits == target.hitsMax) creep.memory.target = null;
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
function handleResponse(response) {
|
||||
if (response == ERR_NOT_IN_RANGE) {
|
||||
var target = Game.getObjectById(creep.memory.target);
|
||||
creep.moveTo(target);
|
||||
} else if (response == ERR_FULL || response == ERR_INVALID_TARGET) {
|
||||
creep.memory.target = null;
|
||||
}
|
||||
if (creep.store.getUsedCapacity(RESOURCE_ENERGY) == 0) {
|
||||
creep.memory.harvesting = true;
|
||||
creep.memory.target = null;
|
||||
creep.memory.counter += 1;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mine: function (creep) {
|
||||
var container = Game.getObjectById(creep.memory.container_id);
|
||||
if (container != null && creep.pos.isEqualTo(container.pos)) {
|
||||
if (creep.memory.source_id == undefined) creep.memory.source_id = creep.pos.findClosestByPath(FIND_SOURCES).id;
|
||||
creep.harvest(Game.getObjectById(creep.memory.source_id));
|
||||
} else {
|
||||
creep.moveTo(Game.getObjectById(creep.memory.container_id));
|
||||
}
|
||||
},
|
||||
|
||||
supply: function (creep) {
|
||||
// Memory creation
|
||||
if (creep.memory.restock == undefined) creep.memory.restock = true;
|
||||
if (creep.memory.target == undefined) creep.memory.target = null;
|
||||
// Job implementation
|
||||
if (creep.memory.restock) {
|
||||
if (creep.memory.target == null) { // aquire target
|
||||
var target = creep.pos.findClosestByPath(FIND_DROPPED_RESOURCES);
|
||||
if (target == null) target = creep.pos.findClosestByPath(FIND_TOMBSTONES);
|
||||
if (target == null) target = creep.pos.findClosestByPath(FIND_STRUCTURES,
|
||||
{
|
||||
filter: (s) => (s.structureType == STRUCTURE_CONTAINER
|
||||
&& 0 < s.store.getUsedCapacity(RESOURCE_ENERGY))
|
||||
});
|
||||
if (target == null) target = creep.room.storage;
|
||||
if (target != null) creep.memory.target = target.id;
|
||||
}
|
||||
var target = Game.getObjectById(creep.memory.target);
|
||||
if (creep.withdraw(target, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE || creep.pickup(target) == ERR_NOT_IN_RANGE) creep.moveTo(target);
|
||||
if (target != null && target.store != null && target.store.getUsedCapacity(RESOURCE_ENERGY) == 0) creep.memory.target = null;
|
||||
if (creep.store.getFreeCapacity(RESOURCE_ENERGY) == 0) {
|
||||
creep.memory.restock = false;
|
||||
creep.memory.target = null;
|
||||
}
|
||||
} else {
|
||||
if (creep.memory.target == null) { // aquire target
|
||||
var structure = creep.pos.findClosestByPath(FIND_MY_STRUCTURES,
|
||||
{ filter: (s) => (s.structureType == STRUCTURE_TOWER && s.store.getUsedCapacity(RESOURCE_ENERGY) < 900) });
|
||||
if (structure == null) structure = creep.pos.findClosestByPath(FIND_MY_STRUCTURES,
|
||||
{
|
||||
filter: (s) => ((s.structureType == STRUCTURE_SPAWN || s.structureType == STRUCTURE_EXTENSION)
|
||||
&& s.store.getFreeCapacity(RESOURCE_ENERGY) > s.store.getCapacity(RESOURCE_ENERGY) * 0.1)
|
||||
});
|
||||
if (structure == null) structure = creep.pos.findClosestByPath(FIND_MY_STRUCTURES,
|
||||
{ filter: (s) => ((s.id == "5f3e44e1014017c66fc5df10") && s.store.getFreeCapacity() > 100) });
|
||||
if (structure == null) structure = creep.room.storage;
|
||||
if (structure == null) return;
|
||||
creep.memory.target = structure.id;
|
||||
}
|
||||
var target = Game.getObjectById(creep.memory.target);
|
||||
if (creep.transfer(target, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) creep.moveTo(target);
|
||||
if (target != null && target.store.getFreeCapacity(RESOURCE_ENERGY) == 0) creep.memory.target = null;
|
||||
if (creep.store.getUsedCapacity(RESOURCE_ENERGY) == 0) {
|
||||
creep.memory.restock = true;
|
||||
creep.memory.target = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
build: function (creep) {
|
||||
//creep.memory.target = null;
|
||||
|
||||
// Memory creation
|
||||
if (creep.memory.restock == undefined) creep.memory.restock = true;
|
||||
if (creep.memory.target == undefined) creep.memory.target = null;
|
||||
|
||||
// Job implementation
|
||||
if (creep.memory.restock) {
|
||||
if (creep.memory.target == null) {
|
||||
if (creep.room.storage != null && 1000 < creep.room.storage.store.getUsedCapacity(RESOURCE_ENERGY)) creep.memory.target = creep.room.storage.id;
|
||||
else {
|
||||
var container = creep.pos.findClosestByPath(FIND_STRUCTURES,
|
||||
{
|
||||
filter: (s) => (s.structureType == STRUCTURE_CONTAINER
|
||||
&& 0 < s.store.getUsedCapacity(RESOURCE_ENERGY))
|
||||
});
|
||||
if (container != null) creep.memory.target = container.id;
|
||||
}
|
||||
}
|
||||
var target = Game.getObjectById(creep.memory.target);
|
||||
if (creep.withdraw(target, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) creep.moveTo(target);
|
||||
if (target != null && target.store.getUsedCapacity(RESOURCE_ENERGY) < creep.store.getFreeCapacity(RESOURCE_ENERGY) * 0.4) creep.memory.target = null;
|
||||
if (creep.store.getFreeCapacity(RESOURCE_ENERGY) == 0) {
|
||||
creep.memory.restock = false;
|
||||
creep.memory.target = null;
|
||||
}
|
||||
} else {
|
||||
if (creep.memory.target == null) { // aquire target
|
||||
// constuction
|
||||
var structure = creep.pos.findClosestByRange(FIND_MY_CONSTRUCTION_SITES);
|
||||
|
||||
// buildings
|
||||
if (structure == null) {
|
||||
var buildings = creep.room.find(FIND_STRUCTURES,
|
||||
{ filter: (s) => ((s.structureType != STRUCTURE_RAMPART || s.structureType != STRUCTURE_WALL) && s.hits < s.hitsMax) });
|
||||
for (var building in buildings) {
|
||||
building = buildings[building];
|
||||
if (structure == null || structure.hits > building.hits) structure = building;
|
||||
}
|
||||
}
|
||||
|
||||
// ramparts and walls
|
||||
if (structure == null) {
|
||||
var ramparts = creep.room.find(FIND_STRUCTURES,
|
||||
{ filter: (s) => ((s.structureType == STRUCTURE_RAMPART || s.structureType == STRUCTURE_WALL) && s.hits < s.hitsMax) });
|
||||
for (var ramp in ramparts) {
|
||||
ramp = ramparts[ramp];
|
||||
if (structure == null || structure.hits > ramp.hits) structure = ramp;
|
||||
}
|
||||
}
|
||||
creep.memory.target = structure.id;
|
||||
}
|
||||
var target = Game.getObjectById(creep.memory.target);
|
||||
if (target == null || target.hits == target.hitsMax) creep.memory.target = null;
|
||||
if (creep.build(target) == ERR_NOT_IN_RANGE || creep.repair(target) == ERR_NOT_IN_RANGE) creep.moveTo(target);
|
||||
if (creep.store.getUsedCapacity(RESOURCE_ENERGY) == 0) {
|
||||
creep.memory.restock = true;
|
||||
creep.memory.target = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
upgrade: function (creep) {
|
||||
// Memory creation
|
||||
if (creep.memory.restock == undefined) creep.memory.restock = true;
|
||||
if (creep.memory.target == undefined) creep.memory.target = null;
|
||||
|
||||
// Job implementation
|
||||
if (creep.memory.restock) {
|
||||
if (creep.memory.target == null) {
|
||||
if (creep.room.storage != null && 1000 < creep.room.storage.store.getUsedCapacity(RESOURCE_ENERGY)) creep.memory.target = creep.room.storage.id;
|
||||
else {
|
||||
var container = creep.pos.findClosestByPath(FIND_STRUCTURES,
|
||||
{
|
||||
filter: (s) => (s.structureType == STRUCTURE_CONTAINER
|
||||
&& 0 < s.store.getUsedCapacity(RESOURCE_ENERGY))
|
||||
});
|
||||
if (container != null) creep.memory.target = container.id;
|
||||
}
|
||||
}
|
||||
var target = Game.getObjectById(creep.memory.target);
|
||||
if (creep.withdraw(target, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) creep.moveTo(target);
|
||||
if (target != null && target.store.getUsedCapacity(RESOURCE_ENERGY) < creep.store.getFreeCapacity(RESOURCE_ENERGY) * 0.4) creep.memory.target = null;
|
||||
if (creep.store.getFreeCapacity(RESOURCE_ENERGY) == 0) {
|
||||
creep.memory.restock = false;
|
||||
creep.memory.target = null;
|
||||
}
|
||||
} else {
|
||||
if (creep.memory.target == null) { // aquire target
|
||||
var structure = structure = creep.room.controller;
|
||||
creep.memory.target = structure.id;
|
||||
}
|
||||
var target = Game.getObjectById(creep.memory.target);
|
||||
if (creep.transfer(target, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) creep.moveTo(target);
|
||||
if (creep.store.getUsedCapacity(RESOURCE_ENERGY) == 0) {
|
||||
creep.memory.restock = true;
|
||||
creep.memory.target = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
defend: function (creep) {
|
||||
if (creep.memory.flag != undefined && Game.flags[creep.memory.flag].room.name != creep.room.name) creep.moveTo(Game.flags[creep.memory.flag]);
|
||||
if (creep.memory.target == undefined) creep.memory.target = null;
|
||||
if (creep.memory.target == null) {
|
||||
var enemy = creep.pos.findClosestByPath(FIND_HOSTILE_CREEPS);
|
||||
if (enemy != null) creep.memory.target = enemy.id;
|
||||
}
|
||||
var enemy = Game.getObjectById(creep.memory.target);
|
||||
if (enemy != null) {
|
||||
creep.say("ATTACK");
|
||||
if (creep.attack(enemy) == ERR_NOT_IN_RANGE) creep.moveTo(enemy);
|
||||
} else {
|
||||
creep.memory.target = null;
|
||||
}
|
||||
},
|
||||
|
||||
reserve: function (creep) {
|
||||
if (Game.flags[creep.memory.target].room != undefined && Game.flags[creep.memory.target].room == creep.room) {
|
||||
if (creep.memory.target == "xxx") {
|
||||
if (creep.claimController(creep.room.controller) == ERR_NOT_IN_RANGE) {
|
||||
creep.moveTo(creep.room.controller);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (creep.reserveController(creep.room.controller) == ERR_NOT_IN_RANGE) {
|
||||
creep.moveTo(creep.room.controller);
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
creep.moveTo(Game.flags[creep.memory.target]);
|
||||
}
|
||||
},
|
||||
|
||||
harvest_reserved: function (creep) {
|
||||
creep.memory.home = "SpawnAlpha"
|
||||
//memory setup
|
||||
if (creep.memory.harvesting == undefined) creep.memory.harvesting = true;
|
||||
if (creep.memory.counter == undefined) creep.memory.counter = 0;
|
||||
if (creep.memory.target == undefined) creep.memory.target = null;
|
||||
|
||||
if (creep.memory.harvesting) {
|
||||
var source = Game.getObjectById(creep.memory.source_id);
|
||||
if (source != undefined && creep.room.name == source.room.name) {
|
||||
var container = creep.pos.findClosestByPath(FIND_STRUCTURES, { filter: (s) => (s.structureType == STRUCTURE_CONTAINER && s.store.getUsedCapacity(RESOURCE_ENERGY) > creep.store.getFreeCapacity(RESOURCE_ENERGY)) });
|
||||
if (container == null) {
|
||||
result = creep.harvest(source);
|
||||
if (result == ERR_NOT_IN_RANGE) {
|
||||
creep.moveTo(source);
|
||||
}
|
||||
} else {
|
||||
var result = creep.withdraw(container, RESOURCE_ENERGY);
|
||||
if (result == ERR_NOT_IN_RANGE) {
|
||||
creep.moveTo(container);
|
||||
}
|
||||
}
|
||||
if (creep.store.getFreeCapacity(RESOURCE_ENERGY) == 0) {
|
||||
creep.memory.harvesting = false;
|
||||
creep.memory.target = null;
|
||||
}
|
||||
} else {
|
||||
creep.moveTo(source);
|
||||
}
|
||||
} else {
|
||||
if (creep.memory.target == null) {
|
||||
switch (creep.memory.counter % 3) {
|
||||
case 0: // building
|
||||
creep.memory.target = creep.pos.findClosestByRange(FIND_CONSTRUCTION_SITES);
|
||||
if (creep.memory.target != null) creep.memory.target = creep.memory.target.id;
|
||||
else creep.memory.counter += 1;
|
||||
break;
|
||||
case 1: // repairing (no walls or ramparts)
|
||||
creep.memory.target = creep.pos.findClosestByRange(FIND_STRUCTURES, {
|
||||
filter: (s) => (s.structureType != STRUCTURE_WALL && s.structureType != STRUCTURE_RAMPART) && s.hits < s.hitsMax - creep.store.getUsedCapacity(RESOURCE_ENERGY) * 3 / 4
|
||||
});
|
||||
if (creep.memory.target != null) creep.memory.target = creep.memory.target.id;
|
||||
else creep.memory.counter += 1;
|
||||
break;
|
||||
case 2: // suppling
|
||||
var home = Game.spawns[creep.memory.home];
|
||||
if (creep.room.name == home.room.name) {
|
||||
creep.memory.target = creep.pos.findClosestByRange(FIND_MY_STRUCTURES, {
|
||||
filter: (s) => (s.structureType == STRUCTURE_SPAWN || s.structureType == STRUCTURE_EXTENSION || s.structureType == STRUCTURE_STORAGE) && s.store.getFreeCapacity(RESOURCE_ENERGY) > 0
|
||||
});
|
||||
if (creep.memory.target != null) creep.memory.target = creep.memory.target.id;
|
||||
else creep.memory.counter += 1;
|
||||
} else {
|
||||
creep.moveTo(home);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var target = Game.getObjectById(creep.memory.target);
|
||||
var response = OK;
|
||||
switch (creep.memory.counter % 3) {
|
||||
case 0: // building
|
||||
response = creep.build(target);
|
||||
if (target != null && target.progress == target.progressTotal) creep.memory.target = null;
|
||||
break;
|
||||
case 1: // repairing
|
||||
response = creep.repair(target);
|
||||
if (target != null && target.hits == target.hitsMax) creep.memory.target = null;
|
||||
break;
|
||||
case 2: // suppling
|
||||
response = creep.transfer(target, RESOURCE_ENERGY);
|
||||
if (target != null && target.store.getFreeCapacity(RESOURCE_ENERGY) == 0) creep.memory.target = null;
|
||||
break;
|
||||
}
|
||||
if (response == ERR_NOT_IN_RANGE) {
|
||||
creep.moveTo(target);
|
||||
} else if (response == ERR_FULL || response == ERR_INVALID_TARGET) {
|
||||
creep.memory.target = null;
|
||||
}
|
||||
if (creep.store.getUsedCapacity(RESOURCE_ENERGY) == 0) {
|
||||
creep.memory.harvesting = true;
|
||||
creep.memory.target = null;
|
||||
creep.memory.counter += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
7
rooms.js
7
rooms.js
@@ -1,7 +0,0 @@
|
||||
/**
|
||||
* Managing the behavior of buildings and creeps is on a per room level.
|
||||
*/
|
||||
|
||||
|
||||
module.exports = {
|
||||
}
|
||||
1
screepsxx
Submodule
1
screepsxx
Submodule
Submodule screepsxx added at 3567060bf5
183
spawns.js
183
spawns.js
@@ -1,183 +0,0 @@
|
||||
|
||||
/* #####################################
|
||||
# Controls the way creeps are spawn #
|
||||
#####################################*/
|
||||
|
||||
var roles = require("roles");
|
||||
|
||||
module.exports = {
|
||||
run: function () {
|
||||
for (var sp in Game.spawns) {
|
||||
sp = Game.spawns[sp]
|
||||
// values
|
||||
var creep_count = 0
|
||||
for (var cr in Game.creeps) {
|
||||
if (Game.creeps[cr].room.name == sp.room.name) creep_count += 1;
|
||||
}
|
||||
var source_count = 0;
|
||||
if (sp.memory.sources_ids != undefined) source_count = sp.memory.sources_ids.length;
|
||||
|
||||
|
||||
// Memory setup
|
||||
if (sp.memory.creep_iterate == undefined) sp.memory.creep_iterate = 0;
|
||||
|
||||
if (sp.memory.sources_ids == undefined) {
|
||||
sp.memory.sources_ids = [];
|
||||
var sources = sp.room.find(FIND_SOURCES);
|
||||
for (var source in sources) {
|
||||
source = sources[source];
|
||||
sp.memory.sources_ids.push(source.id);
|
||||
}
|
||||
source_count = sp.memory.sources_ids.length;
|
||||
}
|
||||
|
||||
if (sp.memory.containers_ids == undefined || sp.memory.containers_ids.length != source_count) {
|
||||
sp.memory.containers_ids = [];
|
||||
var containers = sp.room.find(FIND_STRUCTURES, { filter: { structureType: STRUCTURE_CONTAINER } });
|
||||
if (containers.length > 0) {
|
||||
for (let i = 0; i < containers.length; i += 1) {
|
||||
sp.memory.containers_ids.push(containers[i].id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Different spawning configurations
|
||||
|
||||
// Add improved versions at top of if-else statement
|
||||
if (sp.memory.containers_ids.length >= source_count && sp.room.energyCapacityAvailable >= 550 && creep_count > source_count) { // Miner method: Miners fille containers rest picks up from them
|
||||
// Check current creep_jobs
|
||||
var jobs = { miner: 0, supplier: 0, builder: 0, upgrader: 0, defender: 0 };
|
||||
var container_id = sp.memory.containers_ids[0];
|
||||
for (var creep in Game.creeps) {
|
||||
var creep = Game.creeps[creep];
|
||||
if (creep.room.name != sp.room.name) continue;
|
||||
switch (creep.memory.role) {
|
||||
case roles.ROLE_MINER:
|
||||
jobs.miner += 1;
|
||||
for (let i = 0; i < sp.memory.containers_ids.length; i++) {
|
||||
if (creep.memory.container_id != sp.memory.containers_ids[i]) container_id = sp.memory.containers_ids[i];
|
||||
}
|
||||
break;
|
||||
case roles.ROLE_SUPPLIER:
|
||||
jobs.supplier += creep.body.length;
|
||||
break;
|
||||
case roles.ROLE_BUILDER:
|
||||
jobs.builder += creep.body.length;
|
||||
break;
|
||||
case roles.ROLE_UPGRADER:
|
||||
jobs.upgrader += creep.body.length;
|
||||
break;
|
||||
case roles.ROLE_DEFENDER:
|
||||
jobs.defender += 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (jobs.miner < source_count) {
|
||||
if (sp.room.energyAvailable >= 550) create_miner(sp, container_id);
|
||||
}
|
||||
else if (jobs.supplier < source_count * 15 && sp.room.energyAvailable >= 300 && jobs.miner > 0) create_supplier(sp);
|
||||
else if (jobs.builder < source_count * 5 && sp.room.energyAvailable >= 300 && jobs.miner > 0) create_builder(sp);
|
||||
else if (jobs.upgrader < source_count * 5 && sp.room.energyAvailable >= 300 && jobs.miner > 0) create_upgrader(sp);
|
||||
else if (jobs.defender < 0 && sp.room.energyAvailable >= sp.room.energyCapacityAvailable * 0.8 && jobs.miner > 0) create_defender(sp);
|
||||
} else { // Harvesting method: everybody mines own sources
|
||||
if (sp.room.find(FIND_MY_CREEPS).length < source_count * 5 && sp.room.energyAvailable >= 300) {
|
||||
var source_id = sp.memory.sources_ids[sp.memory.creep_iterate % source_count];
|
||||
create_harvester(sp, source_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function create_harvester(sp, source_id) {
|
||||
var body = [];
|
||||
for (let i = 0; i < Math.floor(sp.room.energyAvailable / 200); i++) {
|
||||
body.push(WORK);
|
||||
body.push(CARRY);
|
||||
body.push(MOVE);
|
||||
}
|
||||
var name = "Harvy" + sp.memory.creep_iterate;
|
||||
sp.spawnCreep(body, name, {
|
||||
memory:
|
||||
{ role: roles.ROLE_HARVESTER, source_id: source_id }
|
||||
});
|
||||
sp.memory.creep_iterate += 1;
|
||||
}
|
||||
|
||||
function create_miner(sp, container_id) {
|
||||
var body = [WORK, WORK, WORK, WORK, WORK, MOVE]; // (creep)5*work(2energy/tick)=10energy/tick -> (source)3000energy/300tick=10energy/tick
|
||||
var name = "Mindy" + sp.memory.creep_iterate;
|
||||
sp.spawnCreep(body, name, {
|
||||
memory:
|
||||
{ role: roles.ROLE_MINER, container_id: container_id }
|
||||
});
|
||||
sp.memory.creep_iterate += 1;
|
||||
}
|
||||
|
||||
function create_supplier(sp) {
|
||||
var body = [WORK];
|
||||
|
||||
for (let i = 0; i < Math.floor(sp.room.energyAvailable / 100) - 1 && i < 8; i++) { // as big as possible
|
||||
body.push(CARRY);
|
||||
body.push(MOVE);
|
||||
}
|
||||
var name = "Suppry" + sp.memory.creep_iterate;
|
||||
sp.spawnCreep(body, name, {
|
||||
memory:
|
||||
{ role: roles.ROLE_SUPPLIER }
|
||||
});
|
||||
sp.memory.creep_iterate += 1;
|
||||
}
|
||||
|
||||
function create_builder(sp) {
|
||||
var body = [];
|
||||
|
||||
for (let i = 0; i < Math.floor(sp.room.energyAvailable / 200); i++) { // as big as possible
|
||||
body.push(CARRY);
|
||||
body.push(MOVE);
|
||||
body.push(WORK);
|
||||
}
|
||||
var name = "Bobby" + sp.memory.creep_iterate;
|
||||
sp.spawnCreep(body, name, {
|
||||
memory:
|
||||
{ role: roles.ROLE_BUILDER }
|
||||
});
|
||||
sp.memory.creep_iterate += 1;
|
||||
}
|
||||
|
||||
function create_upgrader(sp) {
|
||||
var body = [];
|
||||
|
||||
for (let i = 0; i < Math.floor(sp.room.energyAvailable / 300); i++) { // as big as possible
|
||||
body.push(CARRY);
|
||||
body.push(MOVE);
|
||||
body.push(WORK);
|
||||
body.push(WORK);
|
||||
}
|
||||
var name = "Undy" + sp.memory.creep_iterate;
|
||||
sp.spawnCreep(body, name, {
|
||||
memory:
|
||||
{ role: roles.ROLE_UPGRADER }
|
||||
});
|
||||
sp.memory.creep_iterate += 1;
|
||||
}
|
||||
|
||||
function create_defender(sp) {
|
||||
var body = [];
|
||||
|
||||
for (let i = 0; i < Math.floor(sp.room.energyAvailable / 150); i++) { // as big as possible
|
||||
body.push(TOUGH);
|
||||
body.push(TOUGH);
|
||||
body.push(ATTACK);
|
||||
body.push(MOVE);
|
||||
}
|
||||
var name = "Destroyer CODE" + sp.memory.creep_iterate;
|
||||
sp.spawnCreep(body, name, {
|
||||
memory:
|
||||
{ role: roles.ROLE_DEFENDER }
|
||||
});
|
||||
sp.memory.creep_iterate += 1;
|
||||
}
|
||||
19
system.js
19
system.js
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Basis of the entire system. Everything will be managed from here on out.
|
||||
*/
|
||||
|
||||
const commands = require("commands");
|
||||
const creeps = require("creeps")
|
||||
|
||||
module.exports = {
|
||||
// Gets called when recompiling and when Restart command is called.
|
||||
start: function () {
|
||||
commands.configure();
|
||||
creeps.configure();
|
||||
},
|
||||
|
||||
// Gets called every tick.
|
||||
update: function () {
|
||||
creeps.execute();
|
||||
}
|
||||
}
|
||||
36
towers.js
36
towers.js
@@ -1,36 +0,0 @@
|
||||
module.exports = {
|
||||
|
||||
run: function(){
|
||||
for(var spawn in Game.spawns){
|
||||
var room = Game.spawns[spawn].room;
|
||||
var towers = room.find(FIND_MY_STRUCTURES,
|
||||
{filter: {structureType: STRUCTURE_TOWER}});
|
||||
|
||||
for(var tower in towers){
|
||||
tower = towers[tower];
|
||||
var enemy = tower.pos.findClosestByRange(FIND_HOSTILE_CREEPS);
|
||||
if(enemy != null) tower.attack(enemy);
|
||||
else {
|
||||
var healt_creep = false;
|
||||
for(var creep in Game.creeps){
|
||||
creep = Game.creeps[creep];
|
||||
if(creep.hits < creep.hitsMax) {
|
||||
tower.heal(creep);
|
||||
healt_creep = true;
|
||||
}
|
||||
}
|
||||
if(!healt_creep && 500 < tower.energy){
|
||||
var structure = tower.pos.findClosestByPath(FIND_STRUCTURES,
|
||||
{filter: (s)=>(s.structureType != STRUCTURE_RAMPART && s.structureType != STRUCTURE_WALL && s.hits < s.hitsMax)});
|
||||
if(750 < tower.energy && structure == null) {
|
||||
var structures = tower.room.find(FIND_STRUCTURES, {filter: { structureType: STRUCTURE_RAMPART, structureType: STRUCTURE_WALL }});
|
||||
structures.sort(function(a,b){return a.hits - b.hits});
|
||||
structure = structures[0];
|
||||
}
|
||||
tower.repair(structure);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user