@thegraid/hexlib 1.0.9 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/game-play.d.ts +10 -4
- package/dist/game-play.d.ts.map +1 -1
- package/dist/game-play.js +12 -2
- package/dist/game-play.js.map +1 -1
- package/dist/hex.d.ts +145 -81
- package/dist/hex.d.ts.map +1 -1
- package/dist/hex.js +255 -175
- package/dist/hex.js.map +1 -1
- package/dist/table-params.js +1 -1
- package/dist/table-params.js.map +1 -1
- package/dist/table.d.ts +7 -4
- package/dist/table.d.ts.map +1 -1
- package/dist/table.js +13 -10
- package/dist/table.js.map +1 -1
- package/dist/tile.d.ts +5 -0
- package/dist/tile.d.ts.map +1 -1
- package/dist/tile.js +6 -1
- package/dist/tile.js.map +1 -1
- package/package.json +1 -1
package/dist/hex.js
CHANGED
|
@@ -7,7 +7,7 @@ export const S_Resign = 'Hex@Resign';
|
|
|
7
7
|
export const S_Skip = 'Hex@skip ';
|
|
8
8
|
export function newHSC(hex, sc, Aname = hex.Aname) { return { Aname, hex, sc }; }
|
|
9
9
|
/** to recognize this class in hexUnderPoint and obtain the associated Hex2. */
|
|
10
|
-
class HexCont extends Container {
|
|
10
|
+
export class HexCont extends Container {
|
|
11
11
|
hex2;
|
|
12
12
|
constructor(hex2) {
|
|
13
13
|
super();
|
|
@@ -95,8 +95,9 @@ export class Hex {
|
|
|
95
95
|
col;
|
|
96
96
|
/** Link to neighbor in each H.dirs direction [NE, E, SE, SW, W, NW] */
|
|
97
97
|
links = {};
|
|
98
|
+
metaLinks; // defined only for the center Hex of a metaHex
|
|
98
99
|
get linkDirs() { return Object.keys(this.links); }
|
|
99
|
-
/**
|
|
100
|
+
/** Hex(playerColor)@rcs */
|
|
100
101
|
toString() {
|
|
101
102
|
return `Hex@${this.rcs}`; // hex.toString => Hex@[r,c] | Hex@Skip , Hex@Resign
|
|
102
103
|
}
|
|
@@ -137,9 +138,10 @@ export class Hex {
|
|
|
137
138
|
forEachHexDir(func) {
|
|
138
139
|
this.linkDirs.forEach((dir) => this.hexesInDir(dir).filter(hex => !!hex).map(hex => func(hex, dir, this)));
|
|
139
140
|
}
|
|
140
|
-
|
|
141
|
+
/** from this Hex, follow links[ds], ns times. */
|
|
142
|
+
nextHex(dir, ns = 1) {
|
|
141
143
|
let hex = this;
|
|
142
|
-
while (!!(hex = hex.links[
|
|
144
|
+
while (!!(hex = hex.links[dir]) && --ns > 0) { }
|
|
143
145
|
return hex;
|
|
144
146
|
}
|
|
145
147
|
/** return last Hex on axis in given direction */
|
|
@@ -170,13 +172,13 @@ export class Hex1 extends Hex {
|
|
|
170
172
|
get meep() { return this._meep; }
|
|
171
173
|
set meep(meep) { this._meep = meep; }
|
|
172
174
|
get occupied() { return (this.tile || this.meep) ? [this.tile, this.meep] : undefined; }
|
|
173
|
-
/**
|
|
174
|
-
toString(
|
|
175
|
-
return `${
|
|
175
|
+
/** COLOR@[r,c]; COLOR = this.(tile??meep).player.color ?? Empty */
|
|
176
|
+
toString(color = (this.tile ?? this.meep)?.player?.color ?? 'Empty') {
|
|
177
|
+
return `${color}@${this.rcs}`; // hex.toString => COLOR@[r,c] | COLOR@Skip , COLOR@Resign
|
|
176
178
|
}
|
|
177
|
-
/**
|
|
178
|
-
rcspString(
|
|
179
|
-
return `${
|
|
179
|
+
/** COLOR@[ r, c] or COLOR@Name */
|
|
180
|
+
rcspString(color = (this.tile ?? this.meep)?.player?.color ?? 'Empty') {
|
|
181
|
+
return `${color}@${this.rcsp}`;
|
|
180
182
|
}
|
|
181
183
|
}
|
|
182
184
|
/** One Hex cell in the game, shown as a polyStar Shape */
|
|
@@ -203,7 +205,7 @@ export class Hex2 extends Hex1 {
|
|
|
203
205
|
distText; // shown on this.cont
|
|
204
206
|
rcText; // shown on this.cont
|
|
205
207
|
setUnit(unit, meep = false) {
|
|
206
|
-
const cont = this.
|
|
208
|
+
const cont = this.mapCont.tileCont, x = this.x, y = this.y;
|
|
207
209
|
let k = true; // debug double tile
|
|
208
210
|
const this_unit = (meep ? this.meep : this.tile);
|
|
209
211
|
if (unit !== undefined && this_unit !== undefined && !(meep && this_unit.recycleVerb === 'demolished')) {
|
|
@@ -256,7 +258,7 @@ export class Hex2 extends Hex1 {
|
|
|
256
258
|
this.showText(true); // & this.cache()
|
|
257
259
|
}
|
|
258
260
|
/** set visibility of rcText & distText */
|
|
259
|
-
showText(vis = this.rcText.visible) {
|
|
261
|
+
showText(vis = !this.rcText.visible) {
|
|
260
262
|
this.rcText.visible = this.distText.visible = vis;
|
|
261
263
|
this.cont.updateCache();
|
|
262
264
|
}
|
|
@@ -278,7 +280,7 @@ export class Hex2 extends Hex1 {
|
|
|
278
280
|
// cont.rotation = this.map.topoRot;
|
|
279
281
|
}
|
|
280
282
|
makeHexShape(shape = HexShape) {
|
|
281
|
-
const hs = new shape(this.radius
|
|
283
|
+
const hs = new shape(this.radius);
|
|
282
284
|
this.cont.addChildAt(hs, 0);
|
|
283
285
|
this.cont.hitArea = hs;
|
|
284
286
|
hs.paint('grey');
|
|
@@ -329,69 +331,86 @@ export class Hex2 extends Hex1 {
|
|
|
329
331
|
}
|
|
330
332
|
export class RecycleHex extends Hex2 {
|
|
331
333
|
}
|
|
332
|
-
/**
|
|
334
|
+
/**
|
|
335
|
+
* A HexShape/PaintableShape to indicate selected hex of HexMap.
|
|
336
|
+
*
|
|
337
|
+
* For contrast paint it (GREY,.3), leave a hole in the middle unpainted.
|
|
338
|
+
*
|
|
339
|
+
* @param radius of this HexShape
|
|
340
|
+
* @param radius0 of removed circle
|
|
341
|
+
* @param cm of HexShape/ring for mark ['rgba(127,127,127,.3)']
|
|
342
|
+
*/
|
|
333
343
|
export class HexMark extends HexShape {
|
|
334
|
-
hexMap;
|
|
335
344
|
hex;
|
|
336
|
-
constructor(
|
|
345
|
+
constructor(radius, radius0 = 0, cm = 'rgba(127,127,127,.3)') {
|
|
337
346
|
super(radius);
|
|
338
|
-
this.
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
return this.graphics; // do not repaint.
|
|
351
|
-
}
|
|
347
|
+
this.graphics.f(cm).dp(0, 0, this.radius, 6, 0, this.tilt);
|
|
348
|
+
this.cache(-radius, -radius, 2 * radius, 2 * radius);
|
|
349
|
+
this.graphics.c().f(C.BLACK).dc(0, 0, radius0);
|
|
350
|
+
this.updateCache("destination-out");
|
|
351
|
+
this.setHexBounds(); // bounds are based on readonly, should be const
|
|
352
|
+
this.mouseEnabled = false;
|
|
353
|
+
}
|
|
354
|
+
// don't invoke Mark.paint(new_color); TODO: remove this override.
|
|
355
|
+
// override paint(color: string): Graphics {
|
|
356
|
+
// this.setHexBounds(); // <--- likely redundant, see HexSHape
|
|
357
|
+
// return this.graphics; // do not repaint.
|
|
358
|
+
// }
|
|
352
359
|
// Fail: markCont to be 'above' tileCont...
|
|
360
|
+
/**
|
|
361
|
+
* Show or hide mark on given hex; and hex.updateCache.
|
|
362
|
+
*
|
|
363
|
+
* (this.hex = hex) ? hex.cont.addChild(this.cont) : this.visible = false
|
|
364
|
+
*/
|
|
353
365
|
showOn(hex) {
|
|
354
366
|
// when mark is NOT showing, this.visible === false && this.hex === undefined.
|
|
355
367
|
// when mark IS showing, this.visible === true && (this.hex instanceof Hex2)
|
|
356
368
|
if (this.hex === hex)
|
|
357
369
|
return;
|
|
358
|
-
|
|
370
|
+
let ohex = this.hex, map = ohex?.map;
|
|
371
|
+
if (ohex) {
|
|
359
372
|
this.visible = false;
|
|
360
|
-
if (!
|
|
373
|
+
if (!ohex.cont.cacheID)
|
|
361
374
|
debugger;
|
|
362
|
-
|
|
375
|
+
ohex.cont.updateCache();
|
|
376
|
+
map = ohex.map;
|
|
363
377
|
}
|
|
364
|
-
|
|
365
|
-
if (this.hex) {
|
|
378
|
+
if (hex) {
|
|
366
379
|
this.visible = true;
|
|
367
380
|
hex.cont.addChild(this);
|
|
368
381
|
if (!hex.cont.cacheID)
|
|
369
382
|
debugger;
|
|
370
383
|
hex.cont.updateCache();
|
|
384
|
+
map = hex.map;
|
|
371
385
|
}
|
|
372
|
-
this.
|
|
386
|
+
this.hex = hex;
|
|
387
|
+
map?.update(); // remove old hex, add new hex
|
|
373
388
|
}
|
|
374
389
|
}
|
|
390
|
+
/** MapCont is an empty Container until .addContainers(cNames) */
|
|
375
391
|
export class MapCont extends Container {
|
|
376
|
-
|
|
377
|
-
constructor(hexMap) {
|
|
392
|
+
constructor() {
|
|
378
393
|
super();
|
|
379
|
-
this.hexMap = hexMap;
|
|
380
394
|
this.name = 'mapCont';
|
|
381
395
|
}
|
|
382
|
-
|
|
396
|
+
/** initial, default, readonly Container names, fields */
|
|
397
|
+
static cNames = ['resaCont', 'hexCont', 'tileCont', 'markCont', 'counterCont'];
|
|
398
|
+
/** actual cNames being used for this MapCont, set in addContainers() */
|
|
399
|
+
_cNames = MapCont.cNames.concat();
|
|
400
|
+
get cNames() { return this._cNames; }
|
|
383
401
|
resaCont; // playerPanels
|
|
384
402
|
hexCont; // hex shapes on bottom stats: addChild(dsText), parent.rotation
|
|
385
|
-
infCont
|
|
403
|
+
// infCont: Container // infMark below tileCont; Hex2.showInf
|
|
386
404
|
tileCont; // Tiles & Meeples on Hex2/HexMap.
|
|
387
405
|
markCont; // showMark over Hex2; LegalMark
|
|
388
|
-
capCont
|
|
406
|
+
// capCont: Container // for tile.capMark
|
|
389
407
|
counterCont; // counters for AuctionCont
|
|
390
|
-
eventCont
|
|
408
|
+
// eventCont: Container// the eventHex & and whatever Tile is on it...
|
|
391
409
|
/** add all the layers of Containers. */
|
|
392
|
-
addContainers() {
|
|
410
|
+
addContainers(cNames = this.cNames) {
|
|
411
|
+
this._cNames = cNames.concat();
|
|
393
412
|
this.removeAllChildren();
|
|
394
|
-
|
|
413
|
+
this.cNames.forEach(cname => {
|
|
395
414
|
const cont = new Container();
|
|
396
415
|
cont.Aname = cont.name = cname;
|
|
397
416
|
this[cname] = cont;
|
|
@@ -401,16 +420,16 @@ export class MapCont extends Container {
|
|
|
401
420
|
/**
|
|
402
421
|
* Set hexCont(x,y) so hexMap.getBounds() is centered around mapCont(0,0);
|
|
403
422
|
*
|
|
404
|
-
* [
|
|
423
|
+
* [Generally, hexCont.centerHex is ~ mapCont(0,0)]
|
|
405
424
|
*
|
|
406
|
-
* Move ALL children of
|
|
407
|
-
* @param hexCont
|
|
425
|
+
* Move ALL children of this MapCont to have that same (x,y) alignment.
|
|
426
|
+
* @param bounds [hexCont.getBounds()] align containers to center of given bounds.
|
|
408
427
|
*/
|
|
409
|
-
centerContainers(
|
|
410
|
-
|
|
411
|
-
const { x, y, width, height } =
|
|
428
|
+
centerContainers(bounds = this.hexCont.getBounds()) {
|
|
429
|
+
// based on aggregate of all added Hex2.cont; == the .cache(bounds);
|
|
430
|
+
const { x, y, width, height } = bounds;
|
|
412
431
|
const x0 = x + width / 2, y0 = y + height / 2;
|
|
413
|
-
|
|
432
|
+
this.cNames.forEach(cname => {
|
|
414
433
|
const cont = this[cname];
|
|
415
434
|
cont.x = -x0;
|
|
416
435
|
cont.y = -y0;
|
|
@@ -431,13 +450,29 @@ export class MapCont extends Container {
|
|
|
431
450
|
*/
|
|
432
451
|
export class HexMap extends Array {
|
|
433
452
|
hexC;
|
|
453
|
+
Aname;
|
|
434
454
|
// A color for each District: 'rgb(198,198,198)'
|
|
435
455
|
static distColor = ['lightgrey', "limegreen", "deepskyblue", "rgb(255,165,0)", "violet", "rgb(250,80,80)", "yellow"];
|
|
456
|
+
/**
|
|
457
|
+
* HexMap: TP.nRows X TP.nCols hexes.
|
|
458
|
+
*
|
|
459
|
+
* Basic map is non-GUI, addToMapCont uses Hex2 elements to enable GUI interaction.
|
|
460
|
+
* @param addToMapCont use Hex2 for Hex, make Containers: hexCont, infCont, markCont, stoneCont
|
|
461
|
+
* @param hexC Constructor<T> for the Hex elements (typed as HexConstructor<Hex> for Typescript...)
|
|
462
|
+
*/
|
|
463
|
+
constructor(radius = TP.hexRad, addToMapCont = false, hexC = Hex, Aname = 'mainMap') {
|
|
464
|
+
super(); // Array<Array<Hex>>()
|
|
465
|
+
this.hexC = hexC;
|
|
466
|
+
this.Aname = Aname;
|
|
467
|
+
this.radius = radius;
|
|
468
|
+
if (addToMapCont)
|
|
469
|
+
this.addToMapCont(this.hexC);
|
|
470
|
+
}
|
|
436
471
|
get asHex2Map() { return this; }
|
|
437
472
|
/** Each occupied Hex, with the occupying PlayerColor */
|
|
438
473
|
district = [];
|
|
439
474
|
hexAry; // set by makeAllDistricts()
|
|
440
|
-
mapCont = new MapCont(
|
|
475
|
+
mapCont = new MapCont(); // if/when using Hex2
|
|
441
476
|
//
|
|
442
477
|
// | // | // |
|
|
443
478
|
// 2 . | 1 // 1 . | .5 // 2/sqrt3 . | 1/sqrt3
|
|
@@ -446,6 +481,7 @@ export class HexMap extends Array {
|
|
|
446
481
|
// -----------------------+ // -----------------------+ // -----------------------+
|
|
447
482
|
// sqrt3 // sqrt3/2 // 1
|
|
448
483
|
//
|
|
484
|
+
allStones = [];
|
|
449
485
|
radius = TP.hexRad;
|
|
450
486
|
/** return this.centerHex.xywh() for this.topo */
|
|
451
487
|
get xywh() { return this.centerHex.xywh(); }
|
|
@@ -453,10 +489,14 @@ export class HexMap extends Array {
|
|
|
453
489
|
maxCol = undefined; // used by rcLinear
|
|
454
490
|
minRow = undefined; // to find centerHex
|
|
455
491
|
maxRow = undefined; // to find centerHex
|
|
492
|
+
get centerRC() {
|
|
493
|
+
const row = Math.floor(((this.maxRow ?? 0) + (this.minRow ?? 0)) / 2);
|
|
494
|
+
const col = Math.floor(((this.minCol ?? 0) + (this.maxCol ?? 0)) / 2);
|
|
495
|
+
return { row, col };
|
|
496
|
+
}
|
|
456
497
|
get centerHex() {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
return this[cr][cc]; // as Hex2; as T;
|
|
498
|
+
const { row, col } = this.centerRC;
|
|
499
|
+
return this[row][col]; // as Hex2; as T;
|
|
460
500
|
}
|
|
461
501
|
// when called, maxRow, etc are defined...
|
|
462
502
|
get nRowCol() { return [(this.maxRow ?? 0) - (this.minRow ?? 0), (this.maxCol ?? 0) - (this.minCol ?? 0)]; }
|
|
@@ -464,41 +504,23 @@ export class HexMap extends Array {
|
|
|
464
504
|
return this.centerHex.lastHex(dn);
|
|
465
505
|
}
|
|
466
506
|
rcLinear(row, col) { return col + row * (1 + (this.maxCol ?? 0) - (this.minCol ?? 0)); }
|
|
467
|
-
metaMap = Array(); // hex0 (center Hex) of each MetaHex, has metaLinks to others.
|
|
468
507
|
mark; // a cached DisplayObject, used by showMark
|
|
469
|
-
Aname = 'mainMap';
|
|
470
|
-
/**
|
|
471
|
-
* HexMap: TP.nRows X TP.nCols hexes.
|
|
472
|
-
*
|
|
473
|
-
* Basic map is non-GUI, addToMapCont uses Hex2 elements to enable GUI interaction.
|
|
474
|
-
* @param addToMapCont use Hex2 for Hex, make Containers: hexCont, infCont, markCont, stoneCont
|
|
475
|
-
* @param hexC Constructor<T> for the Hex elements (typed as HexConstructor<Hex> for Typescript...)
|
|
476
|
-
*/
|
|
477
|
-
constructor(radius = TP.hexRad, addToMapCont = false, hexC = Hex) {
|
|
478
|
-
super(); // Array<Array<Hex>>()
|
|
479
|
-
this.hexC = hexC;
|
|
480
|
-
this.radius = radius;
|
|
481
|
-
if (addToMapCont)
|
|
482
|
-
this.addToMapCont(this.hexC);
|
|
483
|
-
}
|
|
484
|
-
// the 'tilt' to apply to a HexShape to align with map.topo:
|
|
485
|
-
get topoRot() { return TP.useEwTopo ? 30 : 0; }
|
|
486
508
|
makeMark() {
|
|
487
|
-
const mark = new HexMark(this.
|
|
509
|
+
const mark = new HexMark(this.radius, this.radius / 2.5);
|
|
488
510
|
return mark;
|
|
489
511
|
}
|
|
490
512
|
/** create/attach Graphical components for HexMap */
|
|
491
|
-
addToMapCont(hexC) {
|
|
513
|
+
addToMapCont(hexC, cNames) {
|
|
492
514
|
if (hexC)
|
|
493
515
|
this.hexC = hexC;
|
|
516
|
+
this.mapCont.addContainers(cNames);
|
|
494
517
|
this.mark = this.makeMark();
|
|
495
|
-
this.mapCont.addContainers();
|
|
496
518
|
return this;
|
|
497
519
|
}
|
|
498
|
-
/** ...stage
|
|
520
|
+
/** ...stage?.update() */
|
|
499
521
|
update() {
|
|
500
|
-
this.mapCont
|
|
501
|
-
this.mapCont
|
|
522
|
+
this.mapCont?.hexCont?.updateCache(); // when toggleText: hexInspector
|
|
523
|
+
this.mapCont?.stage?.update();
|
|
502
524
|
}
|
|
503
525
|
/** to build this HexMap: create Hex (or Hex2) and link it to neighbors. */
|
|
504
526
|
addHex(row, col, district, hexC = this.hexC) {
|
|
@@ -581,11 +603,30 @@ export class HexMap extends Array {
|
|
|
581
603
|
get linkDirs() {
|
|
582
604
|
return TP.useEwTopo ? H.ewDirs : H.nsDirs;
|
|
583
605
|
}
|
|
606
|
+
/** return a new RC; does not mutate the given RC.
|
|
607
|
+
* @return RC of adjacent Hex in given direction for given topo.
|
|
608
|
+
*/
|
|
584
609
|
nextRowCol(rc, dir, nt = this.topo(rc)) {
|
|
585
610
|
const ntdir = nt[dir];
|
|
586
611
|
const { dr, dc } = ntdir; // OR (nt as TopoEW[dir as EwDir]) OR simply: nt[dir]
|
|
587
|
-
|
|
588
|
-
|
|
612
|
+
return { row: rc.row + dr, col: rc.col + dc };
|
|
613
|
+
}
|
|
614
|
+
metaMap = Array(); // hex0 (center Hex) of each MetaHex, has metaLinks to others.
|
|
615
|
+
addMetaHex(hex, mrc) {
|
|
616
|
+
const metaMap = this.metaMap, { row: mr, col: mc } = mrc;
|
|
617
|
+
if (metaMap[mr] === undefined)
|
|
618
|
+
metaMap[mr] = new Array();
|
|
619
|
+
if (metaMap[mr][mc] === undefined)
|
|
620
|
+
metaMap[mr][mc] = hex;
|
|
621
|
+
this.metaLink(hex, { row: mr, col: mc });
|
|
622
|
+
}
|
|
623
|
+
/** link metaHex on metaMap; maybe need ewTopo for nh==1 ?? */
|
|
624
|
+
metaLink(hex, rc) {
|
|
625
|
+
// planner expects Dir1 & Dir2 in NsDir; nextMetaRC.mrc: NsDir
|
|
626
|
+
let nt = (this.nh == 0) ? H.ewTopo(rc) : H.nsTopo(rc); // always nsTopo!!
|
|
627
|
+
if (!hex.metaLinks)
|
|
628
|
+
hex.metaLinks = {};
|
|
629
|
+
this.link(hex, rc, this.metaMap, nt, (hex) => hex.metaLinks);
|
|
589
630
|
}
|
|
590
631
|
/** link hex to/from each extant neighor */
|
|
591
632
|
link(hex, rc = hex, map = this, nt = this.topo(rc), lf = (hex) => hex.links) {
|
|
@@ -626,19 +667,112 @@ export class HexMap extends Array {
|
|
|
626
667
|
_mh;
|
|
627
668
|
get nh() { return this._nh; }
|
|
628
669
|
get mh() { return this._mh; }
|
|
670
|
+
/** final; set size one time, then it is readonly. */
|
|
671
|
+
setSize(nh = TP.nHexes, mh = TP.mHexes) {
|
|
672
|
+
this._nh = nh;
|
|
673
|
+
this._mh = mh;
|
|
674
|
+
}
|
|
675
|
+
/** utility for makeAllDistricts; make hex0 at RC */
|
|
676
|
+
calculateRC0() {
|
|
677
|
+
// suitable for makeMetaHexes
|
|
678
|
+
const offs = Math.ceil(2 * this.nh * (this.mh - .5)); // row incr could be smaller for EwTopo
|
|
679
|
+
return { row: offs, col: offs }; // row,col to be non-negative
|
|
680
|
+
}
|
|
629
681
|
/**
|
|
630
|
-
*
|
|
682
|
+
* Wrapper for makeAllHexes;
|
|
683
|
+
* setSize, calculateRC0, makeAllHexes, set this.hexAry, centerContainers()
|
|
631
684
|
* @param nh number of hexes on on edge of metaHex
|
|
632
685
|
* @param mh order of metaHexes (greater than 0);
|
|
633
686
|
*/
|
|
634
687
|
makeAllDistricts(nh = TP.nHexes, mh = TP.mHexes) {
|
|
635
|
-
this.
|
|
636
|
-
|
|
637
|
-
const hexAry = this.
|
|
688
|
+
this.setSize(nh, mh);
|
|
689
|
+
const rc0 = this.calculateRC0();
|
|
690
|
+
const hexAry = this.hexAry = this.makeAllHexes(nh, mh, rc0); // nh hexes on outer ring; single meta-hex
|
|
638
691
|
this.mapCont.hexCont && this.mapCont.centerContainers();
|
|
639
|
-
this.hexAry = hexAry;
|
|
640
692
|
return hexAry;
|
|
641
693
|
}
|
|
694
|
+
/**
|
|
695
|
+
* overridable action for makeAllDistricts;
|
|
696
|
+
*
|
|
697
|
+
* Base implementation invokes makeMetaDistrict(nh, mh, rc0)
|
|
698
|
+
* @param nh
|
|
699
|
+
* @param mh
|
|
700
|
+
* @param rc0
|
|
701
|
+
* @return hexAry of the created hexes, becomes hexMap.hexAry
|
|
702
|
+
*/
|
|
703
|
+
makeAllHexes(nh = TP.nHexes, mh = TP.mHexes, rc0) {
|
|
704
|
+
return this.makeMetaHexRings(nh, mh, rc0);
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Make the center district, then make (mh-1) rings other meta-hex districts.
|
|
708
|
+
* @param nh order [number of 'rings'] of meta-hexes (2 or 3 for this game) [TP.mHexes]
|
|
709
|
+
* @param mh size ['rings' in each meta-hex] of meta-hex (1..6) [TP.nHexes]
|
|
710
|
+
* @param rc0 location of initial, central Hex
|
|
711
|
+
* @return
|
|
712
|
+
*/
|
|
713
|
+
makeMetaHexRings(nh = TP.nHexes, mh = TP.mHexes, rc0, mrc = { row: 0, col: 0 }) {
|
|
714
|
+
const dL = nh, dS = (nh - 1), dirs = this.linkDirs;
|
|
715
|
+
const nextMetaRC = (rc, nd) => {
|
|
716
|
+
const dirL = dirs[nd], dirS = dirs[(nd + 5) % 6], metaD = H.nsDirs[(nd + 5) % 6];
|
|
717
|
+
rc = this.forRCsOnLine(dL, rc, dirL); // step (WS) by dist
|
|
718
|
+
rc = this.forRCsOnLine(dS, rc, dirS); // step (S) to center of 0-th metaHex
|
|
719
|
+
mrc = this.nextRowCol(mrc, metaD, H.nsTopo(mrc)); // metaMap uses nsTopo!
|
|
720
|
+
return rc;
|
|
721
|
+
};
|
|
722
|
+
// do metaRing = 0, district 0:
|
|
723
|
+
let district = 0, rc = rc0;
|
|
724
|
+
let hexAry = this.makeMetaHex(nh, district++, rc, mrc); // Central District [0]
|
|
725
|
+
for (let metaRing = 1; metaRing < mh; metaRing++) {
|
|
726
|
+
rc = nextMetaRC(rc, 4); // step in dirs[4] to initial rc (W or WS of previous rc)
|
|
727
|
+
// from rc, for each dir, step dir to center of next metaHex.
|
|
728
|
+
dirs.forEach((dirL, nd) => {
|
|
729
|
+
for (let nhc = 1; nhc <= metaRing; nhc++) {
|
|
730
|
+
rc = nextMetaRC(rc, nd);
|
|
731
|
+
const hexAry2 = this.makeMetaHex(nh, district++, rc, mrc);
|
|
732
|
+
hexAry = hexAry.concat(...hexAry2);
|
|
733
|
+
}
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
return hexAry;
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Make a single metaHex (district) of order nh, at hex[mr, mc]
|
|
740
|
+
*
|
|
741
|
+
* addHex for center and each of nh rings.
|
|
742
|
+
* @param nh order of the metaHex/district
|
|
743
|
+
* @param district identifying number of district
|
|
744
|
+
* @param rc location of center Hex
|
|
745
|
+
* @return array containing all the added Hexes
|
|
746
|
+
*/
|
|
747
|
+
makeMetaHex(nh, district, rc, mrc) {
|
|
748
|
+
const hexAry = Array();
|
|
749
|
+
const hex = this.addHex(rc.row, rc.col, district);
|
|
750
|
+
hexAry.push(hex); // The *center* hex of district
|
|
751
|
+
this.addMetaHex(hex, mrc); // for hexline! (link centers of districts)
|
|
752
|
+
for (let ring = 1; ring < nh; ring++) {
|
|
753
|
+
rc = this.nextRowCol(rc, this.linkDirs[4]);
|
|
754
|
+
// place 'ring' of hexes, addHex along each line:
|
|
755
|
+
rc = this.ringWalk(rc, ring, this.linkDirs, (rc, dir) => {
|
|
756
|
+
hexAry.push(this.addHex(rc.row, rc.col, district));
|
|
757
|
+
return this.nextRowCol(rc, dir);
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
this.setDistrictAndPaint(hexAry, district);
|
|
761
|
+
return hexAry;
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* pickColor and paint all Hexes in hex2Ary
|
|
765
|
+
*
|
|
766
|
+
* Optional special color for center hex of each district
|
|
767
|
+
* @param hex2Aray a Hex2[] of hexes to be colored by pickColor(hexAry)
|
|
768
|
+
* @param district if district == 0, paint with special distColor[0]
|
|
769
|
+
* @param cColor color for center hex, else use dcolor from pickColor(hex2Ary)
|
|
770
|
+
*/
|
|
771
|
+
paintDistrict(hex2Ary, district = 0, cColor) {
|
|
772
|
+
let dcolor = (district == 0) ? HexMap.distColor[0] : this.pickColor(hex2Ary);
|
|
773
|
+
hex2Ary.forEach((hex, n) => hex.setHexColor((n == 0) ? cColor ?? dcolor : dcolor));
|
|
774
|
+
}
|
|
775
|
+
/** find color not used by hex adjacent to given hexAry */
|
|
642
776
|
pickColor(hexAry) {
|
|
643
777
|
let hex = hexAry[0];
|
|
644
778
|
let adjColor = [HexMap.distColor[0]]; // colors not to use
|
|
@@ -653,65 +787,24 @@ export class HexMap extends Array {
|
|
|
653
787
|
});
|
|
654
788
|
return HexMap.distColor.find(ci => !adjColor.includes(ci)) ?? 'white'; // or undefined or ...
|
|
655
789
|
}
|
|
656
|
-
/**
|
|
657
|
-
* Make one meta-hex district.
|
|
790
|
+
/** record hexAry in this.district[district];
|
|
658
791
|
*
|
|
659
|
-
*
|
|
660
|
-
* @param nh order of inner-hex: number hexes on side of meta-hex
|
|
661
|
-
* @param district identifying number of this district
|
|
662
|
-
* @param mr make new district on meta-row
|
|
663
|
-
* @param mc make new district on meta-col
|
|
792
|
+
* paint each Hex using paintDistrict.
|
|
664
793
|
*/
|
|
665
|
-
|
|
666
|
-
const mcp = Math.abs(mc % 2), mrp = Math.abs(mr % 2), dia = 2 * nh - 1;
|
|
667
|
-
// irow-icol define topology of MetaHex composed of HexDistrict
|
|
668
|
-
// TODO: generalize using this.topo to compute offsets!
|
|
669
|
-
const irow = (mr, mc) => {
|
|
670
|
-
let ir = mr * dia - nh * (mcp + 1) + 1;
|
|
671
|
-
ir -= Math.floor((mc) / 2); // - half a row for each metaCol
|
|
672
|
-
return ir;
|
|
673
|
-
};
|
|
674
|
-
const icol = (mr, mc, row) => {
|
|
675
|
-
let np = Math.abs(nh % 2), rp = Math.abs(row % 2);
|
|
676
|
-
let ic = Math.floor(mc * ((nh * 3 - 1) / 2));
|
|
677
|
-
ic += (nh - 1); // from left edge to center
|
|
678
|
-
ic -= Math.floor((mc + (2 - np)) / 4); // 4-metaCol means 2-rows, mean 1-col
|
|
679
|
-
ic += Math.floor((mr - rp) / 2); // 2-metaRow means +1 col
|
|
680
|
-
return ic;
|
|
681
|
-
};
|
|
682
|
-
const hexAry = [];
|
|
683
|
-
hexAry['Mr'] = mr;
|
|
684
|
-
hexAry['Mc'] = mc;
|
|
685
|
-
const row0 = irow(mr, mc), col0 = icol(mr, mc, row0);
|
|
686
|
-
hexAry.push(this.addHex(row0, col0, district)); // make centerHex of metaHex
|
|
687
|
-
//console.groupCollapsed(`makelDistrict [mr: ${mr}, mc: ${mc}] hex0= ${hex.Aname}:${district}-${dcolor}`)
|
|
688
|
-
//console.log(`.makeDistrict: [mr: ${mr}, mc: ${mc}] hex0= ${hex.Aname}`, hex)
|
|
689
|
-
let rc = { row: row0, col: col0 };
|
|
690
|
-
for (let ring = 1; ring < nh; ring++) {
|
|
691
|
-
rc = this.ringWalk(ring, (rc, dir) => {
|
|
692
|
-
// place 'ring' hexes along each axis-line:
|
|
693
|
-
return this.newHexesOnLine(ring, rc, dir, district, hexAry);
|
|
694
|
-
});
|
|
695
|
-
}
|
|
696
|
-
//console.groupEnd()
|
|
697
|
-
this.setDistrictColor(hexAry, district);
|
|
698
|
-
return hexAry;
|
|
699
|
-
}
|
|
700
|
-
setDistrictColor(hexAry, district = 0) {
|
|
794
|
+
setDistrictAndPaint(hexAry, district = 0) {
|
|
701
795
|
this.district[district] = hexAry;
|
|
702
796
|
if (hexAry[0] instanceof Hex2) {
|
|
703
|
-
|
|
704
|
-
const dcolor = district == 0 ? HexMap.distColor[0] : this.pickColor(hex2Ary);
|
|
705
|
-
hex2Ary.forEach(hex => hex.setHexColor(dcolor)); // makeDistrict: dcolor=lightgrey
|
|
797
|
+
this.paintDistrict(hexAry, district);
|
|
706
798
|
}
|
|
707
799
|
}
|
|
708
800
|
/**
|
|
709
|
-
* Make rectangle of hexes
|
|
801
|
+
* Make rectangle of hexes created with this.hexC.
|
|
802
|
+
*
|
|
803
|
+
* Note: district = 0; hexAry.forEach() to set alternate district.
|
|
710
804
|
*
|
|
711
805
|
* rnd == 1 looks best when nc is odd;
|
|
712
806
|
* @param nr height
|
|
713
807
|
* @param nc width [nr + 1]
|
|
714
|
-
* @param district district [0]
|
|
715
808
|
* @param rnd 0: all, 1: rm end of row 0 (& half of last row!)
|
|
716
809
|
* @parma half [(rnd === 1) || (nc % 2 === 1)] force/deny final half-row
|
|
717
810
|
* @param hexAry array in which to push the created Hexes [Array()<T>]
|
|
@@ -726,24 +819,30 @@ export class HexMap extends Array {
|
|
|
726
819
|
const ncOdd = (nc % 2) === 0;
|
|
727
820
|
const c00 = (rnd === 0) ? 0 : 1;
|
|
728
821
|
const nc0 = (rnd === 0) ? 0 : nc - (ncOdd ? 1 : 2 * c00);
|
|
729
|
-
this.
|
|
822
|
+
this.addLineOfHex(nc0, 0, c00, district, hexAry);
|
|
730
823
|
for (let row = 1; row < nr - 1; row++) {
|
|
731
|
-
this.
|
|
824
|
+
this.addLineOfHex(nc, row, 0, district, hexAry);
|
|
732
825
|
}
|
|
733
826
|
const cf0 = (rnd === 0) ? 0 : 2;
|
|
734
827
|
const ncf = nc - ((rnd === 0) ? 0 : 3);
|
|
735
|
-
const
|
|
736
|
-
this.
|
|
737
|
-
this.
|
|
738
|
-
this.hexAry = hexAry;
|
|
828
|
+
const dc = (half) ? 2 : 1;
|
|
829
|
+
this.addLineOfHex(ncf, nr - 1, cf0, district, hexAry, dc);
|
|
830
|
+
this.setDistrictAndPaint(hexAry, district);
|
|
739
831
|
return hexAry;
|
|
740
832
|
}
|
|
741
|
-
/**
|
|
742
|
-
|
|
743
|
-
|
|
833
|
+
/**
|
|
834
|
+
* create horizontal row using hexAry.push(addHex(row, col++dc, district))
|
|
835
|
+
* @param maxc max col to use (esp when dc > 1)
|
|
836
|
+
* @param row
|
|
837
|
+
* @param col
|
|
838
|
+
* @param district
|
|
839
|
+
* @param hexAry
|
|
840
|
+
* @param dc delta to column [1]
|
|
841
|
+
*/
|
|
842
|
+
addLineOfHex(maxc, row, col, district, hexAry, dc = 1) {
|
|
843
|
+
for (let i = 0; i < maxc; i += dc) {
|
|
744
844
|
hexAry.push(this.addHex(row, col + i, district));
|
|
745
845
|
}
|
|
746
|
-
return { row, col };
|
|
747
846
|
}
|
|
748
847
|
/**
|
|
749
848
|
* Select RC location of each Hex on a line, and eval f(rc) => Hex.
|
|
@@ -755,50 +854,31 @@ export class HexMap extends Array {
|
|
|
755
854
|
* @param n number of Hex locations to select
|
|
756
855
|
* @param rc {row, col} of selected location
|
|
757
856
|
* @param dir from rc, move by dir to next location
|
|
758
|
-
* @param f do 'whatever'
|
|
759
|
-
* @returns
|
|
857
|
+
* @param f do 'whatever' based on RC
|
|
858
|
+
* @returns nextRowCol(rc, dir) from the last rc of the line.
|
|
760
859
|
*/
|
|
761
|
-
forRCsOnLine(n, rc, dir, f) {
|
|
860
|
+
forRCsOnLine(n, rc, dir, f = (rc) => { }) {
|
|
762
861
|
for (let i = 0; i < n; i++) {
|
|
763
|
-
|
|
862
|
+
f(rc);
|
|
863
|
+
rc = this.nextRowCol(rc, dir);
|
|
764
864
|
}
|
|
765
865
|
return rc;
|
|
766
866
|
}
|
|
767
867
|
/**
|
|
768
|
-
*
|
|
769
|
-
* @param n number of Hex to create
|
|
770
|
-
* @param rc create first Hex in given RC location
|
|
771
|
-
* @param dir after first Hex move dir for each next Hex
|
|
772
|
-
* @param district supplied to addHex()
|
|
773
|
-
* @param hexAry push created Hex(s) on this array
|
|
774
|
-
* @returns RC of next Hex location on line (typically use next direction and continue...)
|
|
775
|
-
*/
|
|
776
|
-
newHexesOnLine(n, rc, dir, district, hexAry) {
|
|
777
|
-
let hex;
|
|
778
|
-
return this.forRCsOnLine(n, rc, dir, (rc) => {
|
|
779
|
-
hexAry.push(hex = this.addHex(rc.row, rc.col, district));
|
|
780
|
-
return rc;
|
|
781
|
-
});
|
|
782
|
-
}
|
|
783
|
-
/**
|
|
784
|
-
* Apply f(rc, dir) to each of 'n' RCs on nth ring.
|
|
868
|
+
* Apply f(rc, dir) to each of 'n' lines of RCs on nth ring.
|
|
785
869
|
* Step from centerHex by dirs[4], do a line for each dir in dirs.
|
|
786
870
|
*
|
|
787
871
|
* - if topoEW: step to W; make lines going NE, E, SE, SW, W, NW
|
|
788
872
|
* - if topoNS: step to WS; make lines going N, EN, ES, S, WS, WN
|
|
789
|
-
* @param
|
|
790
|
-
* @param
|
|
873
|
+
* @param rc start of first line (heading dirs[0])
|
|
874
|
+
* @param n ring number; number of hexes per line
|
|
791
875
|
* @param dirs [this.linkDirs] each topo dirs in [clockwise] order.
|
|
876
|
+
* @param f (RC, dir) => void; run f(rc) then step to next RC
|
|
792
877
|
* @return the *next* RC on the final line (so can easily spiral)
|
|
793
878
|
*/
|
|
794
|
-
ringWalk(
|
|
795
|
-
const startHex = this.centerHex.nextHex(dirs[4], n);
|
|
796
|
-
let rc = { row: startHex.row, col: startHex.col };
|
|
879
|
+
ringWalk(rc, n, dirs = this.linkDirs, f) {
|
|
797
880
|
dirs.forEach(dir => {
|
|
798
|
-
rc = this.forRCsOnLine(n, rc, dir, (rc) =>
|
|
799
|
-
f(rc, dir);
|
|
800
|
-
return rc;
|
|
801
|
-
});
|
|
881
|
+
rc = this.forRCsOnLine(n, rc, dir, (rc) => f(rc, dir));
|
|
802
882
|
});
|
|
803
883
|
return rc;
|
|
804
884
|
}
|