From 0a1c3e5de66003d354207808c47dafc3c23ab065 Mon Sep 17 00:00:00 2001 From: "Clarence \"Sparr\" Risher" Date: Thu, 28 Sep 2017 00:03:16 -0700 Subject: [PATCH] new tower placement algorithm, fixes bugs and improves --- src/prototype_roomPosition.js | 4 +- src/prototype_room_init.js | 78 ++++++++++++++++++------------- src/prototype_room_memory.js | 87 +++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 35 deletions(-) diff --git a/src/prototype_roomPosition.js b/src/prototype_roomPosition.js index 4bdeaf835..61472f751 100644 --- a/src/prototype_roomPosition.js +++ b/src/prototype_roomPosition.js @@ -1,7 +1,7 @@ 'use strict'; -RoomPosition.prototype.checkTowerFillerPos = function() { - if (this.isBorder(3)) { +RoomPosition.prototype.checkTowerLinkPos = function() { + if (this.isBorder(2)) { return false; } diff --git a/src/prototype_room_init.js b/src/prototype_room_init.js index 14b664930..9bdaae4d1 100644 --- a/src/prototype_room_init.js +++ b/src/prototype_room_init.js @@ -166,62 +166,72 @@ Room.prototype.setPosition = function(type, pos, value, positionType = 'structur this.setMemoryCostMatrix(costMatrix); }; -Room.prototype.setTowerFillerIterate = function(roomName, offsetDirection) { - let linkSet = false; - let towerFillerSet = false; - let positionsFound = false; - const path = this.getMemoryPath('pathStart-' + roomName); +/** + * Places one tower, filler, link along the path from a specific exit. + * + * @param {String} roomName + * @param {Number} offsetDirection (-1 or +1) + * @return {Boolean} success + */ +Room.prototype.setTowerIterate = function(roomName, offsetDirection) { + const path = this.getMemoryPathSidewalk('pathStart-' + roomName, offsetDirection); + let linkPos = null; + let fillerPos = null; for (let pathIndex = path.length - 1; pathIndex >= 1; pathIndex--) { const posPath = path[pathIndex]; - const posPathObject = new RoomPosition(posPath.x, posPath.y, posPath.roomName); - const posPathNext = path[pathIndex - 1]; - - const directionNext = posPathObject.getDirectionTo(posPathNext.x, posPathNext.y, posPathNext.roomName); - - const pos = posPathObject.getAdjacentPosition(directionNext + offsetDirection); + const pos = new RoomPosition(posPath.x, posPath.y, posPath.roomName); + const terrain = pos.lookFor(LOOK_TERRAIN)[0]; - if (!pos.checkTowerFillerPos()) { + if (terrain === 'wall' || !pos.checkTowerLinkPos() || pos.isEqualTo(linkPos) || pos.isEqualTo(fillerPos)) { + linkPos = null; + fillerPos = null; continue; } - const terrain = pos.lookFor(LOOK_TERRAIN)[0]; - if (terrain === 'wall') { - break; - } - - if (!linkSet) { - this.setPosition('link', pos, config.layout.structureAvoid); - linkSet = true; + if (linkPos === null) { + linkPos = pos; continue; } - if (!towerFillerSet) { - this.setPosition('towerfiller', pos, config.layout.creepAvoid, 'creep'); - towerFillerSet = true; + + if (fillerPos === null) { + fillerPos = pos; continue; } + + this.setPosition('link', linkPos, config.layout.structureAvoid); + this.setPosition('towerfiller', fillerPos, config.layout.creepAvoid, 'creep'); this.setPosition('tower', pos, config.layout.structureAvoid); - positionsFound = true; - break; + return true; } - return positionsFound; + return false; }; Room.prototype.setTowerFiller = function() { const exits = _.map(Game.map.describeExits(this.name)); this.memory.position.creep.towerfiller = []; - for (let index = 0; index < CONTROLLER_STRUCTURES.tower[8] - 1; index++) { + let towersPlaced = 0; + let towersPlacedThisRound = 0; + for (let index = 0; towersPlaced < CONTROLLER_STRUCTURES.tower[8] - 1; index++) { + if (index % (exits.length * 2) === 0) { + if (index > 0 && towersPlacedThisRound === 0) { + // tried every exit, both sides, placed no towers, nowhere left to try + return false; + } + towersPlacedThisRound = 0; + } const roomName = exits[index % exits.length]; if (!roomName) { - break; + return false; } - for (let offsetDirection = 2; offsetDirection < 7; offsetDirection += 4) { - if (this.setTowerFillerIterate(roomName, offsetDirection)) { - break; - } + const offsetDirection = (Math.floor(index / exits.length) % 2) * 2 - 1; + if (this.setTowerIterate(roomName, offsetDirection)) { + towersPlaced++; + towersPlacedThisRound++; } } + return true; }; Room.prototype.checkLabStructures = function(structurePos, pathPos) { @@ -339,7 +349,9 @@ Room.prototype.setStructuresIteratePos = function(structurePos, pathI, path) { }; Room.prototype.setStructures = function(path) { - this.setTowerFiller(); + if (!this.setTowerFiller()) { + this.log('Failed to place all towers'); + } for (let pathI = 0; pathI < path.length; pathI++) { const pathPos = new RoomPosition(path[pathI].x, path[pathI].y, this.name); diff --git a/src/prototype_room_memory.js b/src/prototype_room_memory.js index 100b9912f..83ad78971 100644 --- a/src/prototype_room_memory.js +++ b/src/prototype_room_memory.js @@ -151,6 +151,93 @@ Room.prototype.getMemoryPath = function(name) { return false; }; +/** + * Returns a pseudo-path including every tile adjacent to one side of the given path + * + * @param {String} name - the name of the path + * @param {Number} side - +1 or -1 indicating which side of the path + * @return {array|boolean} path + */ +Room.prototype.getMemoryPathSidewalk = function(name, side = 1) { + const path = this.getMemoryPath(name); + if (!path) { + return false; + } + const sidewalk = []; + let prevDirection = null; + for (let pathIndex = 0; pathIndex < path.length; pathIndex++) { + const posPath = path[pathIndex]; + const posPathObject = new RoomPosition(posPath.x, posPath.y, posPath.roomName); + const posPathNext = pathIndex < path.length - 1 ? path[pathIndex + 1] : null; + const directionNext = pathIndex < path.length - 1 ? + posPathObject.getDirectionTo(posPathNext.x, posPathNext.y, posPathNext.roomName) : + prevDirection; + prevDirection = prevDirection === null ? directionNext : prevDirection; + + if (directionNext === prevDirection) { + // straight line + sidewalk.push(posPathObject.getAdjacentPosition(directionNext + side * 2 + 8)); + if (directionNext % 2 === 0) { + // diagonal + sidewalk.push(posPathObject.getAdjacentPosition(directionNext + side + 8)); + } + } else { + // corner + if (prevDirection % 2 === 0) { + if (directionNext % 2 === 0) { + // diagonal to diagonal + if ((directionNext - prevDirection + 8) % 8 === (side * 2 + 8) % 8) { + // turn towards side + // do nothing + } else { + // turn away from side + sidewalk.push(posPathObject.getAdjacentPosition(prevDirection + side * 2 + 8)); + sidewalk.push(posPathObject.getAdjacentPosition(prevDirection + side + 8)); + sidewalk.push(posPathObject.getAdjacentPosition(prevDirection)); + sidewalk.push(posPathObject.getAdjacentPosition(prevDirection - side + 8)); + } + } else { + // diagonal to orthogonal + if ((directionNext - prevDirection + 8) % 8 === (side + 8) % 8) { + // turn towards side + // do nothing + } else { + // turn away from side + sidewalk.push(posPathObject.getAdjacentPosition(prevDirection + side * 2 + 8)); + sidewalk.push(posPathObject.getAdjacentPosition(prevDirection + side + 8)); + } + } + } else { + if (directionNext % 2 === 0) { + // orthogonal to diagonal + if ((directionNext - prevDirection + 8) % 8 === (side + 8) % 8) { + // turn towards side + sidewalk.push(posPathObject.getAdjacentPosition(prevDirection + side * 2 + 8)); + } else { + // turn away from side + sidewalk.push(posPathObject.getAdjacentPosition(prevDirection + side * 2 + 8)); + sidewalk.push(posPathObject.getAdjacentPosition(prevDirection + side + 8)); + sidewalk.push(posPathObject.getAdjacentPosition(prevDirection)); + } + } else { + // orthogonal to orthogonal + if ((directionNext - prevDirection + 8) % 8 === (side * 2 + 8) % 8) { + // turn towards side + pathIndex++; + } else { + // turn away from side + sidewalk.push(posPathObject.getAdjacentPosition(prevDirection + side * 2 + 8)); + sidewalk.push(posPathObject.getAdjacentPosition(prevDirection + side + 8)); + sidewalk.push(posPathObject.getAdjacentPosition(prevDirection)); + } + } + } + } + prevDirection = directionNext; + } + return sidewalk; +}; + /** * Cleans the cache and memory from all paths */