@woosh/meep-engine 2.43.40 → 2.43.42

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 (34) hide show
  1. package/core/binary/BitSet.js +4 -18
  2. package/core/model/node-graph/Connection.js +41 -0
  3. package/core/model/node-graph/Connection.spec.js +21 -0
  4. package/core/model/node-graph/DataType.js +23 -1
  5. package/core/model/node-graph/DataType.spec.js +28 -0
  6. package/core/model/node-graph/NodeGraph.js +16 -7
  7. package/core/model/node-graph/node/NodeDescription.js +12 -5
  8. package/core/model/node-graph/node/NodeInstance.js +9 -3
  9. package/core/model/node-graph/node/NodeInstancePortReference.js +18 -0
  10. package/core/model/node-graph/node/NodeRegistry.js +36 -10
  11. package/core/model/node-graph/node/NodeRegistry.spec.js +25 -0
  12. package/core/model/node-graph/node/Port.js +12 -1
  13. package/core/model/node-graph/node/PortDirection.js +1 -1
  14. package/engine/graphics/render/frame_graph/RenderGraph.js +5 -1
  15. package/engine/intelligence/behavior/SelectorBehavior.js +3 -1
  16. package/engine/intelligence/behavior/behavior_to_dot.js +251 -0
  17. package/engine/intelligence/behavior/behavior_to_dot.prototype.js +55 -0
  18. package/engine/intelligence/behavior/composite/CompositeBehavior.js +6 -0
  19. package/engine/intelligence/behavior/composite/ParallelBehavior.js +10 -0
  20. package/engine/intelligence/behavior/composite/SequenceBehavior.js +6 -50
  21. package/engine/intelligence/behavior/composite/SequenceBehaviorSerializationAdapter.js +52 -0
  22. package/engine/intelligence/blackboard/Blackboard.js +26 -14
  23. package/engine/intelligence/blackboard/Blackboard.spec.js +62 -0
  24. package/engine/intelligence/blackboard/{Blacboard.spec.js → BlackboardSerializationAdapter.spec.js} +1 -1
  25. package/engine/intelligence/mcts/README.md +7 -0
  26. package/engine/intelligence/optimization/RandomOptimizer.js +2 -1
  27. package/engine/intelligence/resource/ResourceAllocationBid.js +3 -3
  28. package/engine/intelligence/resource/ResourceAllocationSolver.js +1 -1
  29. package/engine/intelligence/resource/StrategicResourceAllocator.js +6 -4
  30. package/engine/intelligence/resource/TacticalModule.js +7 -0
  31. package/engine/knowledge/database/StaticKnowledgeDataTableDescriptor.js +5 -5
  32. package/engine/navigation/grid/GridField.js +1 -0
  33. package/engine/notify/NotificationLog.js +2 -2
  34. package/package.json +1 -1
@@ -86,7 +86,6 @@ function BitSet() {
86
86
  this.__data_uint32 = new Uint32Array(this.__capacity >> 5);
87
87
 
88
88
  /**
89
- *
90
89
  * @type {number}
91
90
  */
92
91
  this.__shrinkFactor = SHRINK_FACTOR;
@@ -201,7 +200,7 @@ BitSet.prototype.__setLength = function (new_length) {
201
200
  * @returns {int} Index of previous set bit, or -1 if no set bit found
202
201
  */
203
202
  BitSet.prototype.previousSetBit = function (fromIndex) {
204
- assert.ok(fromIndex >= 0, `fromIndex must be greater or equal to 0, instead was ${fromIndex}`);
203
+ assert.isNonNegativeInteger(fromIndex, `fromIndex`);
205
204
 
206
205
  const index = min2(fromIndex, this.__length - 1);
207
206
 
@@ -354,21 +353,6 @@ BitSet.prototype.nextClearBit = function (fromIndex) {
354
353
  return set_length;
355
354
  };
356
355
 
357
- /**
358
- * Slow method for scanning through bitset, used for debugging
359
- * @param {BitSet} set
360
- * @returns {number}
361
- */
362
- function scanToFirstClearBit(set) {
363
- for (let i = 0; i <= set.size(); i++) {
364
- if (set.get(i) === false) {
365
- return i;
366
- }
367
- }
368
-
369
- return -1;
370
- }
371
-
372
356
  /**
373
357
  *
374
358
  * @param {int} bitIndex
@@ -443,7 +427,9 @@ BitSet.prototype.setRange = function (startIndex, endIndex) {
443
427
  * @param {number} endIndex clear up to here, excluding this position
444
428
  */
445
429
  BitSet.prototype.clearRange = function (startIndex, endIndex) {
446
- //TODO this can be done more efficiently
430
+ assert.greaterThanOrEqual(startIndex, 0, "invalid start index");
431
+ assert.greaterThanOrEqual(endIndex, 0, "invalid end index");
432
+
447
433
  for (let i = startIndex; i < endIndex; i++) {
448
434
  this.set(i, false);
449
435
  }
@@ -3,13 +3,26 @@ import { noop } from "../../function/Functions.js";
3
3
  import { objectKeyByValue } from "../object/objectKeyByValue.js";
4
4
  import { PortDirection } from "./node/PortDirection.js";
5
5
 
6
+ /**
7
+ *
8
+ * @type {number}
9
+ */
10
+ let id_counter = 0;
11
+
6
12
  export class Connection {
7
13
  constructor() {
14
+ /**
15
+ * @readonly
16
+ * @type {number}
17
+ */
18
+ this.id = id_counter++;
19
+
8
20
  /**
9
21
  *
10
22
  * @type {NodeInstancePortReference}
11
23
  */
12
24
  this.source = null;
25
+
13
26
  /**
14
27
  *
15
28
  * @type {NodeInstancePortReference}
@@ -93,4 +106,32 @@ export class Connection {
93
106
 
94
107
  return this.source.instance.id === id || this.target.instance.id === id;
95
108
  }
109
+
110
+ /**
111
+ *
112
+ * @param {Connection} other
113
+ * @returns {boolean}
114
+ */
115
+ equals(other) {
116
+ return this.target === other.target
117
+ && this.source === other.source
118
+ ;
119
+ }
120
+
121
+ hash() {
122
+ const source_hash = this.source !== null ? this.source.id : 0;
123
+ const target_hash = this.target !== null ? this.target.id : 0;
124
+
125
+ // shuffle bits a bit to get better spread
126
+ return ((source_hash << 16) | (source_hash >>> 16))
127
+ ^ (target_hash)
128
+ ;
129
+ }
96
130
  }
131
+
132
+
133
+ /**
134
+ * @readonly
135
+ * @type {boolean}
136
+ */
137
+ Connection.prototype.isConnection = true;
@@ -0,0 +1,21 @@
1
+ import { Connection } from "./Connection.js";
2
+
3
+ test("stable hash", () => {
4
+ const a = new Connection();
5
+ const b = new Connection();
6
+
7
+ expect(a.hash()).toEqual(b.hash());
8
+ });
9
+
10
+ test("equality of fresh instances", () => {
11
+ const a = new Connection();
12
+ const b = new Connection();
13
+
14
+ expect(a.equals(b)).toBe(true);
15
+ });
16
+
17
+ test("equality on self", () => {
18
+ const thing = new Connection();
19
+
20
+ expect(thing.equals(thing)).toBe(true);
21
+ });
@@ -1,3 +1,5 @@
1
+ import { assert } from "../../assert.js";
2
+
1
3
  export class DataType {
2
4
  constructor() {
3
5
  /**
@@ -14,7 +16,15 @@ export class DataType {
14
16
  }
15
17
 
16
18
  toString() {
17
- return `${this.id}:'${this.name}'`;
19
+ return `{DataType: id=${this.id}, name='${this.name}' }`;
20
+ }
21
+
22
+ /**
23
+ *
24
+ * @return {number}
25
+ */
26
+ hash() {
27
+ return this.id;
18
28
  }
19
29
 
20
30
  /**
@@ -26,6 +36,18 @@ export class DataType {
26
36
  return this.id === other.id && this.name === other.name;
27
37
  }
28
38
 
39
+ toJSON() {
40
+ return { ...this };
41
+ }
42
+
43
+ fromJSON({ id, name }) {
44
+ assert.isNonNegativeInteger(id, 'id');
45
+ assert.isString(name, 'name');
46
+
47
+ this.id = id;
48
+ this.name = name;
49
+ }
50
+
29
51
  /**
30
52
  *
31
53
  * @param {number} id
@@ -0,0 +1,28 @@
1
+ import { DataType } from "./DataType.js";
2
+
3
+ test('to/from json', () => {
4
+ const a = DataType.from(7, 'kitty');
5
+
6
+ const b = new DataType();
7
+
8
+ b.fromJSON(a.toJSON());
9
+
10
+ expect(b.id).toBe(a.id);
11
+ expect(b.name).toBe(a.name);
12
+
13
+ });
14
+
15
+ test('equals', () => {
16
+ const a = DataType.from(7, 'kitty');
17
+ const b = DataType.from(7, 'kitty');
18
+ const c = DataType.from(7, 'fluffy');
19
+ const d = DataType.from(9, 'kitty');
20
+
21
+
22
+ expect(a.equals(b)).toBe(true);
23
+
24
+ expect(a.equals(c)).toBe(false);
25
+ expect(a.equals(d)).toBe(false);
26
+
27
+ expect(c.equals(d)).toBe(false);
28
+ });
@@ -43,7 +43,7 @@ export class NodeGraph {
43
43
 
44
44
  /**
45
45
  *
46
- * @param {function(NodeInstance)} visitor
46
+ * @param {function(NodeInstance):*} visitor
47
47
  * @param [thisArg]
48
48
  */
49
49
  traverseNodes(visitor, thisArg) {
@@ -52,7 +52,7 @@ export class NodeGraph {
52
52
 
53
53
  /**
54
54
  *
55
- * @param {function(Connection)} visitor
55
+ * @param {function(Connection):*} visitor
56
56
  * @param [thisArg]
57
57
  */
58
58
  traverseConnections(visitor, thisArg) {
@@ -105,15 +105,18 @@ export class NodeGraph {
105
105
  *
106
106
  * @param {number} node_id
107
107
  * @param {number} port_id
108
- * @returns {NodeInstancePortReference}
108
+ * @returns {NodeInstancePortReference|undefined}
109
109
  */
110
110
  getConnectionEndpoint(node_id, port_id) {
111
111
 
112
112
  const nodeInstance = this.getNode(node_id);
113
113
 
114
- const endpoint = nodeInstance.getEndpoint(port_id);
114
+ if (nodeInstance === undefined) {
115
+ // no node
116
+ return undefined;
117
+ }
115
118
 
116
- return endpoint;
119
+ return nodeInstance.getEndpoint(port_id);
117
120
  }
118
121
 
119
122
  /**
@@ -219,13 +222,13 @@ export class NodeGraph {
219
222
  //get endpoints
220
223
  const sourceEndpoint = sourceNodeInstance.getEndpoint(sourcePort);
221
224
 
222
- if (sourceEndpoint === null) {
225
+ if (sourceEndpoint === undefined) {
223
226
  throw new Error(`Source port '${sourcePort}' not found`);
224
227
  }
225
228
 
226
229
  const targetEndpoint = targetNodeInstance.getEndpoint(targetPort);
227
230
 
228
- if (targetEndpoint === null) {
231
+ if (targetEndpoint === undefined) {
229
232
  throw new Error(`Target port '${targetPort}' not found`);
230
233
  }
231
234
 
@@ -287,3 +290,9 @@ export class NodeGraph {
287
290
  return count;
288
291
  }
289
292
  }
293
+
294
+ /**
295
+ * @readonly
296
+ * @type {boolean}
297
+ */
298
+ NodeGraph.prototype.isNodeGraph = true;
@@ -67,19 +67,20 @@ export class NodeDescription {
67
67
  assert.typeOf(name, 'string', 'name');
68
68
  assert.enum(type, NodeParameterDataType, 'type');
69
69
 
70
+ let _default = defaultValue;
70
71
 
71
72
  //if default value is not given, pick one
72
- if (defaultValue === undefined) {
73
+ if (_default === undefined) {
73
74
  switch (type) {
74
75
  //intended fallthrough
75
76
  case NodeParameterDataType.Number:
76
- defaultValue = 0;
77
+ _default = 0;
77
78
  break;
78
79
  case NodeParameterDataType.Boolean:
79
- defaultValue = false;
80
+ _default = false;
80
81
  break;
81
82
  case NodeParameterDataType.String:
82
- defaultValue = "";
83
+ _default = "";
83
84
  break;
84
85
  default:
85
86
  throw new Error(`Unknown data type '${type}'`);
@@ -93,7 +94,7 @@ export class NodeDescription {
93
94
 
94
95
  pd.name = name;
95
96
  pd.type = type;
96
- pd.defaultValue = defaultValue;
97
+ pd.defaultValue = _default;
97
98
  pd.id = id;
98
99
 
99
100
  assert.ok(pd.validate(console.error), 'parameter is not valid');
@@ -188,3 +189,9 @@ export class NodeDescription {
188
189
  return this.ports
189
190
  }
190
191
  }
192
+
193
+ /**
194
+ * @readonly
195
+ * @type {boolean}
196
+ */
197
+ NodeDescription.prototype.isNodeDescription = true;
@@ -4,13 +4,19 @@ import { NodeInstancePortReference } from "./NodeInstancePortReference.js";
4
4
  import { PortDirection } from "./PortDirection.js";
5
5
  import { isArrayEqual } from "../../../collection/array/isArrayEqual.js";
6
6
 
7
+ /**
8
+ *
9
+ * @type {number}
10
+ */
11
+ let id_counter = 0;
12
+
7
13
  export class NodeInstance {
8
14
  constructor() {
9
15
  /**
10
16
  *
11
17
  * @type {number}
12
18
  */
13
- this.id = 0;
19
+ this.id = id_counter++;
14
20
 
15
21
  /**
16
22
  *
@@ -149,7 +155,7 @@ export class NodeInstance {
149
155
  /**
150
156
  *
151
157
  * @param {number} port Port ID
152
- * @returns {NodeInstancePortReference|null}
158
+ * @returns {NodeInstancePortReference|undefined}
153
159
  */
154
160
  getEndpoint(port) {
155
161
  const endpoints = this.endpoints;
@@ -161,7 +167,7 @@ export class NodeInstance {
161
167
  }
162
168
 
163
169
  //not found
164
- return null;
170
+ return undefined;
165
171
  }
166
172
 
167
173
  hash() {
@@ -1,12 +1,24 @@
1
1
  import { assert } from "../../../assert.js";
2
2
  import { computeHashIntegerArray } from "../../../collection/array/computeHashIntegerArray.js";
3
3
 
4
+ /**
5
+ *
6
+ * @type {number}
7
+ */
8
+ let id_counter = 0;
9
+
4
10
  /**
5
11
  * Reference for a port of a node instance
6
12
  */
7
13
  export class NodeInstancePortReference {
8
14
 
9
15
  constructor() {
16
+ /**
17
+ * @readonly
18
+ * @type {number}
19
+ */
20
+ this.id = id_counter++;
21
+
10
22
  /**
11
23
  *
12
24
  * @type {NodeInstance}
@@ -75,3 +87,9 @@ export class NodeInstancePortReference {
75
87
  ;
76
88
  }
77
89
  }
90
+
91
+ /**
92
+ * @readonly
93
+ * @type {boolean}
94
+ */
95
+ NodeInstancePortReference.prototype.isNodeInstancePortReference = true;
@@ -4,16 +4,25 @@ import { DataType } from "../DataType.js";
4
4
  import { NodeDescription } from "./NodeDescription.js";
5
5
  import { Port } from "./Port.js";
6
6
 
7
+ /**
8
+ *
9
+ * @param {Port} port
10
+ * @return {DataType}
11
+ */
12
+ function getPortType(port) {
13
+ return port.dataType;
14
+ }
15
+
7
16
  export class NodeRegistry {
8
17
  constructor() {
9
18
  /**
10
- *
19
+ * ID -> Node mapping
11
20
  * @type {Map<number, NodeDescription>}
12
21
  */
13
22
  this.nodes = new Map();
14
23
 
15
24
  /**
16
- *
25
+ * ID -> DataType mapping
17
26
  * @type {Map<number, DataType>}
18
27
  */
19
28
  this.types = new Map();
@@ -31,19 +40,17 @@ export class NodeRegistry {
31
40
  * @param {NodeDescription} node
32
41
  */
33
42
  addNode(node) {
34
- assert.notEqual(node, undefined, "node is undefined");
35
- assert.notEqual(node, null, "node is null");
43
+ assert.defined(node, "node");
44
+ assert.notNull(node, "node");
36
45
 
37
46
  if (this.nodes.has(node.id)) {
38
- console.warn(`Node with id ${node.id} already exists`);
47
+ // console.warn(`Node with id ${node.id} already exists`);
39
48
 
40
49
  return false;
41
50
  }
42
51
 
43
52
  //extract types
44
- node.getPorts().forEach(port => {
45
- this.addType(port.dataType);
46
- });
53
+ node.getPorts().map(getPortType).forEach(this.addType, this);
47
54
 
48
55
  this.nodes.set(node.id, node);
49
56
 
@@ -55,14 +62,27 @@ export class NodeRegistry {
55
62
  * @param {DataType} type
56
63
  */
57
64
  addType(type) {
58
- if (this.types.has(type.id)) {
65
+ if (this.hasType(type)) {
59
66
  return false;
60
67
  }
61
68
 
62
69
  this.types.set(type.id, type);
70
+
63
71
  return true;
64
72
  }
65
73
 
74
+ /**
75
+ *
76
+ * @param {DataType} type
77
+ * @return {boolean}
78
+ */
79
+ hasType(type) {
80
+ assert.defined(type, 'type');
81
+ assert.notNull(type, 'type');
82
+
83
+ return this.types.has(type.id);
84
+ }
85
+
66
86
  /**
67
87
  *
68
88
  * @returns {number}
@@ -123,7 +143,7 @@ export class NodeRegistry {
123
143
  }
124
144
 
125
145
  /**
126
- *
146
+ * NOTE: this only works with un-extended node descriptions
127
147
  * @param json
128
148
  * @returns {NodeDescription}
129
149
  */
@@ -215,3 +235,9 @@ export class NodeRegistry {
215
235
  };
216
236
  }
217
237
  }
238
+
239
+ /**
240
+ * @readonly
241
+ * @type {boolean}
242
+ */
243
+ NodeRegistry.prototype.isNodeRegistry = true;
@@ -50,3 +50,28 @@ test("serialize/deserialize 1 node with 1 port", () => {
50
50
  expect(port.dataType.name).toBe("kitty");
51
51
  expect(port.dataType.id).toBe(42);
52
52
  });
53
+
54
+ test("port types are added automatically when node is added", () => {
55
+ const registry = new NodeRegistry();
56
+
57
+ const type = DataType.from(0, 'a');
58
+
59
+ const node = new NodeDescription();
60
+ node.createPort(type, "port name", PortDirection.In);
61
+
62
+ registry.addNode(node);
63
+
64
+ expect(registry.hasType(type));
65
+ });
66
+
67
+ test("hasType", () => {
68
+ const registry = new NodeRegistry();
69
+
70
+ const type = DataType.from(0, 'a');
71
+
72
+ expect(registry.hasType(type)).toBe(false);
73
+
74
+ registry.addType(type);
75
+
76
+ expect(registry.hasType(type)).toBe(true);
77
+ });
@@ -2,6 +2,11 @@ import { computeStringHash } from "../../../primitives/strings/computeStringHash
2
2
  import { PortDirection } from "./PortDirection.js";
3
3
  import { computeHashIntegerArray } from "../../../collection/array/computeHashIntegerArray.js";
4
4
 
5
+ /**
6
+ * @type {number}
7
+ */
8
+ let id_counter = 0;
9
+
5
10
  export class Port {
6
11
  constructor() {
7
12
  /**
@@ -14,7 +19,7 @@ export class Port {
14
19
  * ID uniquely identifies object within some context. Ids are assumed to be immutable
15
20
  * @type {number}
16
21
  */
17
- this.id = 0;
22
+ this.id = id_counter++;
18
23
 
19
24
  /**
20
25
  *
@@ -53,3 +58,9 @@ export class Port {
53
58
 
54
59
  }
55
60
  }
61
+
62
+ /**
63
+ * @readonly
64
+ * @type {boolean}
65
+ */
66
+ Port.prototype.isPort = true;
@@ -1,5 +1,5 @@
1
1
  /**
2
- *
2
+ * @readonly
3
3
  * @enum
4
4
  */
5
5
  export const PortDirection = {
@@ -338,6 +338,10 @@ export class RenderGraph {
338
338
  }
339
339
  }
340
340
 
341
+ /**
342
+ * @see https://en.wikipedia.org/wiki/DOT_(graph_description_language)
343
+ * @return {string}
344
+ */
341
345
  exportToDot() {
342
346
  const out = new LineBuilder();
343
347
 
@@ -397,9 +401,9 @@ export class RenderGraph {
397
401
  out.dedent();
398
402
  out.add("} [color=olivedrab3]");
399
403
  }
404
+ // -- Clusters:
400
405
  out.dedent();
401
406
  out.add("}");
402
- // -- Clusters:
403
407
  return out.build();
404
408
  }
405
409
  }
@@ -46,7 +46,9 @@ export class SelectorBehavior extends CompositeBehavior {
46
46
  }
47
47
  }
48
48
 
49
- initialize() {
49
+ initialize(context) {
50
+ super.initialize(context);
51
+
50
52
  this.__currentBehaviourIndex = 0;
51
53
  this.__currentBehaviour = this.__children[0];
52
54