1+ // bunkerLayout.ts
2+ // A library for processing human-readable bunker layout maps
3+
4+ /**
5+ * Originally posted to Slack on 19 October 2017 by @sparr
6+ * Ported from JS to TS and improved by @sparr in August 2021
7+ */
8+
9+ // An example layout, one array for buildings, one for the RCL at which to build them
10+ // let bunkerStructures : string[] = [ // let bunkerLevels : string[] = [
11+ // " ..E...E.. ", // " 445233555 ",
12+ // " .EE.EEE.EE. ", // " 44422233555 ",
13+ // ".EE.E.E.E.EE.", // "4442212233555",
14+ // ".E.EEA.EEE.E.", // "4444211335555",
15+ // "E.EEE.T.EEE.E", // "6444413335556",
16+ // ".E.E.T.T.A.E.", // "6664455757666",
17+ // ".EE.NSKMP.E.E", // "6666N456P6666",
18+ // ".E.E.T.T.E.E.", // "7777686866666",
19+ // "E.EEE.T.OLL..", // "7777768686766",
20+ // ".E.EEA.ELL.L.", // "7777787866677",
21+ // ".EE.E.E.L.LL.", // "7788888888877",
22+ // " .EE.E.E.LL. ", // " 88888888888 ",
23+ // " ..E.E.... ", // " 888888888 ",
24+ // ]; // ];
25+ // A similar structure might describe rampart locations and levels
26+
27+ // example usage:
28+ // BunkerLayout.getLayout(bunkerStructures,{rcl:6})
29+ // returns a description of all the structures up to RCL 6:
30+ // {rcl:6,buildings:{road:{pos:[{x:2,y:0},...] },extension:{pos:[{x:4,y:0},...]},spawn:{pos:[{x:5,y:4}]},... }}
31+ // intended to comply with the schema used by https://screeps.admon.dev/building-planner
32+
33+ // maps chacters in the layout arrays to structures
34+ const layoutMappingForward : { [ symbol :string ] :BuildableStructureConstant } = {
35+ 'A' : STRUCTURE_SPAWN ,
36+ 'N' : STRUCTURE_NUKER ,
37+ 'K' : STRUCTURE_LINK ,
38+ 'L' : STRUCTURE_LAB ,
39+ 'E' : STRUCTURE_EXTENSION ,
40+ 'S' : STRUCTURE_STORAGE ,
41+ 'T' : STRUCTURE_TOWER ,
42+ 'O' : STRUCTURE_OBSERVER ,
43+ 'M' : STRUCTURE_TERMINAL ,
44+ 'P' : STRUCTURE_POWER_SPAWN ,
45+ '.' : STRUCTURE_ROAD ,
46+ 'C' : STRUCTURE_CONTAINER ,
47+ 'R' : STRUCTURE_RAMPART ,
48+ 'W' : STRUCTURE_WALL ,
49+ 'X' : STRUCTURE_EXTRACTOR ,
50+ 'F' : STRUCTURE_FACTORY ,
51+ } ;
52+ // maps structures to characters
53+ const layoutMappingReverse : { [ key in BuildableStructureConstant ] :string } = _ . invert ( layoutMappingForward ) ;
54+ // lowercase letters are structure+road
55+ for ( let letter in layoutMappingForward ) {
56+ layoutMappingForward [ letter . toLocaleLowerCase ( ) ] = layoutMappingForward [ letter ] ;
57+ }
58+
59+ export interface BunkerLayoutPos {
60+ x : number ,
61+ y : number ,
62+ }
63+
64+ export interface BunkerLayoutArrayEntry extends BunkerLayoutPos {
65+ rcl ?: number ,
66+ structureType ?: BuildableStructureConstant ,
67+ } ;
68+
69+
70+ /**
71+ * Get all the positions from a layout, optionally for a specific structure type(s), optionally for a specific RCL, optionally as an array
72+ * @param {String[] } [layout] a layout map with structure letters
73+ * @param {BuildableStructureConstant|BuildableStructureConstant[] } [params.structureType] structure(s) to return, optional
74+ * @param {String[] } [params.levelLayout] a layout map with level numbers, optional
75+ * @param {Number } [params.rcl] room control level, optional
76+ * @param {Boolean } [params.asArray=false] results as flat array, optional
77+ * @return {BunkerLayoutResults } object
78+ * @return {{x:Number,y:Number,stuctureType?:String,level?:Number}[] } array of coordinate+type?+level? objects
79+ */
80+ export interface BunkerGetLayoutParams {
81+ structureType ?: BuildableStructureConstant | BuildableStructureConstant [ ] ,
82+ levelLayout ?: string [ ] ,
83+ rcl ?: number ,
84+ asArray ?: boolean ,
85+ }
86+ export interface BunkerLayoutResults {
87+ rcl ?: number ,
88+ buildings :Partial < {
89+ [ structureType in BuildableStructureConstant ] :{
90+ pos :BunkerLayoutPos [ ]
91+ }
92+ } > ,
93+ }
94+ function getLayout ( layout : string [ ] , params ?: BunkerGetLayoutParams ) : any
95+ {
96+ const height = layout . length ;
97+ const width = layout [ 0 ] . length ;
98+ params ||= { } ;
99+ if ( typeof ( params . structureType ) == "string" ) params . structureType = [ params . structureType ] ;
100+ // convert [road,container,extension] into {.:road,C:container,E:extension}
101+ const structureTypesMap = new Map ( ( params . structureType || [ ] ) . map ( ( s :BuildableStructureConstant ) => [ layoutMappingReverse [ s ] , s ] ) ) ;
102+ const results : BunkerLayoutResults = { buildings :{ } } ;
103+ if ( params . rcl ) results . rcl = params . rcl ;
104+ for ( let y = 0 ; y < height ; y ++ ) {
105+ for ( let x = 0 ; x < width ; x ++ ) {
106+ if ( params . levelLayout && params . rcl && params . rcl < parseInt ( params . levelLayout [ y ] [ x ] ) ) continue ;
107+ const layoutChar = layout [ y ] [ x ] ;
108+ const structureChar = layoutChar . toUpperCase ( ) ;
109+ const structureType = layoutMappingForward [ structureChar ] ;
110+ if ( structureType ) {
111+ const pos = { x :x , y :y } ;
112+ if ( structureTypesMap . size == 0 || structureTypesMap . get ( structureChar ) ) {
113+ ( results . buildings [ structureType ] ||= { pos :[ ] } ) . pos . push ( pos ) ;
114+ }
115+ if ( layoutChar != structureChar && ( structureTypesMap . size == 0 || structureTypesMap . get ( '.' ) ) ) {
116+ // emit a road if the character was the wrong case and we're doing roads or everything
117+ ( results . buildings [ STRUCTURE_ROAD ] ||= { pos :[ ] } ) . pos . push ( pos ) ;
118+ }
119+ }
120+ }
121+ }
122+
123+ if ( ! params . asArray ) return results ;
124+
125+ const resultsArray : BunkerLayoutArrayEntry [ ] = [ ] ;
126+ for ( let structureType in results . buildings ) {
127+ for ( let pos of results . buildings [ structureType as BuildableStructureConstant ] ! . pos ) {
128+ const entry : BunkerLayoutArrayEntry = { x :pos . x , y :pos . y , structureType :structureType as BuildableStructureConstant } ;
129+ if ( ! params . rcl && params . levelLayout ) entry . rcl = parseInt ( params . levelLayout [ pos . y ] [ pos . x ] ) ;
130+ resultsArray . push ( entry ) ;
131+ }
132+ }
133+ return resultsArray ;
134+ } ;
135+
136+ const BunkerLayout = {
137+ layoutMappingForward : layoutMappingForward ,
138+ layoutMappingReverse : layoutMappingReverse ,
139+ getLayout : getLayout ,
140+ }
141+
142+ export default BunkerLayout ;
0 commit comments