@woosh/meep-engine 2.31.1 → 2.31.5

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.
Files changed (55) hide show
  1. package/core/binary/BitSet.js +5 -1
  2. package/core/collection/RingBuffer.js +16 -1
  3. package/core/geom/Vector1.js +228 -219
  4. package/core/geom/Vector2.js +547 -502
  5. package/core/geom/Vector3.js +8 -0
  6. package/core/geom/Vector4.js +322 -311
  7. package/core/graph/v2/Graph.js +6 -6
  8. package/core/model/ObservedBoolean.js +12 -4
  9. package/core/process/worker/WorkerBuilder.js +27 -9
  10. package/core/process/worker/WorkerProxy.js +6 -0
  11. package/editor/Editor.js +10 -1
  12. package/editor/process/symbolic/makePositionedIconDisplaySymbol.js +3 -1
  13. package/engine/EngineHarness.js +1 -1
  14. package/engine/ecs/parent/ParentEntitySystem.js +1 -1
  15. package/engine/ecs/terrain/ecs/Terrain.js +11 -2
  16. package/engine/ecs/terrain/ecs/makeTerrainWorkerProxy.js +10 -10
  17. package/engine/graphics/camera/makeOrbitalCameraController.js +7 -1
  18. package/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +4 -31
  19. package/engine/graphics/ecs/mesh/Mesh.js +9 -3
  20. package/engine/graphics/ecs/path/entity/EntityPath.js +7 -7
  21. package/engine/graphics/ecs/trail2d/Trail2DSystem.js +31 -16
  22. package/engine/graphics/micron/build/buildMicronGeometryFromBufferGeometry.js +17 -8
  23. package/engine/graphics/micron/build/graph/metis/metis.js +23 -33
  24. package/engine/graphics/micron/render/v1/MaterialContext.js +21 -2
  25. package/engine/graphics/particles/particular/engine/renderers/billboard/prototypeBillboardRenderer.js +1 -1
  26. package/engine/graphics/particles/particular/engine/simulator/SimulationStepFixedPhysics.js +1 -1
  27. package/engine/graphics/render/buffer/buffers/NormalFrameBuffer.js +25 -16
  28. package/engine/graphics/render/buffer/buffers/prototypeNormalFrameBuffer.js +6 -5
  29. package/engine/graphics/trail/x/RibbonMaterialX.js +7 -2
  30. package/engine/grid/components/GridPosition.js +22 -122
  31. package/engine/grid/components/GridPositionSerializationAdapter.js +58 -0
  32. package/engine/grid/components/GridPositionSerializationUpdater_0_1.js +37 -0
  33. package/engine/intelligence/mcts/MonteCarlo.js +12 -15
  34. package/engine/intelligence/mcts/StateNode.js +3 -3
  35. package/generation/GridTags.js +3 -2
  36. package/generation/example/SampleGenerator0.js +1 -1
  37. package/generation/example/generators/{mir_generator_place_buff_objects.js → interactive/mir_generator_place_buff_objects.js} +97 -26
  38. package/generation/example/generators/mir_generator_place_starting_point.js +12 -5
  39. package/generation/example/grid/configureMirGrid.js +1 -1
  40. package/generation/filtering/CellFilter.js +14 -0
  41. package/generation/filtering/numeric/util/CellFilterLogToConsole.js +2 -1
  42. package/generation/grid/GridData.js +18 -14
  43. package/generation/grid/MarkerMatchCounter.js +23 -0
  44. package/generation/grid/generation/GridTaskApplyActionToCells.js +86 -0
  45. package/generation/grid/generation/grid/select/CellSupplier.js +28 -0
  46. package/generation/grid/generation/grid/select/CellSupplierBestN.js +188 -0
  47. package/generation/grid/generation/grid/select/CellSupplierPathUpHill.js +187 -0
  48. package/generation/markers/GridActionRuleSet.js +1 -1
  49. package/generation/markers/MarkerNode.js +18 -0
  50. package/generation/markers/debug/visualizeMarkers.js +8 -1
  51. package/generation/markers/transform/MarkerNodeTransformerSequence.js +47 -0
  52. package/generation/placement/GridCellActionTransformNearbyMarkers.js +9 -17
  53. package/generation/rules/CellMatcherFromFilter.js +38 -0
  54. package/generation/rules/cell/CellMatcherContainsMarkerWithinRadius.js +1 -1
  55. package/package.json +3 -3
@@ -1,31 +1,32 @@
1
- import { CellMatcherGridPattern } from "../../rules/cell/CellMatcherGridPattern.js";
2
- import { matcher_tag_traversable_unoccupied } from "../rules/matcher_tag_traversable_unoccupied.js";
3
- import { CellMatcherNot } from "../../rules/logic/CellMatcherNot.js";
4
- import { CellMatcherContainsMarkerWithinRadius } from "../../rules/cell/CellMatcherContainsMarkerWithinRadius.js";
5
- import { GridCellActionPlaceTags } from "../../placement/action/GridCellActionPlaceTags.js";
6
- import { GridTags } from "../../GridTags.js";
7
- import { bitwiseAnd } from "../../../core/binary/operations/bitwiseAnd.js";
8
- import { GridCellActionPlaceMarker } from "../../markers/GridCellActionPlaceMarker.js";
9
- import { GridCellPlacementRule } from "../../placement/GridCellPlacementRule.js";
10
- import { GridTaskActionRuleSet } from "../../grid/generation/discrete/GridTaskCellActionRuleSet.js";
11
- import { GridActionRuleSet } from "../../markers/GridActionRuleSet.js";
12
- import { GridCellActionPlaceMarkerGroup } from "../../markers/GridCellActionPlaceMarkerGroup.js";
13
- import { matcher_tag_not_traversable } from "../rules/matcher_tag_not_traversable.js";
14
- import { MarkerNodeMatcherContainsTag } from "../../markers/matcher/MarkerNodeMatcherContainsTag.js";
15
- import { CellMatcherAnd } from "../../rules/logic/CellMatcherAnd.js";
16
- import { MarkerNodeMatcherByType } from "../../markers/matcher/MarkerNodeMatcherByType.js";
17
- import { CellMatcherOr } from "../../rules/logic/CellMatcherOr.js";
18
- import { RuleSelectionPolicyType } from "../../markers/RuleSelectionPolicyType.js";
19
- import { MarkerNodeMatcherAnd } from "../../markers/matcher/MarkerNodeMatcherAnd.js";
20
- import { MirGridLayers } from "../grid/MirGridLayers.js";
21
- import { CellFilterLiteralFloat } from "../../filtering/numeric/CellFilterLiteralFloat.js";
22
- import { MirMarkerTypes } from "../../../../generator/MirMarkerTypes.js";
23
- import { GridPatternMatcherCell } from "../../rules/cell/GridPatternMatcherCell.js";
24
- import { BuffObjectTypes } from "../../../../../generator/BuffObjectTypes.js";
25
- import { UnlockableElementsManager } from "../../../../../model/unlocks/UnlockableElementsManager.js";
1
+ import { CellMatcherGridPattern } from "../../../rules/cell/CellMatcherGridPattern.js";
2
+ import { matcher_tag_traversable_unoccupied } from "../../rules/matcher_tag_traversable_unoccupied.js";
3
+ import { CellMatcherNot } from "../../../rules/logic/CellMatcherNot.js";
4
+ import { CellMatcherContainsMarkerWithinRadius } from "../../../rules/cell/CellMatcherContainsMarkerWithinRadius.js";
5
+ import { GridCellActionPlaceTags } from "../../../placement/action/GridCellActionPlaceTags.js";
6
+ import { GridTags } from "../../../GridTags.js";
7
+ import { bitwiseAnd } from "../../../../core/binary/operations/bitwiseAnd.js";
8
+ import { GridCellActionPlaceMarker } from "../../../markers/GridCellActionPlaceMarker.js";
9
+ import { GridCellPlacementRule } from "../../../placement/GridCellPlacementRule.js";
10
+ import { GridTaskActionRuleSet } from "../../../grid/generation/discrete/GridTaskCellActionRuleSet.js";
11
+ import { GridActionRuleSet } from "../../../markers/GridActionRuleSet.js";
12
+ import { GridCellActionPlaceMarkerGroup } from "../../../markers/GridCellActionPlaceMarkerGroup.js";
13
+ import { matcher_tag_not_traversable } from "../../rules/matcher_tag_not_traversable.js";
14
+ import { MarkerNodeMatcherContainsTag } from "../../../markers/matcher/MarkerNodeMatcherContainsTag.js";
15
+ import { CellMatcherAnd } from "../../../rules/logic/CellMatcherAnd.js";
16
+ import { MarkerNodeMatcherByType } from "../../../markers/matcher/MarkerNodeMatcherByType.js";
17
+ import { CellMatcherOr } from "../../../rules/logic/CellMatcherOr.js";
18
+ import { RuleSelectionPolicyType } from "../../../markers/RuleSelectionPolicyType.js";
19
+ import { MarkerNodeMatcherAnd } from "../../../markers/matcher/MarkerNodeMatcherAnd.js";
20
+ import { MirGridLayers } from "../../grid/MirGridLayers.js";
21
+ import { CellFilterLiteralFloat } from "../../../filtering/numeric/CellFilterLiteralFloat.js";
22
+ import { MirMarkerTypes } from "../../../../../generator/MirMarkerTypes.js";
23
+ import { GridPatternMatcherCell } from "../../../rules/cell/GridPatternMatcherCell.js";
24
+ import { BuffObjectTypes } from "../../../../../../generator/BuffObjectTypes.js";
25
+ import { UnlockableElementsManager } from "../../../../../../model/unlocks/UnlockableElementsManager.js";
26
26
 
27
27
  const TAG_MAJOR = 'Major Buff';
28
28
  const TAG_MINOR = 'Minor Buff';
29
+ const TAG_UTILITY = 'Utility Buff';
29
30
 
30
31
 
31
32
  const pMatcherNextToWall = new CellMatcherGridPattern();
@@ -60,6 +61,15 @@ const mNoMinorBuffObjectNearby = CellMatcherNot.from(
60
61
  )
61
62
  );
62
63
 
64
+ const mNoUtilityBuffObjectNearby = CellMatcherNot.from(
65
+ CellMatcherContainsMarkerWithinRadius.from(
66
+ MarkerNodeMatcherAnd.from(
67
+ MarkerNodeMatcherContainsTag.from(MirMarkerTypes.BuffObject),
68
+ MarkerNodeMatcherContainsTag.from(TAG_MINOR)
69
+ ), 10
70
+ )
71
+ );
72
+
63
73
  pMatcherNextToWall.addRule(0, 0, mNoBuffObjectsNearby);
64
74
 
65
75
  const placeTags = new GridCellActionPlaceTags();
@@ -91,7 +101,10 @@ const placeRoadMarkers = GridCellActionPlaceMarkerGroup.from([placeRoadConnector
91
101
  function makeMajorRule(tag) {
92
102
  return GridCellPlacementRule.from({
93
103
  matcher: CellMatcherAnd.from(
94
- mNoMajorBuffObjectNearby,
104
+ CellMatcherAnd.from(
105
+ mNoMajorBuffObjectNearby,
106
+ mNoBuffObjectsNearby
107
+ ),
95
108
  CellMatcherAnd.from(
96
109
  pMatcherNextToWall,
97
110
  CellMatcherNot.from(
@@ -151,6 +164,40 @@ function makeMinorRule(tag) {
151
164
  });
152
165
  }
153
166
 
167
+ /**
168
+ *
169
+ * @param {string} tag
170
+ * @param {number} [frequency]
171
+ * @return {GridCellPlacementRule}
172
+ */
173
+ function makeUtilityRule(tag, frequency = 17) {
174
+ return GridCellPlacementRule.from({
175
+ matcher: CellMatcherAnd.from(
176
+ matcher_tag_traversable_unoccupied,
177
+
178
+ CellMatcherAnd.from(
179
+ mNoUtilityBuffObjectNearby,
180
+ CellMatcherNot.from(
181
+ CellMatcherOr.from(
182
+ mBuffObjectNearby,
183
+ CellMatcherContainsMarkerWithinRadius.from(MarkerNodeMatcherByType.from(tag), frequency)
184
+ )
185
+ )
186
+ )
187
+ ),
188
+ actions: [
189
+ placeTags,
190
+ clearTags,
191
+ GridCellActionPlaceMarker.from({
192
+ type: tag,
193
+ size: 0.52,
194
+ tags: [MirMarkerTypes.BuffObject, TAG_UTILITY]
195
+ })
196
+ ],
197
+ probability: CellFilterLiteralFloat.from(0.1)
198
+ });
199
+ }
200
+
154
201
  /**
155
202
  * @param {Engine} engine
156
203
  * @returns {GridTaskActionRuleSet}
@@ -206,6 +253,25 @@ export const mir_generator_place_buff_objects = (engine) => {
206
253
  }
207
254
 
208
255
 
256
+ /**
257
+ *
258
+ * @param {string} id
259
+ * @param {string} type
260
+ * @param frequency
261
+ */
262
+ function attemptUtilityRule(id, type, frequency) {
263
+
264
+ plugin.runIfElementValue(
265
+ 'object',
266
+ `buff/utility/${id}`,
267
+ true,
268
+ false,
269
+ () => {
270
+ rules.push(makeUtilityRule(type, frequency));
271
+ });
272
+ }
273
+
274
+
209
275
  if (plugin !== undefined) {
210
276
  attemptMajorRule(
211
277
  'increase_ability_power',
@@ -250,6 +316,11 @@ export const mir_generator_place_buff_objects = (engine) => {
250
316
  'campfire',
251
317
  BuffObjectTypes.Campfire
252
318
  );
319
+
320
+ // utility
321
+ attemptUtilityRule('resurrect', BuffObjectTypes.RESURRECT_ALL, 30);
322
+ attemptUtilityRule('heal_small', BuffObjectTypes.HEAL_SMALL, 17);
323
+
253
324
  }
254
325
 
255
326
 
@@ -15,6 +15,7 @@ import { CellFilterLiteralFloat } from "../../filtering/numeric/CellFilterLitera
15
15
  import { MirMarkerTypes } from "../../../../generator/MirMarkerTypes.js";
16
16
  import { MarkerNodeTransformerRemoveTag } from "../../markers/transform/MarkerNodeTransformerRemoveTag.js";
17
17
  import { MirMarkerTags } from "../../../../generator/MirMarkerTags.js";
18
+ import { MarkerNodeTransformerSequence } from "../../markers/transform/MarkerNodeTransformerSequence.js";
18
19
 
19
20
  const MATCH_STARTING_POINT = CellMatcherLayerBitMaskTest.from(GridTags.StartingPoint, MirGridLayers.Tags);
20
21
 
@@ -23,18 +24,24 @@ const pattern = new CellMatcherGridPattern();
23
24
 
24
25
  pattern.addRule(0, 0, matcher_tag_traversable_unoccupied);
25
26
  pattern.addRule(0, 0, CellMatcherNot.from(MATCH_STARTING_POINT));
27
+ // NEXT TO A BASE
26
28
  pattern.addRule(0, -1, CellMatcherLayerBitMaskTest.from(GridTags.Base, MirGridLayers.Tags));
27
29
 
28
30
  const rule = GridCellPlacementRule.from(
29
31
  {
30
- matcher: pattern, actions: [
32
+ matcher: pattern,
33
+ actions: [
31
34
  GridCellActionPlaceTags.from(GridTags.StartingPoint | GridTags.Occupied, MirGridLayers.Tags),
32
35
  GridCellActionPlaceMarker.from({ type: MirMarkerTypes.StartingPoint }),
33
36
  // transfer ownership of any base within some distance to the player
34
- GridCellActionTransformNearbyMarkers.from(5, MarkerNodeMatcherByType.from(MirMarkerTypes.Base), [
35
- MarkerNodeTransformerRecordProperty.from('team', CellFilterLiteralFloat.from(0)),
36
- MarkerNodeTransformerRemoveTag.from(MirMarkerTags.Encounter)
37
- ])
37
+ GridCellActionTransformNearbyMarkers.from(
38
+ 5,
39
+ MarkerNodeMatcherByType.from(MirMarkerTypes.Base),
40
+ MarkerNodeTransformerSequence.from([
41
+ MarkerNodeTransformerRecordProperty.from('team', CellFilterLiteralFloat.from(0)),
42
+ MarkerNodeTransformerRemoveTag.from(MirMarkerTags.Encounter)
43
+ ])
44
+ )
38
45
  ]
39
46
  }
40
47
  );
@@ -8,7 +8,7 @@ import { DataType } from "../../../core/collection/table/DataType.js";
8
8
  */
9
9
  export function configureMirGrid(data) {
10
10
 
11
- data.addLayer(GridDataLayer.from(MirGridLayers.Tags, DataType.Uint32, 1));
11
+ data.addLayer(GridDataLayer.from(MirGridLayers.Tags, DataType.Uint16, 1));
12
12
 
13
13
  data.addLayer(GridDataLayer.from(MirGridLayers.DistanceFromStart, DataType.Uint16, 1));
14
14
  data.addLayer(GridDataLayer.from(MirGridLayers.DistanceFromPlayArea, DataType.Uint16, 1));
@@ -29,6 +29,20 @@ export class CellFilter {
29
29
  return this.__initialized;
30
30
  }
31
31
 
32
+ /**
33
+ *
34
+ * @param {GridData} grid
35
+ * @param {number} seed
36
+ */
37
+ ensureInitialized(grid, seed) {
38
+ if (!this.__initialized) {
39
+ this.initialize(grid, seed);
40
+
41
+ // make sure initialization flag is set
42
+ this.__initialized = true;
43
+ }
44
+ }
45
+
32
46
  /**
33
47
  *
34
48
  * @param {GridData} grid
@@ -1,5 +1,6 @@
1
1
  import { CellFilterUnaryOperation } from "../../core/CellFilterUnaryOperation.js";
2
- import { assert } from "../../../core/assert.js";
2
+ import { assert } from "../../../../core/assert.js";
3
+
3
4
 
4
5
  export class CellFilterLogToConsole extends CellFilterUnaryOperation {
5
6
 
@@ -1,6 +1,9 @@
1
1
  import { assert } from "../../core/assert.js";
2
2
  import { QuadTreeNode } from "../../core/geom/2d/quad-tree/QuadTreeNode.js";
3
3
  import { OffsetScaleTransform2D } from "../../engine/ecs/terrain/ecs/OffsetScaleTransform2D.js";
4
+ import { MarkerMatchCounter } from "./MarkerMatchCounter.js";
5
+
6
+ const scratch_match_counter = new MarkerMatchCounter();
4
7
 
5
8
  export class GridData {
6
9
  constructor() {
@@ -111,23 +114,24 @@ export class GridData {
111
114
  * @returns {boolean}
112
115
  */
113
116
  containsMarkerInCircle(x, y, radius, matcher) {
114
- let result = false;
115
- this.markers.traverseCircleIntersections(x, y, radius, data => {
116
- /**
117
- *
118
- * @type {MarkerNode}
119
- */
120
- const marker = data.data;
117
+ return this.countMarkerInCircle(x, y, radius, matcher) > 0;
118
+ }
121
119
 
122
- if (matcher.match(marker)) {
123
- result = true;
120
+ /**
121
+ *
122
+ * @param {number} x
123
+ * @param {number} y
124
+ * @param {number} radius
125
+ * @param {MarkerNodeMatcher} matcher
126
+ * @returns {number}
127
+ */
128
+ countMarkerInCircle(x, y, radius, matcher) {
129
+ scratch_match_counter.matcher = matcher;
130
+ scratch_match_counter.count = 0;
124
131
 
125
- //stop traversal
126
- return false;
127
- }
128
- });
132
+ this.markers.traverseCircleIntersections(x, y, radius, scratch_match_counter.exec, scratch_match_counter);
129
133
 
130
- return result;
134
+ return scratch_match_counter.count;
131
135
  }
132
136
 
133
137
  /**
@@ -0,0 +1,23 @@
1
+ export class MarkerMatchCounter {
2
+ /**
3
+ * @template T
4
+ */
5
+ constructor() {
6
+ /**
7
+ * Predicate
8
+ * @type {{match:function(T):boolean}|null}
9
+ */
10
+ this.matcher = null;
11
+ this.count = 0;
12
+ }
13
+
14
+ /**
15
+ *
16
+ * @param {QuadTreeDatum<T>} node
17
+ */
18
+ exec(node) {
19
+ if (this.matcher.match(node.data)) {
20
+ this.count++;
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,86 @@
1
+ import { GridTaskGenerator } from "../GridTaskGenerator.js";
2
+ import { assert } from "../../../core/assert.js";
3
+ import { actionTask } from "../../../core/process/task/TaskUtils.js";
4
+ import TaskGroup from "../../../core/process/task/TaskGroup.js";
5
+ import Task from "../../../core/process/task/Task.js";
6
+ import TaskSignal from "../../../core/process/task/TaskSignal.js";
7
+
8
+ export class GridTaskApplyActionToCells extends GridTaskGenerator {
9
+ constructor() {
10
+ super();
11
+
12
+ /**
13
+ *
14
+ * @type {GridCellAction|null}
15
+ */
16
+ this.action = null;
17
+
18
+ /**
19
+ *
20
+ * @type {CellSupplier|null}
21
+ */
22
+ this.fitness = null;
23
+
24
+ }
25
+
26
+ /**
27
+ *
28
+ * @returns {GridTaskApplyActionToCells}
29
+ * @param {CellSupplier} selector
30
+ * @param {GridCellAction} action
31
+ * @param {string} name
32
+ */
33
+ static from({ selector, action, name }) {
34
+ assert.equal(selector.isCellSupplier, true, 'selector.isCellSupplier !== true');
35
+ assert.equal(action.isGridCellAction, true, 'action.isGridCellAction !== true');
36
+
37
+ const r = new GridTaskApplyActionToCells();
38
+
39
+ r.action = action;
40
+ r.fitness = selector;
41
+
42
+ return r;
43
+ }
44
+
45
+ build(grid, ecd, seed) {
46
+ const tInitialize = actionTask(() => {
47
+ this.fitness.initialize(grid, seed);
48
+ this.action.initialize(grid, seed);
49
+ });
50
+
51
+ let cursor = 0;
52
+
53
+ const tMain = new Task({
54
+ name: `Apply action to cells`,
55
+ computeProgress: () => {
56
+ const c = this.fitness.count();
57
+
58
+ if (c <= 0) {
59
+ return 0;
60
+ }
61
+
62
+ return cursor / c;
63
+ },
64
+ cycleFunction: () => {
65
+ const cell_data = this.fitness.next();
66
+
67
+ if (cell_data === undefined) {
68
+ return TaskSignal.EndSuccess;
69
+ }
70
+
71
+ cursor++;
72
+
73
+ const y = cell_data.y;
74
+ const x = cell_data.x;
75
+
76
+ this.action.execute(grid, x, y, cell_data.rotation);
77
+
78
+ return TaskSignal.Continue;
79
+ }
80
+ });
81
+
82
+ tMain.addDependency(tInitialize);
83
+
84
+ return new TaskGroup([tInitialize, tMain]);
85
+ }
86
+ }
@@ -0,0 +1,28 @@
1
+ export class CellSupplier {
2
+ /**
3
+ *
4
+ * @param {GridData} grid
5
+ * @param {number} seed
6
+ */
7
+ initialize(grid, seed) {
8
+
9
+ }
10
+
11
+ /**
12
+ * next cell, or undefined if no more cells left
13
+ * @returns {{x:number, y:number, rotation:number} |undefined}
14
+ */
15
+ next() {
16
+ return undefined;
17
+ }
18
+
19
+ count() {
20
+ return -1;
21
+ }
22
+ }
23
+
24
+ /**
25
+ * @readonly
26
+ * @type {boolean}
27
+ */
28
+ CellSupplier.prototype.isCellSupplier = true;
@@ -0,0 +1,188 @@
1
+ import { CellSupplier } from "./CellSupplier.js";
2
+ import { assert } from "../../../../../core/assert.js";
3
+ import { CellMatcherAny } from "../../../../rules/CellMatcherAny.js";
4
+ import { PI_HALF } from "../../../../../core/math/MathUtils.js";
5
+
6
+ /**
7
+ *
8
+ * @param {{score:number}} a
9
+ * @param {{score:number}} b
10
+ * @returns {number}
11
+ */
12
+ function byScore(a, b) {
13
+ return a.score - b.score;
14
+ }
15
+
16
+ /**
17
+ *
18
+ * @param {{index:number}} a
19
+ * @param {{index:number}} b
20
+ * @returns {number}
21
+ */
22
+ function byIndex(a, b) {
23
+ return a.index - b.index;
24
+ }
25
+
26
+ export class CellSupplierBestN extends CellSupplier {
27
+ constructor() {
28
+ super();
29
+
30
+
31
+ /**
32
+ *
33
+ * @type {CellFilter|null}
34
+ */
35
+ this.fitness = null;
36
+ /**
37
+ *
38
+ * @type {number}
39
+ */
40
+ this.cursor = 0;
41
+ /**
42
+ *
43
+ * @type {{x:number, y:number, rotation:number}[]}
44
+ */
45
+ this.elements = [];
46
+
47
+ /**
48
+ *
49
+ * @type {CellMatcher|null}
50
+ */
51
+ this.predicate = null;
52
+
53
+ /**
54
+ *
55
+ * @type {number}
56
+ */
57
+ this.limit = 0;
58
+
59
+ /**
60
+ *
61
+ * @type {boolean}
62
+ */
63
+ this.allow_rotation = false;
64
+ }
65
+
66
+ /**
67
+ * @param {CellFilter} fitness
68
+ * @param {CellMatcher} [predicate]
69
+ * @param {number} limit
70
+ * @param {boolean} allow_rotation
71
+ */
72
+ static from({
73
+ fitness,
74
+ predicate = CellMatcherAny.INSTANCE,
75
+ limit = 1,
76
+ allow_rotation = false
77
+ }) {
78
+ assert.isNumber(limit, 'limit');
79
+ assert.isNonNegativeInteger(limit, 'limit');
80
+ assert.equal(fitness.isCellFilter, true, 'fitness.isCellFilter !== true');
81
+ assert.equal(predicate.isCellMatcher, true, 'predicate.isCellMatcher !== true');
82
+ assert.isBoolean(allow_rotation, 'allow_rotation');
83
+
84
+ const r = new CellSupplierBestN();
85
+
86
+ r.fitness = fitness;
87
+ r.limit = limit;
88
+ r.predicate = predicate;
89
+ r.allow_rotation = allow_rotation;
90
+
91
+ return r;
92
+ }
93
+
94
+ initialize(grid, seed) {
95
+ super.initialize(grid, seed);
96
+
97
+ const predicate = this.predicate;
98
+ predicate.initialize(grid, seed);
99
+ this.fitness.ensureInitialized(grid, seed);
100
+
101
+ const fitness_scratch = [];
102
+
103
+ this.cursor = 0;
104
+
105
+ // build list
106
+ const h = grid.height;
107
+ const w = grid.width;
108
+
109
+ let rotation = 0;
110
+ for (let y = 0; y < h; y++) {
111
+ for (let x = 0; x < w; x++) {
112
+ const cell_index = y * w + x;
113
+
114
+ if (predicate.match(grid, x, y, 0)) {
115
+ rotation = 0;
116
+ } else if (this.allow_rotation) {
117
+ if (predicate.match(grid, x, y, PI_HALF)) {
118
+ rotation = PI_HALF;
119
+ } else if (predicate.match(grid, x, y, PI_HALF * 2)) {
120
+ rotation = PI_HALF * 2;
121
+ } else if (predicate.match(grid, x, y, PI_HALF * 3)) {
122
+ rotation = PI_HALF * 3;
123
+ } else {
124
+ // no rotated matches
125
+ continue
126
+ }
127
+
128
+ } else {
129
+ continue;
130
+ }
131
+
132
+ const fitness = this.fitness.execute(grid, x, y, rotation);
133
+
134
+ if (fitness_scratch.length < this.limit) {
135
+ } else if (fitness_scratch[0].score < fitness) {
136
+ // evict lower fitness candidate
137
+ fitness_scratch.shift();
138
+ } else {
139
+ continue;
140
+ }
141
+
142
+ fitness_scratch.push({
143
+ score: fitness,
144
+ index: cell_index,
145
+ x,
146
+ y,
147
+ rotation: rotation
148
+ });
149
+
150
+ fitness_scratch.sort(byScore);
151
+
152
+ }
153
+ }
154
+
155
+ // sort elements by index for faster access
156
+ fitness_scratch.sort(byIndex);
157
+
158
+ // copy out the list
159
+ const found_cells = fitness_scratch.length;
160
+
161
+ this.elements = [];
162
+ for (let i = 0; i < found_cells; i++) {
163
+ const s = fitness_scratch[i];
164
+
165
+ this.elements[i] = {
166
+ x: s.x,
167
+ y: s.y,
168
+ rotation: s.rotation
169
+ };
170
+ }
171
+
172
+ }
173
+
174
+ next() {
175
+ const cursor = this.cursor;
176
+ const elements = this.elements;
177
+
178
+ if (cursor >= elements.length) {
179
+ return undefined;
180
+ }
181
+
182
+ const r = elements[cursor];
183
+
184
+ this.cursor++;
185
+
186
+ return r;
187
+ }
188
+ }