diff --git a/src/Actions/Action.ts b/src/Actions/Action.ts deleted file mode 100644 index f3cc0d9..0000000 --- a/src/Actions/Action.ts +++ /dev/null @@ -1,62 +0,0 @@ -declare global { - interface CreepMemory { - state?: number; - } -} - -export interface ChainableAction { - or: (action: Action) => ChainableAction; - and: (action: Action) => ChainableAction; - andThen: (action: Action) => ChainableAction; - repeat: () => void; -} - -export const NoOp: Action = (creep: Creep, state: number = 0) => ({ - or: () => NoOp(creep, state), - and: () => NoOp(creep, state), - andThen: () => NoOp(creep, state), - repeat: () => {}, -}); - -export const Success: Action = (creep: Creep, state: number = 0) => ({ - or: () => Success(creep, state), - and: (action: Action) => action(creep, state), - andThen: (action: Action) => { - creep.memory.state = state + 1; - return action(creep, state + 1); - }, - repeat: () => { - creep.memory.state = 0; - }, -}); - -export const InProgress: Action = (creep: Creep, state: number = 0) => ({ - or: () => InProgress(creep, state), - and: (action: Action) => action(creep, state), - andThen: () => NoOp(creep, state), - repeat: () => {}, -}); - -export const Fail: Action = (creep: Creep, state: number = 0) => ({ - or: (action: Action) => action(creep, state), - and: () => NoOp(creep, state), - andThen: () => NoOp(creep, state), - repeat: () => { - console.log("Warning: Last task in series failed for creep " + creep.name); - }, -}); - -export const createAction - = (name: string, action: (c: Creep) => Action): Action => { - return (creep: Creep, state: number = 0) => { - if ((creep.memory.state ?? 0) > state) { - return Success(creep, state); - } - return action(creep)(creep, state); - }; - }; - -export const runAction = (creep: Creep, action: Action): ChainableAction => - action(creep); - -export type Action = (creep: Creep, state?: number) => ChainableAction; diff --git a/src/Actions/buildConstructionSite.ts b/src/Actions/buildConstructionSite.ts deleted file mode 100644 index 8cc5131..0000000 --- a/src/Actions/buildConstructionSite.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { createAction, Fail, InProgress, Success } from "./Action"; -import { moveTo } from "./moveTo"; - -export const buildConstructionSite = () => - createAction("buildConstructionSite", (creep: Creep) => { - const cs = creep.pos.findClosestByRange(FIND_CONSTRUCTION_SITES); - if (!cs) { - return Fail; - } - switch (creep.build(cs)) { - case OK: { - return InProgress; - } - case ERR_NOT_ENOUGH_RESOURCES: { - return Success; - } - case ERR_NOT_IN_RANGE: { - return moveTo(cs); - } - default: { - return Fail; - } - } - }); diff --git a/src/Actions/harvest.ts b/src/Actions/harvest.ts deleted file mode 100644 index ff04e16..0000000 --- a/src/Actions/harvest.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { createAction, Fail, InProgress, Success } from "./Action"; -import { moveTo } from "./moveTo"; - -export const harvestFromClosestActiveSource = () => - createAction("harvestFromClosestActiveSource", (creep: Creep) => { - const source = creep.pos.findClosestByPath(FIND_SOURCES_ACTIVE); - if (!source) { - return Fail; - } - if (creep.store.getFreeCapacity(RESOURCE_ENERGY) === 0) { - return Success; - } - switch (creep.harvest(source)) { - case OK: { - return InProgress; - } - case ERR_NOT_IN_RANGE: { - return moveTo(source); - } - default: { - return Fail; - } - } - }); diff --git a/src/Actions/moveTo.ts b/src/Actions/moveTo.ts deleted file mode 100644 index 2e34e92..0000000 --- a/src/Actions/moveTo.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { createAction, Fail, InProgress } from "./Action"; - -export const moveTo = (pos: _HasRoomPosition | RoomPosition) => - createAction("moveTo", (creep: Creep) => { - switch (creep.travelTo(pos)) { - case OK: { - return InProgress; - } - case ERR_TIRED: { - return InProgress; - } - default: { - return Fail; - } - } - }); diff --git a/src/Actions/repairStructure.ts b/src/Actions/repairStructure.ts deleted file mode 100644 index a11a796..0000000 --- a/src/Actions/repairStructure.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { createAction, Fail, InProgress, Success } from "./Action"; -import { moveTo } from "./moveTo"; - -export const repairStructure = () => - createAction("repairStructure", (creep: Creep) => { - const cs = creep.pos.findClosestByRange(FIND_STRUCTURES, - { filter: str => str.hits < str.hitsMax * 0.8 }); - if (!cs) { - return Fail; - } - switch (creep.repair(cs)) { - case OK: { - return InProgress; - } - case ERR_NOT_ENOUGH_RESOURCES: { - return Success; - } - case ERR_NOT_IN_RANGE: { - return moveTo(cs); - } - default: { - return Fail; - } - } - }); diff --git a/src/Actions/transferEnergy.ts b/src/Actions/transferEnergy.ts deleted file mode 100644 index 0fefeec..0000000 --- a/src/Actions/transferEnergy.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { createAction, Fail, InProgress, Success } from "./Action"; -import { moveTo } from "./moveTo"; - -type TransferTarget = Creep - | StructureSpawn - | StructureContainer - | StructureStorage - | StructureExtension - | StructureTower; - -export const transferEnergy = (target: TransferTarget | null) => - createAction("transferEnergy", (creep: Creep) => { - if (target == null) { - return Fail; - } - if (target.store.getFreeCapacity(RESOURCE_ENERGY) === 0) { - return Fail; - } - switch (creep.transfer(target, RESOURCE_ENERGY)) { - case OK: { - return InProgress; - } - case ERR_NOT_ENOUGH_RESOURCES: { - return Success; - } - case ERR_NOT_IN_RANGE: { - return moveTo(target); - } - default: { - return Fail; - } - } - }); diff --git a/src/Actions/upgradeController.ts b/src/Actions/upgradeController.ts deleted file mode 100644 index 58af52b..0000000 --- a/src/Actions/upgradeController.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { createAction, Fail, InProgress, Success } from "./Action"; -import { moveTo } from "./moveTo"; - -export const upgradeController = (controller: StructureController) => - createAction("upgradeController", (creep: Creep) => { - switch (creep.upgradeController(controller)) { - case OK: { - return InProgress; - } - case ERR_NOT_ENOUGH_RESOURCES: { - return Success; - } - case ERR_NOT_IN_RANGE: { - return moveTo(controller); - } - default: { - return Fail; - } - } - }); diff --git a/src/Actions/withdrawEnergy.ts b/src/Actions/withdrawEnergy.ts deleted file mode 100644 index 0fe9bd8..0000000 --- a/src/Actions/withdrawEnergy.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { createAction, Fail, InProgress, Success } from "./Action"; -import { moveTo } from "./moveTo"; - -export const withdrawEnergy - = (target: StructureContainer | StructureStorage | null) => - createAction("withdrawEnergy", (creep: Creep) => { - if (target == null) { - return Fail; - } - if (target.store.getUsedCapacity(RESOURCE_ENERGY) === 0) { - return Fail; - } - switch (creep.withdraw(target, RESOURCE_ENERGY)) { - case OK: { - return InProgress; - } - case ERR_FULL: { - return Success; - } - case ERR_NOT_IN_RANGE: { - return moveTo(target); - } - default: { - return Fail; - } - } - }); diff --git a/src/RoomPlanner/Blueprints/Containers.ts b/src/RoomPlanner/Blueprints/Containers.ts deleted file mode 100644 index 57cd32b..0000000 --- a/src/RoomPlanner/Blueprints/Containers.ts +++ /dev/null @@ -1,47 +0,0 @@ -export const buildContainers = (room: Room) => { - const controller = room.controller; - if (controller == null) { - return; - } - if (controller.level < 2 - && room.find(FIND_MY_STRUCTURES, - { filter: STRUCTURE_EXTENSION }).length > 1) { - return; - } - const sources = room.find(FIND_SOURCES); - for (const source of sources) { - const pos = source.pos; - room.createConstructionSite(pos.x - 1, pos.y, STRUCTURE_CONTAINER); - room.createConstructionSite(pos.x + 1, pos.y, STRUCTURE_CONTAINER); - room.createConstructionSite(pos.x, pos.y - 1, STRUCTURE_CONTAINER); - room.createConstructionSite(pos.x, pos.y + 1, STRUCTURE_CONTAINER); - room.createConstructionSite(pos.x - 1, pos.y + 1, STRUCTURE_CONTAINER); - room.createConstructionSite(pos.x + 1, pos.y - 1, STRUCTURE_CONTAINER); - room.createConstructionSite(pos.x - 1, pos.y - 1, STRUCTURE_CONTAINER); - room.createConstructionSite(pos.x + 1, pos.y + 1, STRUCTURE_CONTAINER); - } - if (controller.level < 4) { - return; - } - const terrain = room.getTerrain(); - if (terrain.get(controller.pos.x, controller.pos.y - 3) - !== TERRAIN_MASK_WALL) { - room.createConstructionSite( - controller.pos.x, controller.pos.y - 3, STRUCTURE_STORAGE); - } - else if (terrain.get(controller.pos.x, controller.pos.y + 3) - !== TERRAIN_MASK_WALL) { - room.createConstructionSite( - controller.pos.x, controller.pos.y + 3, STRUCTURE_STORAGE); - } - else if (terrain.get(controller.pos.x - 3, controller.pos.y) - !== TERRAIN_MASK_WALL) { - room.createConstructionSite( - controller.pos.x - 3, controller.pos.y, STRUCTURE_STORAGE); - } - else if (terrain.get(controller.pos.x + 3, controller.pos.y) - !== TERRAIN_MASK_WALL) { - room.createConstructionSite( - controller.pos.x + 3, controller.pos.y, STRUCTURE_STORAGE); - } -}; diff --git a/src/RoomPlanner/Blueprints/Extensions.ts b/src/RoomPlanner/Blueprints/Extensions.ts deleted file mode 100644 index 1d965b1..0000000 --- a/src/RoomPlanner/Blueprints/Extensions.ts +++ /dev/null @@ -1,34 +0,0 @@ -const extentionsAvailable = (roomlevel: number) => { - return roomlevel > 2 ? roomlevel * 10 - 20 : (roomlevel - 1) * 5; -}; - -export const buildExtentions = (room: Room) => { - const spawns = room.find(FIND_MY_SPAWNS); - if (spawns.length < 1) return; - const spawn = spawns[0]; - const exts = extentionsAvailable(room.controller?.level ?? 0); - const terrain = room.getTerrain(); - const sqroffset = Math.sqrt(exts) / 2; - for (let x = -Math.floor(sqroffset); x < sqroffset; x++) { - for (let y = -Math.floor(sqroffset); y < sqroffset; y++) { - room.visual.circle(spawn.pos.x + x * 2, spawn.pos.y + y * 2); - if (terrain.get(spawn.pos.x + x * 2 - 1, spawn.pos.y + y * 2 - 1) - !== TERRAIN_MASK_WALL) { - room.createConstructionSite( - spawn.pos.x + x * 2 - 1, spawn.pos.y + y * 2 - 1, STRUCTURE_ROAD); - } - if (terrain.get(spawn.pos.x + x * 2, spawn.pos.y + y * 2 - 1) - !== TERRAIN_MASK_WALL) { - room.createConstructionSite( - spawn.pos.x + x * 2, spawn.pos.y + y * 2 - 1, STRUCTURE_ROAD); - } - if (terrain.get(spawn.pos.x + x * 2 - 1, spawn.pos.y + y * 2) - !== TERRAIN_MASK_WALL) { - room.createConstructionSite( - spawn.pos.x + x * 2 - 1, spawn.pos.y + y * 2, STRUCTURE_ROAD); - } - room.createConstructionSite( - spawn.pos.x + x * 2, spawn.pos.y + y * 2, STRUCTURE_EXTENSION); - } - } -}; diff --git a/src/RoomPlanner/Blueprints/Roads.ts b/src/RoomPlanner/Blueprints/Roads.ts deleted file mode 100644 index abe4136..0000000 --- a/src/RoomPlanner/Blueprints/Roads.ts +++ /dev/null @@ -1,27 +0,0 @@ -export const buildRoads = (room: Room) => { - const rc = room.controller?.level ?? 0; - if (rc < 2) { - return; - } - const sources: _HasRoomPosition[] = room.find(FIND_SOURCES); - const sourcesAndSpawns = sources.concat(room.find(FIND_MY_SPAWNS)); - const sourcesAndMinerals = sources.concat(room.find(FIND_MINERALS)); - room.visual.clear(); - for (const source of sourcesAndSpawns) { - for (const source2 of rc > 4 ? sourcesAndMinerals : sources) { - const path = source.pos.findPathTo(source2, { - ignoreCreeps: true, - ignoreRoads: true, - }); - for (const point of path) { - if ((point.x === source.pos.x && point.y === source.pos.y) - || (point.x === source2.pos.x && point.y === source2.pos.y)) { - continue; - } - room.visual.line(point.x, point.y, - point.x - point.dx, point.y - point.dy); - room.createConstructionSite(point.x, point.y, STRUCTURE_ROAD); - } - } - } -}; diff --git a/src/RoomPlanner/index.ts b/src/RoomPlanner/index.ts new file mode 100644 index 0000000..2fdea09 --- /dev/null +++ b/src/RoomPlanner/index.ts @@ -0,0 +1,448 @@ +import profiler from "screeps-profiler"; + +const roomSize = 50; +const OBSTACLE = 1000; +const UNSET = 999; + +declare global { + interface RoomMemory { + _planner: string + } +} + const structureCoding: (BuildableStructureConstant | null)[] = + [null, STRUCTURE_ROAD, STRUCTURE_CONTAINER, STRUCTURE_EXTENSION, STRUCTURE_FACTORY, + STRUCTURE_EXTRACTOR, STRUCTURE_WALL, STRUCTURE_SPAWN, STRUCTURE_POWER_SPAWN, + STRUCTURE_STORAGE, STRUCTURE_NUKER, STRUCTURE_TERMINAL, STRUCTURE_LAB, + STRUCTURE_LINK, STRUCTURE_TOWER, STRUCTURE_RAMPART]; + +const getCoord = (x: number, y: number): number => { + return x + y * roomSize; +} + +const distanceTransform = (mask: (0 | 999 | 1000)[]): number[] => { + let arr: number[] = new Array(...mask); + for (let i = 0; arr.find((x) => x === UNSET) != null; i++) { + for (let x = 0; x < roomSize; x++) { + for (let y = 0; y < roomSize; y++) { + if (arr[getCoord(x, y)] === i) { + for (let dx = -1; dx < 2; dx++) { + for (let dy = -1; dy < 2; dy++) { + if (x + dx < 0 || y + dy < 0 || x + dx >= 50 || y + dy >= 50 + || arr[getCoord(x, y)] === OBSTACLE) { + continue; + } + if (arr[getCoord(x + dx, y + dy)] === UNSET) { + arr[getCoord(x + dx, y + dy)] = i + 1; + } + } + } + } + } + } + } + return arr; +}; + +/* const renderHeatmap = (mask: number[], visual: RoomVisual) => { + for (let x = 0; x < 50; x++) { + for (let y = 0; y < 50; y++) { + if (mask[getCoord(x, y)] === OBSTACLE) { + continue; + } + visual.rect(x - 0.5, y - 0.5, 1, 1, { + fill: "#" + (127 + mask[getCoord(x, y)] * 3).toString(16) + + 127..toString(16) + + (255 - mask[getCoord(x, y)] * 5).toString(16), + opacity: 0.2 + }).text(mask[getCoord(x, y)].toString(), x, y + 0.25); + } + } +} */ + +const createBuildSites = (room: Room) => { + let structures = new Array(); + for (let i = 0; i < room.memory._planner.length; i++) { + structures.push( + structureCoding[(room.memory._planner.charCodeAt(i) - 32) & 0b11111] + ); + structures.push( + structureCoding[(room.memory._planner.charCodeAt(i) - 32) >> 5] + ); + } + for (let x = 0; x < roomSize; x++) { + for (let y = 0; y < roomSize; y++) { + if ((room.controller?.level ?? 0) < 2 + && structures[getCoord(x, y)] != STRUCTURE_CONTAINER) { + continue; + } + if ((room.controller?.level ?? 0) < 3 + && !(structures[getCoord(x, y)] == STRUCTURE_CONTAINER + || structures[getCoord(x, y)] == STRUCTURE_ROAD + || structures[getCoord(x, y)] == STRUCTURE_EXTENSION)) { + continue; + } + if ((room.controller?.level ?? 0) < 4 + && !(structures[getCoord(x, y)] == STRUCTURE_CONTAINER + || structures[getCoord(x, y)] == STRUCTURE_ROAD + || structures[getCoord(x, y)] == STRUCTURE_EXTENSION + || structures[getCoord(x, y)] == STRUCTURE_RAMPART + || structures[getCoord(x, y)] == STRUCTURE_TOWER)) { + continue; + } + if ((room.controller?.level ?? 0) < 5 + && !(structures[getCoord(x, y)] == STRUCTURE_CONTAINER + || structures[getCoord(x, y)] == STRUCTURE_ROAD + || structures[getCoord(x, y)] == STRUCTURE_EXTENSION + || structures[getCoord(x, y)] == STRUCTURE_RAMPART + || structures[getCoord(x, y)] == STRUCTURE_TOWER + || structures[getCoord(x, y)] == STRUCTURE_WALL)) { + continue; + } + if ((room.controller?.level ?? 0) < 6 + && !(structures[getCoord(x, y)] == STRUCTURE_CONTAINER + || structures[getCoord(x, y)] == STRUCTURE_ROAD + || structures[getCoord(x, y)] == STRUCTURE_EXTENSION + || structures[getCoord(x, y)] == STRUCTURE_RAMPART + || structures[getCoord(x, y)] == STRUCTURE_TOWER + || structures[getCoord(x, y)] == STRUCTURE_WALL + || structures[getCoord(x, y)] == STRUCTURE_STORAGE)) { + continue; + } + if ((room.controller?.level ?? 0) < 8 + && !(structures[getCoord(x, y)] == STRUCTURE_CONTAINER + || structures[getCoord(x, y)] == STRUCTURE_ROAD + || structures[getCoord(x, y)] == STRUCTURE_EXTENSION + || structures[getCoord(x, y)] == STRUCTURE_RAMPART + || structures[getCoord(x, y)] == STRUCTURE_TOWER + || structures[getCoord(x, y)] == STRUCTURE_WALL + || structures[getCoord(x, y)] == STRUCTURE_STORAGE + || structures[getCoord(x, y)] == STRUCTURE_EXTRACTOR)) { + continue; + } + if (structures[getCoord(x, y)] != null) { + if (room.createConstructionSite(x, y, structures[getCoord(x, y)]) + === ERR_FULL) { + return; + } + } + } + } +} + +export default profiler.registerFN(function RoomPlanner(room: Room) { + if (room.controller == null || !room.controller.my) { + return; + } + if (Game.cpu.bucket < 100 && room.name != "sim") { + return; + } + if (room.name != "sim" && Game.time % 113 !== 0) { + return; + } + if (room.memory._planner != null) { + createBuildSites(room); + return; + } + const terrain = room.getTerrain(); + let mask: number[] = new Array(roomSize * roomSize).fill(0); + for (let x = 0; x < roomSize; x++) { + for (let y = 0; y < roomSize; y++) { + mask[getCoord(x, y)] = terrain.get(x, y); + } + } + const wallDistance = distanceTransform( + mask.map((t) => t === TERRAIN_MASK_WALL ? 0 : UNSET)); + const controllerCoord = + (room.controller?.pos.x ?? 0) + (room.controller?.pos.y ?? -1) * roomSize; + const controllerDistance = distanceTransform( + mask.map((t, i) => + i === controllerCoord ? 0 : ( + t === TERRAIN_MASK_WALL ? OBSTACLE : UNSET + )) + ); + const buildCenter = wallDistance.map( + (x, i) => [x * 2.5 - controllerDistance[i], i]).sort( + (a, b) => b[0] - a[0])[0][1]; + const buildCenterX = buildCenter % roomSize; + const buildCenterY = Math.floor(buildCenter / roomSize); + const buildCenterPos = room.getPositionAt(buildCenterX, buildCenterY)!; + /* room.visual.rect(buildCenterX - 0.5, buildCenterY - 0.5, 1, 1, { + stroke: "#FF0000", + }); */ + + // + // Build structures + // + + let structures: (BuildableStructureConstant | null)[] + = new Array(roomSize * roomSize); + + // Build Roads + Containers + const roadTargets = (room.sources as (_HasRoomPosition | null)[]) + .concat([room.controller, room.mineral]) + .concat([room.find(FIND_EXIT_TOP)?.[0], + room.find(FIND_EXIT_LEFT)?.[0], + room.find(FIND_EXIT_RIGHT)?.[0], + room.find(FIND_EXIT_BOTTOM)?.[0]] + .map((pos) => pos == null ? null : ({ pos, highRange: true }))); + for (let target of roadTargets) { + if (target == null) { continue; } + const { path } = PathFinder.search(buildCenterPos, + { pos: target.pos, range: "highRange" in target ? 3 : 1 }, { + swampCost: 10, + plainCost: 2, + roomCallback: function(roomName) { + if (roomName != room.name) { + return false; + } + + let costs = new PathFinder.CostMatrix; + for (let x = 0; x < roomSize; x++) { + for (let y = 0; y < roomSize; y++) { + if (structures[getCoord(x, y)] === STRUCTURE_ROAD) { + costs.set(x, y, 1); + } + } + } + return costs; + } + }); + for (let i = 0; i < path.length; i++) { + const pos = path[i]; + structures[getCoord(pos.x, pos.y)] + = (i === path.length - 1 && "energy" in target) + ? STRUCTURE_CONTAINER : STRUCTURE_ROAD; + } + } + + // Build Core + for (let dx = -2; dx < 3; dx++) { + for (let dy = -2; dy < 3; dy++) { + structures[getCoord(buildCenterX + dx, buildCenterY + dy)] + = STRUCTURE_ROAD; + } + } + structures[getCoord(buildCenterX, buildCenterY)] = STRUCTURE_RAMPART; + structures[getCoord(buildCenterX + 1, buildCenterY)] = STRUCTURE_STORAGE; + structures[getCoord(buildCenterX + 1, buildCenterY - 1)] = STRUCTURE_TERMINAL; + structures[getCoord(buildCenterX, buildCenterY - 1)] = STRUCTURE_LINK; + structures[getCoord(buildCenterX - 1, buildCenterY - 1)] = STRUCTURE_FACTORY; + structures[getCoord(buildCenterX - 1, buildCenterY)] = STRUCTURE_NUKER; + structures[getCoord(buildCenterX - 1, buildCenterY + 1)] = STRUCTURE_SPAWN; + structures[getCoord(buildCenterX, buildCenterY + 1)] = STRUCTURE_POWER_SPAWN; + structures[getCoord(buildCenterX + 1, buildCenterY + 1)] = STRUCTURE_ROAD; + + // Labs + const coreCorners = [ + [buildCenterX - 2, buildCenterY - 2], + [buildCenterX - 2, buildCenterY + 2], + [buildCenterX + 2, buildCenterY - 2], + [buildCenterX + 2, buildCenterY + 2], + ].map(([x, y]) => [x, y, controllerDistance[x + y * roomSize]] + ).sort(([_x, _y, i], [_x2, _y2, j]) => i - j); + + for (let [x, y, i] of coreCorners) { + const directionX = (x - buildCenterX) / Math.abs(x - buildCenterX); + const directionY = (y - buildCenterY) / Math.abs(y - buildCenterY); + let ok = true; + s: for (let dx = 0; Math.abs(dx) < 4; dx += directionX) { + for (let dy = 0; Math.abs(dy) < 4; dy += directionY) { + if ((structures[getCoord(x + dx, y + dy)] == null + || structures[getCoord(x + dx, y + dy)] === STRUCTURE_ROAD) + && mask[getCoord(x + dx, y + dy)] === 0) { + continue; + } + ok = false; + break s; + } + } + if (ok) { + for (let dx = 0; Math.abs(dx) < 5; dx += directionX) { + for (let dy = 0; Math.abs(dy) < 5; dy += directionY) { + if (Math.abs(dx) == Math.abs(dy)) { + structures[getCoord(x + dx, y + dy)] = STRUCTURE_ROAD; + continue; + } + if (Math.abs(dx) === 4 || Math.abs(dy) === 4) { + if (mask[getCoord(x + dx, y + dy)] === 0) { + structures[getCoord(x + dx, y + dy)] = STRUCTURE_ROAD; + } + } + if (!(dx === 0 && Math.abs(dy) === 3) + && !(dy === 0 && Math.abs(dx) === 3)) { + structures[getCoord(x + dx, y + dy)] = STRUCTURE_LAB; + } + } + } + break; + } + } + + // Extensions + let extensions = 0; + a: for (let dx = 0; dx < roomSize / 2; dx++) { + for (let dy = 0; dy < wallDistance[getCoord(buildCenterX, buildCenterY)]; dy++) { + for (let cardinal = 0; cardinal < 4; cardinal++) { + const x = cardinal < 2 ? buildCenterX + dx : buildCenterX - dx; + const y = cardinal % 2 == 0 ? buildCenterY + dy : buildCenterY - dy; + if (extensions >= 60) { + break a; + } + if (structures[getCoord(x, y)] == null + && (mask[getCoord(x, y)] === 0 + || mask[getCoord(x, y)] === TERRAIN_MASK_SWAMP)) { + let ok = false; + s: for (let ddx = -1; ddx < 2; ddx++) { + for (let ddy = -1; ddy < 2; ddy++) { + if (structures[getCoord(x + ddx, y + ddy)] === STRUCTURE_ROAD) { + ok = true; + break s; + } + } + } + if (ok) { + if (x % 2 == y % 3 || x % 3 == y % 2) { + structures[getCoord(x, y)] = STRUCTURE_ROAD; + } else { + structures[getCoord(x, y)] = STRUCTURE_EXTENSION; + extensions++; + } + } + } + } + } + } + + if (room.mineral != null) { + structures[getCoord(room.mineral.pos.x, room.mineral.pos.y)] + = STRUCTURE_EXTRACTOR; + } + + // Walls + let smallestX = roomSize; + let largestX = 0; + let smallestY = roomSize; + let largestY = 0; + for (let x = 0; x < roomSize; x++) { + for (let y = 0; y < roomSize; y++) { + if (structures[getCoord(x, y)] != null + && structures[getCoord(x, y)] != STRUCTURE_ROAD + && structures[getCoord(x, y)] != STRUCTURE_CONTAINER) { + if (x < smallestX) { + smallestX = x; + } + if (x > largestX) { + largestX = x; + } + if (y < smallestY) { + smallestY = y; + } + if (y > largestY) { + largestY = y; + } + } + } + } + + smallestX = Math.max(2, smallestX - 3); + smallestY = Math.max(2, smallestY - 3); + largestX = Math.min(48, largestX + 3); + largestY = Math.min(48, largestY + 3); + + const centerLine = Math.floor(largestY / 2 + smallestY / 2); + + const { path } = PathFinder.search( + room.getPositionAt(smallestX - 1, centerLine + 1)!, + room.getPositionAt(smallestX - 1, centerLine - 1)!, + { + plainCost: 100, + swampCost: 100, + + roomCallback: function(roomName) { + if (roomName != room.name) { + return false; + } + + let costs = new PathFinder.CostMatrix; + for (let x = 0; x < roomSize; x++) { + for (let y = 0; y < roomSize; y++) { + if (mask[getCoord(x, y)] === TERRAIN_MASK_WALL) { + costs.set(x, y, 1); + } + if (structures[getCoord(x, y)] != null) { + if (structures[getCoord(x, y)] == STRUCTURE_ROAD) { + costs.set(x, y, 254); + } else { + costs.set(x, y, 255); + } + } + } + } + for (let x = smallestX; x <= largestX; x++) { + for (let y = smallestY; y <= largestY; y++) { + costs.set(x, y, 255); + } + } + for (let x = 0; x < smallestX; x++) { + costs.set(x, centerLine, 255); + } + + return costs; + }, + }); + + path.push(room.getPositionAt(smallestX - 1, centerLine)!); + for (let i = 0; i < path.length; i++) { + let s = structures[getCoord(path[i].x, path[i].y)] === STRUCTURE_ROAD + || structures[getCoord(path[i].x + 1, path[i].y)] === STRUCTURE_ROAD + || structures[getCoord(path[i].x - 1, path[i].y)] === STRUCTURE_ROAD + || structures[getCoord(path[i].x + 1, path[i].y + 1)] === STRUCTURE_ROAD + || structures[getCoord(path[i].x + 1, path[i].y - 1)] === STRUCTURE_ROAD + || structures[getCoord(path[i].x - 1, path[i].y + 1)] === STRUCTURE_ROAD + || structures[getCoord(path[i].x - 1, path[i].y - 1)] === STRUCTURE_ROAD + || structures[getCoord(path[i].x, path[i].y + 1)] === STRUCTURE_ROAD + || structures[getCoord(path[i].x, path[i].y - 1)] === STRUCTURE_ROAD + ? STRUCTURE_RAMPART + : STRUCTURE_WALL; + if (mask[getCoord(path[i].x, path[i].y)] != TERRAIN_MASK_WALL) { + structures[getCoord(path[i].x, path[i].y)] = s; + } else { + continue; + } + if (mask[getCoord(path[i].x+1, path[i].y)] != TERRAIN_MASK_WALL + && structures[getCoord(path[i].x+1, path[i].y)] != STRUCTURE_RAMPART) { + structures[getCoord(path[i].x+1, path[i].y)] = s; + }if (mask[getCoord(path[i].x-1, path[i].y)] != TERRAIN_MASK_WALL + && structures[getCoord(path[i].x-1, path[i].y)] != STRUCTURE_RAMPART) { + structures[getCoord(path[i].x-1, path[i].y)] = s; + }if (mask[getCoord(path[i].x, path[i].y+1)] != TERRAIN_MASK_WALL + && structures[getCoord(path[i].x, path[i].y+1)] != STRUCTURE_RAMPART) { + structures[getCoord(path[i].x, path[i].y+1)] = s; + }if (mask[getCoord(path[i].x, path[i].y-1)] != TERRAIN_MASK_WALL + && structures[getCoord(path[i].x, path[i].y-1)] != STRUCTURE_RAMPART) { + structures[getCoord(path[i].x, path[i].y-1)] = s; + } + } + + + // Render + // renderHeatmap(controllerDistance, room.visual); + /* for (let x = 0; x < roomSize; x++) { + for (let y = 0; y < roomSize; y++) { + if (structures[getCoord(x, y)] != null) { + room.visual.structure(x, y, structures[getCoord(x, y)]); + } + } + } + room.visual.connectRoads(); */ + + let str = ""; + for (let i = 0; i < structures.length; i += 2) { + str += String.fromCharCode(32 + + (structureCoding.findIndex((s) => s == structures[i])) + + (structureCoding.findIndex((s) => s == structures[i + 1]) << 5) + ); + } + + room.memory._planner = str; +}); diff --git a/src/Tasks/Build.ts b/src/Tasks/Build.ts index b7b6791..46c49b7 100644 --- a/src/Tasks/Build.ts +++ b/src/Tasks/Build.ts @@ -16,7 +16,7 @@ export const runBuild = profiler.registerFN((creep: Creep): TaskStatus => { return TaskStatus.DONE; } - if (creep.store.getUsedCapacity(RESOURCE_ENERGY) === 0) { + if (creep.store.energy === 0) { return TaskStatus.DONE; } @@ -28,7 +28,6 @@ export const runBuild = profiler.registerFN((creep: Creep): TaskStatus => { if (target == null || creep.build(target) === ERR_NOT_IN_RANGE) { creep.travelTo(task.targetPos); - return TaskStatus.IN_PROGRESS; } - return TaskStatus.DONE; + return TaskStatus.IN_PROGRESS; }, "runBuild"); diff --git a/src/Tasks/Pickup.ts b/src/Tasks/Pickup.ts new file mode 100644 index 0000000..1737689 --- /dev/null +++ b/src/Tasks/Pickup.ts @@ -0,0 +1,35 @@ +import { TaskData, TaskStatus, TaskType } from "./Task"; + +export const Pickup + = (target: Resource): TaskData => ({ + target, + targetPos: target.pos, + type: TaskType.Pickup, + options: {}, + data: { resource: target.resourceType }, + }); + +export const runPickup = (creep: Creep): TaskStatus => { + const task = creep.task; + if (task == null) { + return TaskStatus.DONE; + } + if (task.target == null && task.targetPos.roomName == creep.room.name) { + return TaskStatus.DONE; + } + + const target = task.target as Resource; + const resource: ResourceConstant + = (task.data as { resource: ResourceConstant }).resource; + + if (creep.store.getFreeCapacity(resource) == 0) { + return TaskStatus.DONE; + } + + if (target == null + || creep.pickup(target) === ERR_NOT_IN_RANGE) { + creep.travelTo(task.targetPos); + return TaskStatus.IN_PROGRESS; + } + return TaskStatus.DONE; +}; diff --git a/src/Tasks/Task.ts b/src/Tasks/Task.ts index c4ea1ea..9043477 100644 --- a/src/Tasks/Task.ts +++ b/src/Tasks/Task.ts @@ -1,5 +1,5 @@ import { - packId, packPos, unpackId, unpackPos, + packPos, unpackPos, } from "../../deps/screeps-packrat/src/packrat"; export enum TaskType { @@ -9,6 +9,7 @@ export enum TaskType { Transfer, Build, Repair, + Pickup } export enum TaskStatus { diff --git a/src/Tasks/Withdraw.ts b/src/Tasks/Withdraw.ts index ad4fd6f..c78c999 100644 --- a/src/Tasks/Withdraw.ts +++ b/src/Tasks/Withdraw.ts @@ -30,6 +30,9 @@ export const runWithdraw = (creep: Creep): TaskStatus => { if (task == null) { return TaskStatus.DONE; } + if (task.target == null && task.targetPos.roomName == creep.room.name) { + return TaskStatus.DONE; + } const target = task.target as Structure | Tombstone | Ruin; const opts = task.options as WithdrawOptions; diff --git a/src/Tasks/index.ts b/src/Tasks/index.ts index 8df88c2..cdebb87 100644 --- a/src/Tasks/index.ts +++ b/src/Tasks/index.ts @@ -7,6 +7,7 @@ import { runTransfer, Transfer } from "./Transfer"; import { Build, runBuild } from "./Build"; import { Repair, runRepair } from "./Repair"; import profiler from "screeps-profiler"; +import { Pickup, runPickup } from "./Pickup"; export { TaskType, TaskStatus } from "./Task"; declare global { @@ -29,6 +30,8 @@ const runTask = profiler.registerFN((creep: Creep): TaskStatus => { return runBuild(creep); case TaskType.Repair: return runRepair(creep); + case TaskType.Pickup: + return runPickup(creep); default: return TaskStatus.DONE; } @@ -45,12 +48,16 @@ Creep.prototype.run = function (generator?: (creep: Creep) => TaskData | null) { } }; -export default profiler.registerObject({ +const Tasks = { Harvest, Upgrade, Withdraw, Transfer, Build, Repair, + Pickup, ...TaskStatus, -}, "Tasks"); +}; +profiler.registerObject(Tasks, "Tasks"); + +export default Tasks; diff --git a/src/Actions/Util.ts b/src/Workers/Util.ts similarity index 90% rename from src/Actions/Util.ts rename to src/Workers/Util.ts index 7e53c44..8410165 100644 --- a/src/Actions/Util.ts +++ b/src/Workers/Util.ts @@ -1,13 +1,3 @@ -import { Action, Fail } from "../Actions/Action"; - -export const notNull - = (x: T | null | undefined, f: (y: T) => Action): Action => { - if (x == null) { - return Fail; - } - return f(x); - }; - export const closestTowerToFill = (pos: RoomPosition): StructureTower | null => pos.findClosestByRange(FIND_MY_STRUCTURES, { filter: structure => structure.structureType === STRUCTURE_TOWER diff --git a/src/screeps-profiler.d.ts b/src/screeps-profiler.d.ts deleted file mode 100644 index d6d2261..0000000 --- a/src/screeps-profiler.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -declare module "screeps-profiler" { - export const registerFN: (f: T, n?: string) => T; - export const registerObject: (f: T, n?: string) => T; - export const registerClass: (f: T, n?: string) => T; - export const enable: () => void; - export const wrap: (f: () => void) => () => void; -};