From fea3ee3429fc39be17df8374fcffc1caad4b3062 Mon Sep 17 00:00:00 2001 From: "Clarence \"Sparr\" Risher" <sparr0@gmail.com> Date: Sun, 29 Aug 2021 17:46:21 -1000 Subject: [PATCH] Replace bunkerLayoutsHumanReadable.js with BunkerLayout.ts --- README.md | 2 +- .../JavaScript/bunkerLayoutsHumanReadable.js | 167 ------------------ src/misc/TypeScript/BunkerLayout.ts | 142 +++++++++++++++ 3 files changed, 143 insertions(+), 168 deletions(-) delete mode 100644 src/misc/JavaScript/bunkerLayoutsHumanReadable.js create mode 100644 src/misc/TypeScript/BunkerLayout.ts diff --git a/README.md b/README.md index b61e8c5..a427752 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,6 @@ For pull requests, we use [GitConsensus](https://www.gitconsensus.com/) to allow | folder | name |author |Description | | ----- |---------| -------|----------------------- | |JS| [actually commented evil tower code.js](/src/misc/JavaScript/actually%20commented%20evil%20tower%20code.js) | daboross| lodash chain tower code| -|JS| [bunkerLayoutsHumanReadable.js](/src/misc/JavaScript/bunkerLayoutsHumanReadable.js) |sparr| readable bunker layouts sample| |JS| [Calculate Cost of a Mine.js](/src/misc/JavaScript/Calculate%20Cost%20of%20a%20Mine.js) |Gankdalf| mining cost calculations| |JS| [Check if room is a source keeper room.js](/src/misc/JavaScript/Check%20if%20room%20is%20a%20source%20keeper%20room.js) |issacar|check if room is a source keeper room| |JS| [colors.js](/src/misc/JavaScript/colors.js) |dissi| visualize percentage with colors| @@ -114,6 +113,7 @@ For pull requests, we use [GitConsensus](https://www.gitconsensus.com/) to allow |TS| [Creep intent tracker.ts](/src/misc/TypeScript/Creep%20intent%20tracker.ts) |unfleshedone|intent tracker implementation| |TS| [moving.average.ts](/src/misc/TypeScript/moving.average.ts) |unsleshedone|moving average implementation| |TS| [Typescript roomScan.ts](/src/misc/TypeScript/Typescript%20roomScan.ts) |crzytrane|room scanner?| +|TS| [BunkerLayout.ts](/src/misc/TypeScript/BunkerLayout.ts) |sparr| parse human-readable readable bunker layout strings| || [migrate room to sim.md](/src/misc/migrate%20room%20to%20sim.md) |semperrabbit|how to migrate room to sim| || [screeps body calculator.md](/src/misc/screeps%20body%20calculator.md) |nitroevil|link to creep calculator| |KT| [DistanceTransform](src/misc/Kotlin/DistanceTransform/) |Vipo|Algoritm for finding open areas in rooms| diff --git a/src/misc/JavaScript/bunkerLayoutsHumanReadable.js b/src/misc/JavaScript/bunkerLayoutsHumanReadable.js deleted file mode 100644 index 476c1df..0000000 --- a/src/misc/JavaScript/bunkerLayoutsHumanReadable.js +++ /dev/null @@ -1,167 +0,0 @@ -/** - * Posted 19 October 2017 by @sparr - */ - -// maps letters in the layout arrays to structures and vice versa -exports.layoutKey = { - 'A': STRUCTURE_SPAWN, - 'N': STRUCTURE_NUKER, - 'K': STRUCTURE_LINK, - 'L': STRUCTURE_LAB, - 'E': STRUCTURE_EXTENSION, - 'S': STRUCTURE_STORAGE, - 'T': STRUCTURE_TOWER, - 'O': STRUCTURE_OBSERVER, - 'M': STRUCTURE_TERMINAL, - 'P': STRUCTURE_POWER_SPAWN, - '.': STRUCTURE_ROAD, - 'C': STRUCTURE_CONTAINER, - 'R': STRUCTURE_RAMPART, - 'W': STRUCTURE_WALL, -}; -_.merge(exports.layoutKey, _.invert(exports.layoutKey)); - -// the preferred layout, if there's enough room -exports.bunkerLayout = [ - ' ..E...E.. ', - ' .EE.EEE.EE. ', - '.EE.E.E.E.EE.', - '.E.EEA.EEE.E.', - 'E.EEE.T.EEE.E', - '.E.E.T.T.A.E.', - '.EE.NSKMP.E.E', - '.E.E.T.T.E.E.', - 'E.EEE.T.OLL..', - '.E.EEA.ELL.L.', - '.EE.E.E.L.LL.', - ' .EE.E.E.LL. ', - ' ..E.E.... ', -]; - -exports.bunkerExtensionOrder = [ - ' 3 7 ', - ' 43 447 78 ', - ' 43 2 4 7 78 ', - ' 3 24 887 7 ', - '3 242 887 7', - ' 4 2 7 ', - ' 44 8 8', - ' 5 5 8 8 ', - '5 566 ', - ' 5 56 6 ', - ' 65 5 6 ', - ' 65 5 6 ', - ' 6 6 ', -]; - -exports.bunkerRoadOrder = [ - ' .. ... .. ', - ' . 2 7 . ', - '. 2 2 7 7 .', - '. 2 2 7 .', - ' 2 2 3 7 ', - '. 2 2 3 7 7 .', - '. 2 7 8 ', - '. 5 5 . . 8 .', - ' 5 5 . ..', - '. 5 5 . .', - '. 5 5 6 . .', - ' . 5 6 . . ', - ' .. . .... ', -]; - -exports.bunkerRampartOrder = [ - ' 555555555 ', - ' 55777777755 ', - '5577777777755', - '57777 77775', - '5777 3 7775', - '577 333 775', - '577 33333 775', - '577 333 775', - '5777 3 7775', - '57777 77775', - '5577777777755', - ' 55777777755 ', - ' 555555555 ', -]; - -// just the core of the bunker, plus two spawns -exports.coreLayout = [ - ' . ', - ' AT. ', - ' .T.T. ', - '.NSKMP.', - ' .T.T. ', - ' .TAO ', - ' . ', -]; - -// just the lab block, for placement elsewhere if necessary -exports.labLayout = [ - ' LL.', - 'LL.L', - 'L.LL', - '.LL ', -]; - -// rapid-fill extension block, if there's room -exports.extensionLayout = [ - ' EEE ', - ' EErrEE ', - ' EErEErEE ', - ' EErEEErrEE', - 'EErECECEErE', - ' rEEEKEEEr ', - 'ErEECECErEE', - 'EErrEEErEE ', - ' EErEErEE ', - ' EErrEE ', - ' EEE ', -]; - -/** - * Get all the positions for a certain structure/letter from a layout - * @param {String[]} layout - * @param {String|String} char letter or structure to return, optional - * @return {{x:Number,y:Number}[]} array of coordinate objects - * @return {Object} map of structure types to arrays of coordinate objects - */ -exports.getPositions = function(layout, char) { - if (typeof(char) === 'string') { - char = [char]; - } - const height = layout.length; - const width = layout[0].length; - const top = height / 2 | 0; - const left = width / 2 | 0; - if (char instanceof Array) { - const positions = []; - for (let c of char) { - if (c.length>1) { - if (c in exports.layoutKey) { - c = exports.layoutKey[c]; - } else { - continue; - } - } - for (let y = 0; y < height; y++) { - for (let x = 0; x < width; x++) { - if (layout[y][x] === c) { - positions.push({x: x-left, y: y-top}); - } - } - } - } - return positions; - } else { - const positions = {}; - for (let y = 0; y < height; y++) { - for (let x = 0; x < width; x++) { - const char = layout[y][x]; - positions[exports.layoutKey[char]] = positions[exports.layoutKey[char]] || []; - positions[exports.layoutKey[char]].push({x: x-left, y: y-top}); - } - } - } -}; diff --git a/src/misc/TypeScript/BunkerLayout.ts b/src/misc/TypeScript/BunkerLayout.ts new file mode 100644 index 0000000..21ecb19 --- /dev/null +++ b/src/misc/TypeScript/BunkerLayout.ts @@ -0,0 +1,142 @@ +// bunkerLayout.ts +// A library for processing human-readable bunker layout maps + +/** + * Originally posted to Slack on 19 October 2017 by @sparr + * Ported from JS to TS and improved by @sparr in August 2021 + */ + +// An example layout, one array for buildings, one for the RCL at which to build them +// let bunkerStructures : string[] = [ // let bunkerLevels : string[] = [ +// " ..E...E.. ", // " 445233555 ", +// " .EE.EEE.EE. ", // " 44422233555 ", +// ".EE.E.E.E.EE.", // "4442212233555", +// ".E.EEA.EEE.E.", // "4444211335555", +// "E.EEE.T.EEE.E", // "6444413335556", +// ".E.E.T.T.A.E.", // "6664455757666", +// ".EE.NSKMP.E.E", // "6666N456P6666", +// ".E.E.T.T.E.E.", // "7777686866666", +// "E.EEE.T.OLL..", // "7777768686766", +// ".E.EEA.ELL.L.", // "7777787866677", +// ".EE.E.E.L.LL.", // "7788888888877", +// " .EE.E.E.LL. ", // " 88888888888 ", +// " ..E.E.... ", // " 888888888 ", +// ]; // ]; +// A similar structure might describe rampart locations and levels + +// example usage: +// BunkerLayout.getLayout(bunkerStructures,{rcl:6}) +// returns a description of all the structures up to RCL 6: +// {rcl:6,buildings:{road:{pos:[{x:2,y:0},...]},extension:{pos:[{x:4,y:0},...]},spawn:{pos:[{x:5,y:4}]},...}} +// intended to comply with the schema used by https://screeps.admon.dev/building-planner + +// maps chacters in the layout arrays to structures +const layoutMappingForward : { [symbol:string]:BuildableStructureConstant } = { + 'A': STRUCTURE_SPAWN, + 'N': STRUCTURE_NUKER, + 'K': STRUCTURE_LINK, + 'L': STRUCTURE_LAB, + 'E': STRUCTURE_EXTENSION, + 'S': STRUCTURE_STORAGE, + 'T': STRUCTURE_TOWER, + 'O': STRUCTURE_OBSERVER, + 'M': STRUCTURE_TERMINAL, + 'P': STRUCTURE_POWER_SPAWN, + '.': STRUCTURE_ROAD, + 'C': STRUCTURE_CONTAINER, + 'R': STRUCTURE_RAMPART, + 'W': STRUCTURE_WALL, + 'X': STRUCTURE_EXTRACTOR, + 'F': STRUCTURE_FACTORY, +}; +// maps structures to characters +const layoutMappingReverse : { [key in BuildableStructureConstant]:string } = _.invert(layoutMappingForward); +// lowercase letters are structure+road +for(let letter in layoutMappingForward) { + layoutMappingForward[letter.toLocaleLowerCase()]=layoutMappingForward[letter]; +} + +export interface BunkerLayoutPos { + x: number, + y: number, +} + +export interface BunkerLayoutArrayEntry extends BunkerLayoutPos { + rcl?: number, + structureType?: BuildableStructureConstant, +}; + + +/** + * Get all the positions from a layout, optionally for a specific structure type(s), optionally for a specific RCL, optionally as an array + * @param {String[]} [layout] a layout map with structure letters + * @param {BuildableStructureConstant|BuildableStructureConstant[]} [params.structureType] structure(s) to return, optional + * @param {String[]} [params.levelLayout] a layout map with level numbers, optional + * @param {Number} [params.rcl] room control level, optional + * @param {Boolean} [params.asArray=false] results as flat array, optional + * @return {BunkerLayoutResults} object + * @return {{x:Number,y:Number,stuctureType?:String,level?:Number}[]} array of coordinate+type?+level? objects + */ + export interface BunkerGetLayoutParams { + structureType?: BuildableStructureConstant | BuildableStructureConstant[], + levelLayout?: string[], + rcl?: number, + asArray?: boolean, +} +export interface BunkerLayoutResults { + rcl?: number, + buildings:Partial<{ + [structureType in BuildableStructureConstant]:{ + pos:BunkerLayoutPos[] + } + }>, +} +function getLayout(layout: string[], params?: BunkerGetLayoutParams): any +{ + const height = layout.length; + const width = layout[0].length; + params||={}; + if(typeof(params.structureType) == "string") params.structureType = [params.structureType]; + // convert [road,container,extension] into {.:road,C:container,E:extension} + const structureTypesMap = new Map((params.structureType||[]).map((s:BuildableStructureConstant)=>[layoutMappingReverse[s],s])); + const results: BunkerLayoutResults = {buildings:{}}; + if(params.rcl) results.rcl = params.rcl; + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + if (params.levelLayout && params.rcl && params.rcl < parseInt(params.levelLayout[y][x])) continue; + const layoutChar = layout[y][x]; + const structureChar = layoutChar.toUpperCase(); + const structureType = layoutMappingForward[structureChar]; + if(structureType) { + const pos = {x:x, y:y}; + if(structureTypesMap.size==0 || structureTypesMap.get(structureChar)) { + (results.buildings[structureType]||={pos:[]}).pos.push(pos); + } + if (layoutChar != structureChar && (structureTypesMap.size == 0 || structureTypesMap.get('.'))) { + // emit a road if the character was the wrong case and we're doing roads or everything + (results.buildings[STRUCTURE_ROAD]||={pos:[]}).pos.push(pos); + } + } + } + } + + if (!params.asArray) return results; + + const resultsArray: BunkerLayoutArrayEntry[] = []; + for(let structureType in results.buildings) { + for(let pos of results.buildings[structureType as BuildableStructureConstant]!.pos) { + const entry: BunkerLayoutArrayEntry = {x:pos.x, y:pos.y, structureType:structureType as BuildableStructureConstant}; + if (!params.rcl && params.levelLayout) entry.rcl = parseInt(params.levelLayout[pos.y][pos.x]); + resultsArray.push(entry); + } + } + return resultsArray; +}; + +const BunkerLayout = { + layoutMappingForward: layoutMappingForward, + layoutMappingReverse: layoutMappingReverse, + getLayout: getLayout, +} + +export default BunkerLayout; \ No newline at end of file