@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.
- package/core/binary/BitSet.js +5 -1
- package/core/collection/RingBuffer.js +16 -1
- package/core/geom/Vector1.js +228 -219
- package/core/geom/Vector2.js +547 -502
- package/core/geom/Vector3.js +8 -0
- package/core/geom/Vector4.js +322 -311
- package/core/graph/v2/Graph.js +6 -6
- package/core/model/ObservedBoolean.js +12 -4
- package/core/process/worker/WorkerBuilder.js +27 -9
- package/core/process/worker/WorkerProxy.js +6 -0
- package/editor/Editor.js +10 -1
- package/editor/process/symbolic/makePositionedIconDisplaySymbol.js +3 -1
- package/engine/EngineHarness.js +1 -1
- package/engine/ecs/parent/ParentEntitySystem.js +1 -1
- package/engine/ecs/terrain/ecs/Terrain.js +11 -2
- package/engine/ecs/terrain/ecs/makeTerrainWorkerProxy.js +10 -10
- package/engine/graphics/camera/makeOrbitalCameraController.js +7 -1
- package/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +4 -31
- package/engine/graphics/ecs/mesh/Mesh.js +9 -3
- package/engine/graphics/ecs/path/entity/EntityPath.js +7 -7
- package/engine/graphics/ecs/trail2d/Trail2DSystem.js +31 -16
- package/engine/graphics/micron/build/buildMicronGeometryFromBufferGeometry.js +17 -8
- package/engine/graphics/micron/build/graph/metis/metis.js +23 -33
- package/engine/graphics/micron/render/v1/MaterialContext.js +21 -2
- package/engine/graphics/particles/particular/engine/renderers/billboard/prototypeBillboardRenderer.js +1 -1
- package/engine/graphics/particles/particular/engine/simulator/SimulationStepFixedPhysics.js +1 -1
- package/engine/graphics/render/buffer/buffers/NormalFrameBuffer.js +25 -16
- package/engine/graphics/render/buffer/buffers/prototypeNormalFrameBuffer.js +6 -5
- package/engine/graphics/trail/x/RibbonMaterialX.js +7 -2
- package/engine/grid/components/GridPosition.js +22 -122
- package/engine/grid/components/GridPositionSerializationAdapter.js +58 -0
- package/engine/grid/components/GridPositionSerializationUpdater_0_1.js +37 -0
- package/engine/intelligence/mcts/MonteCarlo.js +12 -15
- package/engine/intelligence/mcts/StateNode.js +3 -3
- package/generation/GridTags.js +3 -2
- package/generation/example/SampleGenerator0.js +1 -1
- package/generation/example/generators/{mir_generator_place_buff_objects.js → interactive/mir_generator_place_buff_objects.js} +97 -26
- package/generation/example/generators/mir_generator_place_starting_point.js +12 -5
- package/generation/example/grid/configureMirGrid.js +1 -1
- package/generation/filtering/CellFilter.js +14 -0
- package/generation/filtering/numeric/util/CellFilterLogToConsole.js +2 -1
- package/generation/grid/GridData.js +18 -14
- package/generation/grid/MarkerMatchCounter.js +23 -0
- package/generation/grid/generation/GridTaskApplyActionToCells.js +86 -0
- package/generation/grid/generation/grid/select/CellSupplier.js +28 -0
- package/generation/grid/generation/grid/select/CellSupplierBestN.js +188 -0
- package/generation/grid/generation/grid/select/CellSupplierPathUpHill.js +187 -0
- package/generation/markers/GridActionRuleSet.js +1 -1
- package/generation/markers/MarkerNode.js +18 -0
- package/generation/markers/debug/visualizeMarkers.js +8 -1
- package/generation/markers/transform/MarkerNodeTransformerSequence.js +47 -0
- package/generation/placement/GridCellActionTransformNearbyMarkers.js +9 -17
- package/generation/rules/CellMatcherFromFilter.js +38 -0
- package/generation/rules/cell/CellMatcherContainsMarkerWithinRadius.js +1 -1
- package/package.json +3 -3
|
@@ -1,31 +1,32 @@
|
|
|
1
|
-
import { CellMatcherGridPattern } from "
|
|
2
|
-
import { matcher_tag_traversable_unoccupied } from "
|
|
3
|
-
import { CellMatcherNot } from "
|
|
4
|
-
import { CellMatcherContainsMarkerWithinRadius } from "
|
|
5
|
-
import { GridCellActionPlaceTags } from "
|
|
6
|
-
import { GridTags } from "
|
|
7
|
-
import { bitwiseAnd } from "
|
|
8
|
-
import { GridCellActionPlaceMarker } from "
|
|
9
|
-
import { GridCellPlacementRule } from "
|
|
10
|
-
import { GridTaskActionRuleSet } from "
|
|
11
|
-
import { GridActionRuleSet } from "
|
|
12
|
-
import { GridCellActionPlaceMarkerGroup } from "
|
|
13
|
-
import { matcher_tag_not_traversable } from "
|
|
14
|
-
import { MarkerNodeMatcherContainsTag } from "
|
|
15
|
-
import { CellMatcherAnd } from "
|
|
16
|
-
import { MarkerNodeMatcherByType } from "
|
|
17
|
-
import { CellMatcherOr } from "
|
|
18
|
-
import { RuleSelectionPolicyType } from "
|
|
19
|
-
import { MarkerNodeMatcherAnd } from "
|
|
20
|
-
import { MirGridLayers } from "
|
|
21
|
-
import { CellFilterLiteralFloat } from "
|
|
22
|
-
import { MirMarkerTypes } from "
|
|
23
|
-
import { GridPatternMatcherCell } from "
|
|
24
|
-
import { BuffObjectTypes } from "
|
|
25
|
-
import { UnlockableElementsManager } from "
|
|
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
|
-
|
|
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,
|
|
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(
|
|
35
|
-
|
|
36
|
-
|
|
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.
|
|
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 "
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
*
|
|
118
|
-
* @type {MarkerNode}
|
|
119
|
-
*/
|
|
120
|
-
const marker = data.data;
|
|
117
|
+
return this.countMarkerInCircle(x, y, radius, matcher) > 0;
|
|
118
|
+
}
|
|
121
119
|
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
|
|
126
|
-
return false;
|
|
127
|
-
}
|
|
128
|
-
});
|
|
132
|
+
this.markers.traverseCircleIntersections(x, y, radius, scratch_match_counter.exec, scratch_match_counter);
|
|
129
133
|
|
|
130
|
-
return
|
|
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
|
+
}
|