diff --git a/src/harvester.py b/src/harvester.py deleted file mode 100644 index 545db8cc..00000000 --- a/src/harvester.py +++ /dev/null @@ -1,80 +0,0 @@ -from defs import * - -__pragma__('noalias', 'name') -__pragma__('noalias', 'undefined') -__pragma__('noalias', 'Infinity') -__pragma__('noalias', 'keys') -__pragma__('noalias', 'get') -__pragma__('noalias', 'set') -__pragma__('noalias', 'type') -__pragma__('noalias', 'update') - - -def run_harvester(creep): - """ - Runs a creep as a generic harvester. - :param creep: The creep to run - """ - - # If we're full, stop filling up and remove the saved source - if creep.memory.filling and _.sum(creep.carry) >= creep.carryCapacity: - creep.memory.filling = False - del creep.memory.source - # If we're empty, start filling again and remove the saved target - elif not creep.memory.filling and creep.carry.energy <= 0: - creep.memory.filling = True - del creep.memory.target - - if creep.memory.filling: - # If we have a saved source, use it - if creep.memory.source: - source = Game.getObjectById(creep.memory.source) - else: - # Get a random new source and save it - source = _.sample(creep.room.find(FIND_SOURCES)) - creep.memory.source = source.id - - # If we're near the source, harvest it - otherwise, move to it. - if creep.pos.isNearTo(source): - result = creep.harvest(source) - if result != OK: - print("[{}] Unknown result from creep.harvest({}): {}".format(creep.name, source, result)) - else: - creep.moveTo(source) - else: - # If we have a saved target, use it - if creep.memory.target: - target = Game.getObjectById(creep.memory.target) - else: - # Get a random new target. - target = _(creep.room.find(FIND_STRUCTURES)) \ - .filter(lambda s: ((s.structureType == STRUCTURE_SPAWN or s.structureType == STRUCTURE_EXTENSION) - and s.energy < s.energyCapacity) or s.structureType == STRUCTURE_CONTROLLER) \ - .sample() - creep.memory.target = target.id - - # If we are targeting a spawn or extension, we need to be directly next to it - otherwise, we can be 3 away. - if target.energyCapacity: - is_close = creep.pos.isNearTo(target) - else: - is_close = creep.pos.inRangeTo(target, 3) - - if is_close: - # If we are targeting a spawn or extension, transfer energy. Otherwise, use upgradeController on it. - if target.energyCapacity: - result = creep.transfer(target, RESOURCE_ENERGY) - if result == OK or result == ERR_FULL: - del creep.memory.target - else: - print("[{}] Unknown result from creep.transfer({}, {}): {}".format( - creep.name, target, RESOURCE_ENERGY, result)) - else: - result = creep.upgradeController(target) - if result != OK: - print("[{}] Unknown result from creep.upgradeController({}): {}".format( - creep.name, target, result)) - # Let the creeps get a little bit closer than required to the controller, to make room for other creeps. - if not creep.pos.inRangeTo(target, 2): - creep.moveTo(target) - else: - creep.moveTo(target) diff --git a/src/main.py b/src/main.py index c279243a..7d881df9 100644 --- a/src/main.py +++ b/src/main.py @@ -1,4 +1,14 @@ -import harvester +# Example Code +# +# This is a copy of the tutorial code from +# https://github.com/screeps/tutorial-scripts. +# +# This tries to be a line-by-line translation, with two exceptions: it includes +# code from both section4 and section5 tutorials (so both tower code and spawning +# code), and it includes some limited comments. + +from role import harvester, upgrader, builder + # defs is a package which claims to export all constants and some JavaScript objects, but in reality does # nothing. This is useful mainly when using an editor like PyCharm, so that it 'knows' that things like Object, Creep, # Game, etc. do exist. @@ -22,28 +32,57 @@ def main(): Main game logic loop. """ + # Clean up dead creep memory + for name in Object.keys(Memory.creeps): + if not Game.creeps[name]: + del Memory.creeps[name] + console.log('Clearing non-existing creep memory:', name) + + harvesters = _.filter( + Game.creeps, lambda creep: creep.memory.role == 'harvester') + console.log('Harvesters: ' + len(harvesters)) + + if len(harvesters) < 2: + newName = 'Harvester' + Game.time + console.log('Spawning new harvester: ' + newName) + Game.spawns['Spawn1'].spawnCreep( + [WORK, CARRY, MOVE], + newName, + {'memory': {'role': 'harvester'}} + ) + + if Game.spawns['Spawn1'].spawning: + spawningCreep = Game.creeps[Game.spawns['Spawn1'].spawning.name] + Game.spawns['Spawn1'].room.visual.text( + '🛠️' + spawningCreep.memory.role, + Game.spawns['Spawn1'].pos.x + 1, + Game.spawns['Spawn1'].pos.y, + {'align': 'left', 'opacity': 0.8} + ) + + # replace this with the id of your tower + tower = Game.getObjectById('TOWER_ID') + + if tower: + closest_damaged_structure = tower.pos.findClosestByRange(FIND_STRUCTURES, { + "filter": lambda structure: structure.hits < structure.hitsMax + }) + if closest_damaged_structure: + tower.repair(closest_damaged_structure) + + closest_hostile = tower.pos.findClosestByRange(FIND_HOSTILE_CREEPS) + if closest_hostile: + tower.attack(closest_hostile) + # Run each creep for name in Object.keys(Game.creeps): creep = Game.creeps[name] - harvester.run_harvester(creep) - - # Run each spawn - for name in Object.keys(Game.spawns): - spawn = Game.spawns[name] - if not spawn.spawning: - # Get the number of our creeps in the room. - num_creeps = _.sum(Game.creeps, lambda c: c.pos.roomName == spawn.pos.roomName) - # If there are no creeps, spawn a creep once energy is at 250 or more - if num_creeps < 0 and spawn.room.energyAvailable >= 250: - spawn.createCreep([WORK, CARRY, MOVE, MOVE]) - # If there are less than 15 creeps but at least one, wait until all spawns and extensions are full before - # spawning. - elif num_creeps < 15 and spawn.room.energyAvailable >= spawn.room.energyCapacityAvailable: - # If we have more energy, spawn a bigger creep. - if spawn.room.energyCapacityAvailable >= 350: - spawn.createCreep([WORK, CARRY, CARRY, MOVE, MOVE, MOVE]) - else: - spawn.createCreep([WORK, CARRY, MOVE, MOVE]) + if creep.memory.role == 'harvester': + harvester.run(creep) + if creep.memory.role == 'upgrader': + upgrader.run(creep) + if creep.memory.role == 'builder': + builder.run(creep) module.exports.loop = main diff --git a/src/role/__init__.py b/src/role/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/role/builder.py b/src/role/builder.py new file mode 100644 index 00000000..f4ed1c67 --- /dev/null +++ b/src/role/builder.py @@ -0,0 +1,31 @@ +from defs import * + +__pragma__('noalias', 'name') +__pragma__('noalias', 'undefined') +__pragma__('noalias', 'Infinity') +__pragma__('noalias', 'keys') +__pragma__('noalias', 'get') +__pragma__('noalias', 'set') +__pragma__('noalias', 'type') +__pragma__('noalias', 'update') + + +def run(creep: Creep): + if creep.memory.building and creep.store[RESOURCE_ENERGY] == 0: + creep.memory.building = False + creep.say('🔄 harvest') + if not creep.memory.building and creep.store.getFreeCapacity() == 0: + creep.memory.building = True + creep.say('🚧 build') + + if creep.memory.building: + targets = creep.room.find(FIND_CONSTRUCTION_SITES) + if len(targets): + if creep.build(targets[0]) == ERR_NOT_IN_RANGE: + creep.moveTo( + targets[0], {'visualizePathStyle': {'stroke': '#ffffff'}}) + else: + sources = creep.room.find(FIND_SOURCES) + if creep.harvest(sources[0]) == ERR_NOT_IN_RANGE: + creep.moveTo( + sources[0], {'visualizePathStyle': {'stroke': '#ffaa00'}}) diff --git a/src/role/harvester.py b/src/role/harvester.py new file mode 100644 index 00000000..1f051855 --- /dev/null +++ b/src/role/harvester.py @@ -0,0 +1,33 @@ +from defs import * + +__pragma__('noalias', 'name') +__pragma__('noalias', 'undefined') +__pragma__('noalias', 'Infinity') +__pragma__('noalias', 'keys') +__pragma__('noalias', 'get') +__pragma__('noalias', 'set') +__pragma__('noalias', 'type') +__pragma__('noalias', 'update') + + +def run(creep: Creep): + if creep.store.getFreeCapacity() > 0: + sources = creep.room.find(FIND_SOURCES) + if creep.harvest(sources[0]) == ERR_NOT_IN_RANGE: + creep.moveTo( + sources[0], {'visualizePathStyle': {'stroke': '#ffaa00'}}) + else: + targets = creep.room.find(FIND_STRUCTURES, { + 'filter': lambda structure: ( + ( + structure.structureType == STRUCTURE_EXTENSION or + structure.structureType == STRUCTURE_SPAWN or + structure.structureType == STRUCTURE_TOWER + ) and + structure.store.getFreeCapacity(RESOURCE_ENERGY) > 0 + ) + }) + if len(targets) > 0: + if creep.transfer(targets[0], RESOURCE_ENERGY) == ERR_NOT_IN_RANGE: + creep.moveTo( + targets[0], {'visualizePathStyle': {'stroke': '#ffffff'}}) diff --git a/src/role/upgrader.py b/src/role/upgrader.py new file mode 100644 index 00000000..2d087508 --- /dev/null +++ b/src/role/upgrader.py @@ -0,0 +1,29 @@ +from defs import * + +__pragma__('noalias', 'name') +__pragma__('noalias', 'undefined') +__pragma__('noalias', 'Infinity') +__pragma__('noalias', 'keys') +__pragma__('noalias', 'get') +__pragma__('noalias', 'set') +__pragma__('noalias', 'type') +__pragma__('noalias', 'update') + + +def run(creep: Creep): + if creep.memory.upgrading and creep.store[RESOURCE_ENERGY] == 0: + creep.memory.upgrading = False + creep.say('🔄 harvest') + if not creep.memory.upgrading and creep.store.getFreeCapacity() == 0: + creep.memory.upgrading = True + creep.say('⚡ upgrade') + + if creep.memory.upgrading: + if creep.upgradeController(creep.room.controller) == ERR_NOT_IN_RANGE: + creep.moveTo(creep.room.controller, + {'visualizePathStyle': {'stroke': '#ffffff'}}) + else: + sources = creep.room.find(FIND_SOURCES) + if creep.harvest(sources[0]) == ERR_NOT_IN_RANGE: + creep.moveTo(sources[0], + {'visualizePathStyle': {'stroke': '#ffaa00'}})