diff --git a/src/creep/builder.ts b/src/creep/builder.ts index 74498ca..3de1f89 100644 --- a/src/creep/builder.ts +++ b/src/creep/builder.ts @@ -1,8 +1,8 @@ -import { randomIntInRange } from '../utils/Random'; +import { selectSource } from './common'; interface BuilderMemory extends CreepMemory { building: boolean | undefined; - sourceNum: number | undefined; + sourceId: Id | undefined; } export function runAsBuilder(creep: Creep) { @@ -16,9 +16,8 @@ export function runAsBuilder(creep: Creep) { memory.building = true; } - if (memory.sourceNum === undefined) { - const sources = creep.room.find(FIND_SOURCES); - memory.sourceNum = randomIntInRange(0, sources.length); + if (memory.sourceId === undefined) { + memory.sourceId = selectSource(creep); } if (memory.building) { @@ -34,11 +33,10 @@ export function runAsBuilder(creep: Creep) { creep.moveTo(spawns[0]); } } else { - const sources = creep.room.find(FIND_SOURCES); - const sourceNum = memory.sourceNum; - if (creep.harvest(sources[sourceNum]) == ERR_NOT_IN_RANGE) { - creep.say('🔄 harvest ' + sourceNum); - creep.moveTo(sources[sourceNum], { visualizePathStyle: { stroke: '#ffaa00' } }); + const source = Game.getObjectById(memory.sourceId); + if (source && creep.harvest(source) == ERR_NOT_IN_RANGE) { + creep.say('🔄 harvest'); + creep.moveTo(source, { visualizePathStyle: { stroke: '#ffaa00' } }); } } } diff --git a/src/creep/common.ts b/src/creep/common.ts index 50d01fc..71764ed 100644 --- a/src/creep/common.ts +++ b/src/creep/common.ts @@ -1,22 +1,21 @@ -import { randomIntInRange } from '../utils/Random'; +import { randomValueFromArray } from '../utils/Random'; -export interface SourceNumber { - sourceNum: number | undefined; -} - -function selectSource(memory: SourceNumber) { - if (memory.sourceNum === undefined) { - const sources = creep.room.find(FIND_SOURCES); - memory.sourceNum = randomIntInRange(0, sources.length); - } -} - -function moveToSource(creep: Creep) { - const memory = creep.memory as SourceNumber; +export function selectSource(creep: Creep): Id { const sources = creep.room.find(FIND_SOURCES); - const sourceNum = memory.sourceNum; - if (creep.harvest(sources[sourceNum]) == ERR_NOT_IN_RANGE) { - creep.say('🔄 harvest ' + sourceNum); - creep.moveTo(sources[sourceNum], { visualizePathStyle: { stroke: '#ffaa00' } }); + const choices: Array = []; + for (let source of sources) { + const weight = getSourceWeight(source); + for (let i = 0; i < weight; ++i) { + choices.push(source.id); + } } + console.log('Sources', choices); + return randomValueFromArray(choices) as Id; +} + +function getSourceWeight(source: Source) { + const pos = source.pos; + const terrains = source.room.lookForAtArea(LOOK_TERRAIN, pos.y - 1, pos.x - 1, pos.y + 1, pos.x + 1, true); + const walked = terrains.filter((t) => t.terrain !== 'wall'); + return Math.max(walked.length - 1, 1); } diff --git a/src/creep/harvester.ts b/src/creep/harvester.ts index 2e70ce5..f3bd67c 100644 --- a/src/creep/harvester.ts +++ b/src/creep/harvester.ts @@ -1,23 +1,21 @@ -import { randomIntInRange } from '../utils/Random'; +import { selectSource } from './common'; interface HarvesterMemory extends CreepMemory { - sourceNum: number | undefined; + sourceId: Id | undefined; } export function runAsHarvester(creep: Creep) { const memory = creep.memory as HarvesterMemory; - if (memory.sourceNum === undefined) { - const sources = creep.room.find(FIND_SOURCES); - memory.sourceNum = randomIntInRange(0, sources.length); + if (memory.sourceId === undefined) { + memory.sourceId = selectSource(creep); } if (creep.store.getFreeCapacity() > 0) { - let sources = creep.room.find(FIND_SOURCES); - const sourceNum = memory.sourceNum; - if (creep.harvest(sources[sourceNum]) === ERR_NOT_IN_RANGE) { - creep.say('🔄 harvest ' + sourceNum); - creep.moveTo(sources[sourceNum], { visualizePathStyle: { stroke: '#ffaa00' } }); + const source = Game.getObjectById(memory.sourceId); + if (source && creep.harvest(source) === ERR_NOT_IN_RANGE) { + creep.say('🔄 harvest'); + creep.moveTo(source, { visualizePathStyle: { stroke: '#ffaa00' } }); } } else { let targets = creep.room.find(FIND_STRUCTURES, { diff --git a/src/creep/upgrader.ts b/src/creep/upgrader.ts index 80eff48..034f7c0 100644 --- a/src/creep/upgrader.ts +++ b/src/creep/upgrader.ts @@ -1,8 +1,8 @@ -import { randomIntInRange } from '../utils/Random'; +import { selectSource } from './common'; interface UpgraderMemory extends CreepMemory { upgrading: boolean | undefined; - sourceNum: number | undefined; + sourceId: Id | undefined; } export function runAsUpgrader(creep: Creep) { @@ -16,9 +16,8 @@ export function runAsUpgrader(creep: Creep) { memory.upgrading = true; } - if (memory.sourceNum === undefined) { - const sources = creep.room.find(FIND_SOURCES); - memory.sourceNum = randomIntInRange(0, sources.length); + if (memory.sourceId === undefined) { + memory.sourceId = selectSource(creep); } if (memory.upgrading) { @@ -27,11 +26,10 @@ export function runAsUpgrader(creep: Creep) { creep.moveTo(creep.room.controller, { visualizePathStyle: { stroke: '#ffffff' } }); } } else { - const sources = creep.room.find(FIND_SOURCES); - const sourceNum = memory.sourceNum; - if (creep.harvest(sources[sourceNum]) == ERR_NOT_IN_RANGE) { - creep.say('🔄 harvest ' + sourceNum); - creep.moveTo(sources[sourceNum], { visualizePathStyle: { stroke: '#ffaa00' } }); + const source = Game.getObjectById(memory.sourceId); + if (source && creep.harvest(source) == ERR_NOT_IN_RANGE) { + creep.say('🔄 harvest'); + creep.moveTo(source, { visualizePathStyle: { stroke: '#ffaa00' } }); } } } diff --git a/src/main.ts b/src/main.ts index a86a42c..f8a6879 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,8 +4,8 @@ import { runAsBuilder } from './creep/builder'; import { runAsUpgrader } from './creep/upgrader'; import { uniqId } from './utils/Identity'; -function makeName(role: string): string { - return uniqId(role + '_'); +function makeName(): string { + return uniqId(); } enum CreepRole { @@ -19,17 +19,35 @@ function makeCreep(role: CreepRole, count: number) { console.log(`Make creep "${role}"`, 'need', count, 'has', creeps.length); if (creeps.length < count) { const firstSpawn = _.first(Object.values(Game.spawns)); - const name = makeName(role); + const name = makeName(); const memory = { role: role } as CreepMemory; const err = firstSpawn.spawnCreep([WORK, CARRY, MOVE], name, { memory }); console.log(`Make creep "${role}"`, 'err', err); } } +function callHarvestersFromOthers(minHarvCount: number) { + const harvesters = Object.values(Game.creeps).filter((c) => c.memory.role === CreepRole.HARVESTER); + if (harvesters.length < minHarvCount) { + const others = Object.values(Game.creeps).filter((c) => c.memory.role !== CreepRole.HARVESTER); + const required = Math.min(minHarvCount, others.length); + console.log('Call harvesters', required); + let count = 0; + for (let creep of others) { + if (count >= required) { + break; + } + count++; + creep.memory.role = CreepRole.HARVESTER; + } + } +} + // When compiling TS to JS and bundling with rollup, the line numbers and file names in error messages change // This utility uses source maps to get the line numbers and file names of the original, TS source code export const loop = ErrorMapper.wrapLoop(() => { - console.log(`\nCurrent game tick is ${Game.time}`); + console.log(''); + console.log(`Current game tick is ${Game.time}`); // Automatically delete memory of missing creeps for (const name in Memory.creeps) { @@ -38,10 +56,15 @@ export const loop = ErrorMapper.wrapLoop(() => { } } - makeCreep(CreepRole.HARVESTER, 6); + const harvCount = 8; + const minHarvCount = Math.floor(harvCount * 0.6); + + makeCreep(CreepRole.HARVESTER, harvCount); makeCreep(CreepRole.UPGRADER, 6); makeCreep(CreepRole.BUILDER, 6); + callHarvestersFromOthers(minHarvCount); + // Process current creeps for (let name in Game.creeps) { const creep = Game.creeps[name]; diff --git a/src/utils/Random.ts b/src/utils/Random.ts index 9a4ddca..ecd379f 100644 --- a/src/utils/Random.ts +++ b/src/utils/Random.ts @@ -2,3 +2,9 @@ export function randomIntInRange(min: number, max: number): number { const delta = max - min; return Math.floor(Math.random() * delta) + min; } + +export function randomValueFromArray(items: Array): T { + const len = items.length; + const index = randomIntInRange(0, len); + return items[index]; +}