@woosh/meep-engine 2.48.17 → 2.48.19
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/package.json +1 -1
- package/src/core/binary/dec2hex.spec.js +13 -0
- package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.d.ts +18 -0
- package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js +18 -0
- package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.spec.js +56 -0
- package/src/core/cache/Cache.d.ts +5 -0
- package/src/core/cache/Cache.js +8 -1
- package/src/core/cache/Cache.spec.js +47 -3
- package/src/core/codegen/LineBuilder.js +117 -106
- package/src/core/collection/HashMap.spec.js +32 -0
- package/src/core/collection/list/List.js +6 -4
- package/src/core/geom/Matrix4.js +4 -1
- package/src/core/geom/Quaternion.js +4 -0
- package/src/core/geom/Vector3.js +9 -31
- package/src/core/graph/Edge.js +11 -2
- package/src/core/graph/v2/Graph.js +36 -31
- package/src/core/graph/v2/Graph.spec.js +309 -1
- package/src/core/math/fract.spec.js +11 -0
- package/src/core/math/isPowerOfTwo.spec.js +9 -0
- package/src/core/math/isPowerOrTwo.js +5 -0
- package/src/core/math/newton_solver_1d.js +1 -1
- package/src/core/math/newton_solver_1d.spec.js +9 -0
- package/src/core/math/pingpong.spec.js +11 -0
- package/src/core/math/random/randomBytes.js +16 -0
- package/src/core/math/random/randomFloatBetween.spec.js +8 -0
- package/src/core/math/random/randomFromArray.js +3 -3
- package/src/core/math/random/randomIntegerBetween.js +5 -0
- package/src/core/math/random/randomIntegerBetween.spec.js +7 -0
- package/src/core/math/statistics/halton_sequence.spec.js +17 -0
- package/src/engine/asset/AssetManager.d.ts +11 -1
- package/src/engine/asset/AssetManager.spec.js +2 -2
- package/src/engine/control/ControlContext.js +2 -1
- package/src/engine/ecs/EntityBuilder.d.ts +6 -0
- package/src/engine/ecs/EntityBuilder.js +2 -22
- package/src/engine/ecs/EntityBuilder.spec.js +71 -1
- package/src/engine/ecs/EntityBuilderFlags.js +20 -0
- package/src/engine/ecs/EntityComponentDataset.js +3 -6
- package/src/engine/ecs/dynamic_actions/DynamicActorSystem.js +2 -1
- package/src/engine/ecs/gui/menu/radial/RadialContextMenu.js +2 -1
- package/src/engine/ecs/guid/GUID.js +48 -26
- package/src/engine/ecs/guid/GUID.spec.js +56 -10
- package/src/engine/ecs/speaker/VoiceSystem.js +2 -1
- package/src/engine/ecs/transform/Transform.d.ts +11 -1
- package/src/engine/ecs/transform/Transform.js +6 -3
- package/src/engine/ecs/transform/Transform.spec.js +67 -1
- package/src/engine/graphics/ecs/decal/v2/prototypeDecalSystem.js +2 -1
- package/src/engine/physics/fluid/Fluid.js +3 -0
- /package/src/core/geom/{Matrix3.js → m3_determinant.js} +0 -0
package/src/core/geom/Vector3.js
CHANGED
|
@@ -38,7 +38,7 @@ class Vector3 {
|
|
|
38
38
|
* @param {number[]} array
|
|
39
39
|
* @param {number} offset
|
|
40
40
|
*/
|
|
41
|
-
readFromArray(array, offset=0) {
|
|
41
|
+
readFromArray(array, offset = 0) {
|
|
42
42
|
this.set(
|
|
43
43
|
array[offset],
|
|
44
44
|
array[offset + 1],
|
|
@@ -51,16 +51,16 @@ class Vector3 {
|
|
|
51
51
|
* @param {number[]} array
|
|
52
52
|
* @param {number} offset
|
|
53
53
|
*/
|
|
54
|
-
writeToArray(array, offset=0) {
|
|
54
|
+
writeToArray(array, offset = 0) {
|
|
55
55
|
array[offset] = this.x;
|
|
56
56
|
array[offset + 1] = this.y;
|
|
57
57
|
array[offset + 2] = this.z;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
asArray(){
|
|
60
|
+
asArray() {
|
|
61
61
|
const r = [];
|
|
62
62
|
|
|
63
|
-
this.writeToArray(r,0);
|
|
63
|
+
this.writeToArray(r, 0);
|
|
64
64
|
|
|
65
65
|
return r;
|
|
66
66
|
}
|
|
@@ -171,12 +171,12 @@ class Vector3 {
|
|
|
171
171
|
* @param {Vector3} a
|
|
172
172
|
* @param {Vector3} b
|
|
173
173
|
*/
|
|
174
|
-
addVectors(a,b){
|
|
174
|
+
addVectors(a, b) {
|
|
175
175
|
const x = a.x + b.x;
|
|
176
176
|
const y = a.y + b.y;
|
|
177
177
|
const z = a.z + b.z;
|
|
178
178
|
|
|
179
|
-
this.set(x,y,z);
|
|
179
|
+
this.set(x, y, z);
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
/**
|
|
@@ -378,7 +378,7 @@ class Vector3 {
|
|
|
378
378
|
* @returns {number}
|
|
379
379
|
*/
|
|
380
380
|
length() {
|
|
381
|
-
return
|
|
381
|
+
return v3_length(this.x, this.y, this.z);
|
|
382
382
|
}
|
|
383
383
|
|
|
384
384
|
/**
|
|
@@ -532,7 +532,7 @@ class Vector3 {
|
|
|
532
532
|
* @param {number} fraction
|
|
533
533
|
*/
|
|
534
534
|
lerpVectors(a, b, fraction) {
|
|
535
|
-
|
|
535
|
+
v3_lerp(this, a.x, a.y, a.z, b.x, b.y, b.z, fraction);
|
|
536
536
|
}
|
|
537
537
|
|
|
538
538
|
/**
|
|
@@ -806,7 +806,7 @@ class Vector3 {
|
|
|
806
806
|
}
|
|
807
807
|
|
|
808
808
|
toString() {
|
|
809
|
-
return `
|
|
809
|
+
return `{ x:${this.x}, y:${this.y}, z:${this.z} }`;
|
|
810
810
|
}
|
|
811
811
|
|
|
812
812
|
/**
|
|
@@ -1095,7 +1095,6 @@ Vector3.back = Object.freeze(new Vector3(0, 0, -1));
|
|
|
1095
1095
|
|
|
1096
1096
|
Vector3.typeName = "Vector3";
|
|
1097
1097
|
|
|
1098
|
-
|
|
1099
1098
|
/**
|
|
1100
1099
|
*
|
|
1101
1100
|
* @param {number} x0
|
|
@@ -1109,25 +1108,4 @@ Vector3.typeName = "Vector3";
|
|
|
1109
1108
|
Vector3._dot = v3_dot;
|
|
1110
1109
|
|
|
1111
1110
|
|
|
1112
|
-
/**
|
|
1113
|
-
*
|
|
1114
|
-
* @param {{x:number, y:number, z:number}} v
|
|
1115
|
-
* @return {number}
|
|
1116
|
-
*/
|
|
1117
|
-
function v3Length(v) {
|
|
1118
|
-
return v3_length(v.x, v.y, v.z);
|
|
1119
|
-
}
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
/**
|
|
1123
|
-
*
|
|
1124
|
-
* @param {Vector3} result
|
|
1125
|
-
* @param {Vector3} a
|
|
1126
|
-
* @param {Vector3} b
|
|
1127
|
-
* @param {number} fraction
|
|
1128
|
-
*/
|
|
1129
|
-
function v3Lerp(result, a, b, fraction) {
|
|
1130
|
-
v3_lerp(result, a.x, a.y, a.z, b.x, b.y, b.z, fraction);
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
1111
|
export default Vector3;
|
package/src/core/graph/Edge.js
CHANGED
|
@@ -26,8 +26,8 @@ export class Edge {
|
|
|
26
26
|
* @constructor
|
|
27
27
|
*/
|
|
28
28
|
constructor(a, b) {
|
|
29
|
-
assert.
|
|
30
|
-
assert.
|
|
29
|
+
assert.defined(a, 'a');
|
|
30
|
+
assert.defined(b, 'b');
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
*
|
|
@@ -46,6 +46,11 @@ export class Edge {
|
|
|
46
46
|
this.direction = EdgeDirectionType.Undirected;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
*
|
|
51
|
+
* @param {N} node
|
|
52
|
+
* @return {boolean}
|
|
53
|
+
*/
|
|
49
54
|
contains(node) {
|
|
50
55
|
return this.first === node || this.second === node;
|
|
51
56
|
}
|
|
@@ -86,6 +91,8 @@ export class Edge {
|
|
|
86
91
|
* @returns {number}
|
|
87
92
|
*/
|
|
88
93
|
angle() {
|
|
94
|
+
console.error('method is deprecated, do not use');
|
|
95
|
+
|
|
89
96
|
const delta = this.second.clone().sub(this.first);
|
|
90
97
|
return Math.atan2(delta.y, delta.x);
|
|
91
98
|
}
|
|
@@ -104,6 +111,8 @@ export class Edge {
|
|
|
104
111
|
* @returns {number}
|
|
105
112
|
*/
|
|
106
113
|
get length() {
|
|
114
|
+
console.error('method is deprecated, do not use');
|
|
115
|
+
|
|
107
116
|
return this.first.distanceTo(this.second);
|
|
108
117
|
}
|
|
109
118
|
}
|
|
@@ -26,29 +26,31 @@ function construct_path(goal_node_container, cameFrom) {
|
|
|
26
26
|
export class Graph {
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
|
-
*
|
|
29
|
+
*
|
|
30
|
+
* @type {Map<N, NodeContainer<N>>}
|
|
31
|
+
* @private
|
|
32
|
+
*/
|
|
33
|
+
__nodes = new Map();
|
|
34
|
+
/**
|
|
35
|
+
*
|
|
36
|
+
* @type {Set<Edge<N>>}
|
|
37
|
+
* @private
|
|
30
38
|
*/
|
|
31
|
-
|
|
39
|
+
__edges = new Set();
|
|
40
|
+
|
|
41
|
+
on = {
|
|
32
42
|
/**
|
|
33
|
-
*
|
|
34
|
-
* @type {Map<N, NodeContainer<N>>}
|
|
35
|
-
* @private
|
|
43
|
+
* @type {Signal<N,this>}
|
|
36
44
|
*/
|
|
37
|
-
|
|
45
|
+
nodeAdded: new Signal(),
|
|
38
46
|
/**
|
|
39
|
-
*
|
|
40
|
-
* @type {Set<Edge<N>>}
|
|
41
|
-
* @private
|
|
47
|
+
* @type {Signal<N,this>}
|
|
42
48
|
*/
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
edgeAdded: new Signal(),
|
|
49
|
-
edgeRemoved: new Signal()
|
|
50
|
-
};
|
|
51
|
-
}
|
|
49
|
+
nodeRemoved: new Signal(),
|
|
50
|
+
edgeAdded: new Signal(),
|
|
51
|
+
edgeRemoved: new Signal()
|
|
52
|
+
};
|
|
53
|
+
|
|
52
54
|
|
|
53
55
|
/**
|
|
54
56
|
*
|
|
@@ -115,6 +117,14 @@ export class Graph {
|
|
|
115
117
|
return this.__nodes.size;
|
|
116
118
|
}
|
|
117
119
|
|
|
120
|
+
/**
|
|
121
|
+
*
|
|
122
|
+
* @returns {number}
|
|
123
|
+
*/
|
|
124
|
+
getNodeCount() {
|
|
125
|
+
return this.__nodes.size;
|
|
126
|
+
}
|
|
127
|
+
|
|
118
128
|
/**
|
|
119
129
|
*
|
|
120
130
|
* @param {function(N):boolean} filter
|
|
@@ -169,14 +179,6 @@ export class Graph {
|
|
|
169
179
|
return this.__nodes.keys();
|
|
170
180
|
}
|
|
171
181
|
|
|
172
|
-
/**
|
|
173
|
-
*
|
|
174
|
-
* @returns {number}
|
|
175
|
-
*/
|
|
176
|
-
getNodeCount() {
|
|
177
|
-
return this.__nodes.size;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
182
|
/**
|
|
181
183
|
* Do not modify this set directly
|
|
182
184
|
* @return {Set<Edge<N>>}
|
|
@@ -217,8 +219,10 @@ export class Graph {
|
|
|
217
219
|
const context_0 = this.__nodes.get(edge.first);
|
|
218
220
|
const context_1 = this.__nodes.get(edge.second);
|
|
219
221
|
|
|
220
|
-
if (context_0 === undefined
|
|
221
|
-
throw new Error(
|
|
222
|
+
if (context_0 === undefined) {
|
|
223
|
+
throw new Error(`First node(=${edge.first}) of the edge is not part of the graph`);
|
|
224
|
+
} else if (context_1 === undefined) {
|
|
225
|
+
throw new Error(`Second node(=${edge.second}) of the edge is not part of the graph`);
|
|
222
226
|
}
|
|
223
227
|
|
|
224
228
|
context_0.addEdge(edge);
|
|
@@ -246,6 +250,7 @@ export class Graph {
|
|
|
246
250
|
const context_1 = this.__nodes.get(edge.second);
|
|
247
251
|
|
|
248
252
|
if (context_0 === undefined || context_1 === undefined) {
|
|
253
|
+
// this is a critical error, it should never happen as long as the API is used correctly
|
|
249
254
|
throw new Error('One or both nodes of the edge are not present on the graph. This is a critical error');
|
|
250
255
|
}
|
|
251
256
|
|
|
@@ -316,7 +321,7 @@ export class Graph {
|
|
|
316
321
|
const context_a = this.__nodes.get(a);
|
|
317
322
|
|
|
318
323
|
if (context_a === undefined) {
|
|
319
|
-
//
|
|
324
|
+
// A is not in the graph
|
|
320
325
|
return undefined;
|
|
321
326
|
}
|
|
322
327
|
|
|
@@ -334,10 +339,10 @@ export class Graph {
|
|
|
334
339
|
* @param {N} to
|
|
335
340
|
* @returns {Edge<N>|undefined}
|
|
336
341
|
*/
|
|
337
|
-
getAnyDirectedEdge(from, to){
|
|
342
|
+
getAnyDirectedEdge(from, to) {
|
|
338
343
|
const ctx_a = this.__nodes.get(from);
|
|
339
344
|
|
|
340
|
-
if(ctx_a === undefined){
|
|
345
|
+
if (ctx_a === undefined) {
|
|
341
346
|
return undefined;
|
|
342
347
|
}
|
|
343
348
|
|
|
@@ -1,10 +1,89 @@
|
|
|
1
|
-
import { Edge } from "../Edge.js";
|
|
1
|
+
import { Edge, EdgeDirectionType } from "../Edge.js";
|
|
2
2
|
import { Graph } from "./Graph.js";
|
|
3
|
+
import { jest } from "@jest/globals";
|
|
3
4
|
|
|
4
5
|
test("constructor doesn't throw", () => {
|
|
5
6
|
expect(() => new Graph()).not.toThrow();
|
|
6
7
|
});
|
|
7
8
|
|
|
9
|
+
test("adding same node twice", () => {
|
|
10
|
+
|
|
11
|
+
const graph = new Graph();
|
|
12
|
+
|
|
13
|
+
expect(graph.addNode(1)).toBe(true);
|
|
14
|
+
expect(graph.addNode(1)).toBe(false); // node already added
|
|
15
|
+
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("adding node triggers nodeAdded signal", () => {
|
|
19
|
+
|
|
20
|
+
const graph = new Graph();
|
|
21
|
+
|
|
22
|
+
const callback = jest.fn();
|
|
23
|
+
|
|
24
|
+
graph.on.nodeAdded.add(callback);
|
|
25
|
+
|
|
26
|
+
graph.addNode(7);
|
|
27
|
+
|
|
28
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
29
|
+
expect(callback).toHaveBeenCalledWith(7, graph);
|
|
30
|
+
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("removing node triggers nodeRemoved signal", () => {
|
|
34
|
+
|
|
35
|
+
const graph = new Graph();
|
|
36
|
+
|
|
37
|
+
const callback = jest.fn();
|
|
38
|
+
|
|
39
|
+
graph.on.nodeRemoved.add(callback);
|
|
40
|
+
|
|
41
|
+
graph.addNode(7);
|
|
42
|
+
|
|
43
|
+
expect(callback).not.toHaveBeenCalled();
|
|
44
|
+
|
|
45
|
+
graph.removeNode(1); // trying to remove non-existent node
|
|
46
|
+
|
|
47
|
+
expect(callback).not.toHaveBeenCalled();
|
|
48
|
+
|
|
49
|
+
graph.removeNode(7);
|
|
50
|
+
|
|
51
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
52
|
+
expect(callback).toHaveBeenCalledWith(7, graph);
|
|
53
|
+
|
|
54
|
+
graph.removeNode(7); //node was already removed, so we expect nothing to happen
|
|
55
|
+
|
|
56
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("check node existence", () => {
|
|
60
|
+
|
|
61
|
+
const graph = new Graph();
|
|
62
|
+
|
|
63
|
+
expect(graph.hasNode(1)).toBe(false);
|
|
64
|
+
|
|
65
|
+
graph.addNode(1);
|
|
66
|
+
|
|
67
|
+
expect(graph.hasNode(1)).toBe(true);
|
|
68
|
+
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("removing node that does not exist", () => {
|
|
72
|
+
const graph = new Graph();
|
|
73
|
+
|
|
74
|
+
expect(graph.removeNode(1)).toBe(false);
|
|
75
|
+
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("removing same node twice", () => {
|
|
79
|
+
const graph = new Graph();
|
|
80
|
+
|
|
81
|
+
graph.addNode(1);
|
|
82
|
+
|
|
83
|
+
expect(graph.removeNode(1)).toBe(true);
|
|
84
|
+
expect(graph.removeNode(1)).toBe(false);
|
|
85
|
+
});
|
|
86
|
+
|
|
8
87
|
test("nodeCount", () => {
|
|
9
88
|
const g = new Graph();
|
|
10
89
|
|
|
@@ -19,6 +98,122 @@ test("nodeCount", () => {
|
|
|
19
98
|
expect(g.nodeCount).toBe(0);
|
|
20
99
|
});
|
|
21
100
|
|
|
101
|
+
test("findNode on empty graph", () => {
|
|
102
|
+
const graph = new Graph();
|
|
103
|
+
|
|
104
|
+
expect(graph.findNode(n => n === 1)).toBe(undefined);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("findNode that doesn't exist on graph with 1 node", () => {
|
|
108
|
+
const graph = new Graph();
|
|
109
|
+
|
|
110
|
+
graph.addNode(3);
|
|
111
|
+
|
|
112
|
+
expect(graph.findNode(n => n === 1)).toBe(undefined);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("findNode amongst two", () => {
|
|
116
|
+
const graph = new Graph();
|
|
117
|
+
|
|
118
|
+
graph.addNode(1);
|
|
119
|
+
graph.addNode(3);
|
|
120
|
+
|
|
121
|
+
expect(graph.findNode(n => n === 3)).toBe(3);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("getNodeDegree", () => {
|
|
125
|
+
|
|
126
|
+
const graph = new Graph();
|
|
127
|
+
|
|
128
|
+
expect(graph.getNodeDegree(1)).toBe(0);
|
|
129
|
+
|
|
130
|
+
graph.addNode(1);
|
|
131
|
+
|
|
132
|
+
expect(graph.getNodeDegree(1)).toBe(0);
|
|
133
|
+
|
|
134
|
+
graph.addNode(3);
|
|
135
|
+
|
|
136
|
+
expect(graph.getNodeDegree(1)).toBe(0);
|
|
137
|
+
expect(graph.getNodeDegree(3)).toBe(0);
|
|
138
|
+
|
|
139
|
+
graph.createEdge(1, 3, EdgeDirectionType.Forward);
|
|
140
|
+
|
|
141
|
+
expect(graph.getNodeDegree(1)).toBe(1);
|
|
142
|
+
expect(graph.getNodeDegree(3)).toBe(1);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("createEdge", () => {
|
|
146
|
+
const graph = new Graph();
|
|
147
|
+
|
|
148
|
+
graph.addNode(1);
|
|
149
|
+
graph.addNode(2);
|
|
150
|
+
|
|
151
|
+
graph.createEdge(1, 2, EdgeDirectionType.Forward);
|
|
152
|
+
|
|
153
|
+
expect(graph.edgeCount).toBe(1);
|
|
154
|
+
|
|
155
|
+
expect(graph.edgeExistsBetween(1, 2)).toBe(true);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test("adding edge where one of the nodes is not part of the graph should throw and exception", () => {
|
|
159
|
+
const graph = new Graph();
|
|
160
|
+
|
|
161
|
+
expect(() => graph.addEdge(new Edge(1, 2))).toThrow();
|
|
162
|
+
|
|
163
|
+
graph.addNode(1);
|
|
164
|
+
|
|
165
|
+
expect(() => graph.addEdge(new Edge(1, 2))).toThrow();
|
|
166
|
+
|
|
167
|
+
graph.removeNode(1);
|
|
168
|
+
graph.addNode(2);
|
|
169
|
+
|
|
170
|
+
expect(() => graph.addEdge(new Edge(1, 2))).toThrow();
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test("add one valid edge", () => {
|
|
174
|
+
|
|
175
|
+
const graph = new Graph();
|
|
176
|
+
|
|
177
|
+
graph.addNode(1);
|
|
178
|
+
graph.addNode(2);
|
|
179
|
+
|
|
180
|
+
const edge = new Edge(1, 2);
|
|
181
|
+
expect(graph.addEdge(edge)).toBe(true);
|
|
182
|
+
|
|
183
|
+
expect(graph.hasEdge(edge)).toBe(true);
|
|
184
|
+
|
|
185
|
+
expect(graph.edgeCount).toBe(1);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test("add same edge twice", () => {
|
|
189
|
+
|
|
190
|
+
const graph = new Graph();
|
|
191
|
+
|
|
192
|
+
graph.addNode(1);
|
|
193
|
+
graph.addNode(2);
|
|
194
|
+
|
|
195
|
+
const edge = new Edge(1, 2);
|
|
196
|
+
|
|
197
|
+
expect(graph.addEdge(edge)).toBe(true);
|
|
198
|
+
expect(graph.addEdge(edge)).toBe(false); //already exists
|
|
199
|
+
|
|
200
|
+
expect(graph.hasEdge(edge)).toBe(true);
|
|
201
|
+
|
|
202
|
+
expect(graph.edgeCount).toBe(1);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
test("remove non-existing edge", () => {
|
|
206
|
+
|
|
207
|
+
const graph = new Graph();
|
|
208
|
+
|
|
209
|
+
graph.addNode(1);
|
|
210
|
+
graph.addNode(2);
|
|
211
|
+
|
|
212
|
+
const edge = new Edge(1, 2);
|
|
213
|
+
|
|
214
|
+
expect(graph.removeEdge(edge)).toBe(false);
|
|
215
|
+
});
|
|
216
|
+
|
|
22
217
|
test("edgeCount", () => {
|
|
23
218
|
const g = new Graph();
|
|
24
219
|
|
|
@@ -54,3 +249,116 @@ test("after removing an edge, neighborhood is properly updated", () => {
|
|
|
54
249
|
expect(g.getAttachedEdges(t, 1)).toBe(0);
|
|
55
250
|
expect(g.getAttachedEdges(t, 2)).toBe(0);
|
|
56
251
|
});
|
|
252
|
+
|
|
253
|
+
test("edgeExistsBetween", () => {
|
|
254
|
+
const graph = new Graph();
|
|
255
|
+
|
|
256
|
+
expect(graph.edgeExistsBetween(1, 2)).toBe(false);
|
|
257
|
+
expect(graph.edgeExistsBetween(2, 1)).toBe(false);
|
|
258
|
+
|
|
259
|
+
graph.addNode(1);
|
|
260
|
+
|
|
261
|
+
expect(graph.edgeExistsBetween(1, 2)).toBe(false);
|
|
262
|
+
expect(graph.edgeExistsBetween(2, 1)).toBe(false);
|
|
263
|
+
|
|
264
|
+
graph.addNode(2);
|
|
265
|
+
|
|
266
|
+
expect(graph.edgeExistsBetween(1, 2)).toBe(false);
|
|
267
|
+
expect(graph.edgeExistsBetween(2, 1)).toBe(false);
|
|
268
|
+
|
|
269
|
+
graph.createEdge(1, 2, EdgeDirectionType.Forward);
|
|
270
|
+
|
|
271
|
+
expect(graph.edgeExistsBetween(1, 2)).toBe(true);
|
|
272
|
+
expect(graph.edgeExistsBetween(2, 1)).toBe(true);
|
|
273
|
+
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
test("nodeHasEdges", () => {
|
|
277
|
+
const graph = new Graph();
|
|
278
|
+
|
|
279
|
+
expect(graph.nodeHasEdges(1)).toBe(false);
|
|
280
|
+
|
|
281
|
+
graph.addNode(1);
|
|
282
|
+
|
|
283
|
+
expect(graph.nodeHasEdges(1)).toBe(false);
|
|
284
|
+
|
|
285
|
+
graph.addNode(2);
|
|
286
|
+
|
|
287
|
+
expect(graph.nodeHasEdges(1)).toBe(false);
|
|
288
|
+
|
|
289
|
+
graph.createEdge(1, 2, EdgeDirectionType.Forward);
|
|
290
|
+
|
|
291
|
+
expect(graph.nodeHasEdges(1)).toBe(true);
|
|
292
|
+
expect(graph.nodeHasEdges(2)).toBe(true);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
test("getAnyEdgeBetween", () => {
|
|
296
|
+
|
|
297
|
+
const graph = new Graph();
|
|
298
|
+
|
|
299
|
+
expect(graph.getAnyEdgeBetween(1, 2)).toBe(undefined);
|
|
300
|
+
expect(graph.getAnyEdgeBetween(2, 1)).toBe(undefined);
|
|
301
|
+
|
|
302
|
+
graph.addNode(1);
|
|
303
|
+
|
|
304
|
+
expect(graph.getAnyEdgeBetween(1, 2)).toBe(undefined);
|
|
305
|
+
expect(graph.getAnyEdgeBetween(2, 1)).toBe(undefined);
|
|
306
|
+
|
|
307
|
+
graph.addNode(2);
|
|
308
|
+
|
|
309
|
+
expect(graph.getAnyEdgeBetween(1, 2)).toBe(undefined);
|
|
310
|
+
expect(graph.getAnyEdgeBetween(2, 1)).toBe(undefined);
|
|
311
|
+
|
|
312
|
+
const edge = graph.createEdge(1, 2, EdgeDirectionType.Forward);
|
|
313
|
+
|
|
314
|
+
expect(graph.getAnyEdgeBetween(1, 2)).toBe(edge);
|
|
315
|
+
expect(graph.getAnyEdgeBetween(2, 1)).toBe(edge);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
test("find path from node to itself", () => {
|
|
319
|
+
const graph = new Graph();
|
|
320
|
+
|
|
321
|
+
graph.addNode(1);
|
|
322
|
+
|
|
323
|
+
const path = graph.findPath(1, 1);
|
|
324
|
+
|
|
325
|
+
expect(path).toEqual([1]);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
test("find path with 2 hops", () => {
|
|
329
|
+
const graph = new Graph();
|
|
330
|
+
|
|
331
|
+
graph.addNode(1);
|
|
332
|
+
graph.addNode(2);
|
|
333
|
+
graph.addNode(3);
|
|
334
|
+
|
|
335
|
+
graph.createEdge(1, 2, EdgeDirectionType.Forward);
|
|
336
|
+
graph.createEdge(2, 3, EdgeDirectionType.Forward);
|
|
337
|
+
|
|
338
|
+
const path = graph.findPath(1, 3);
|
|
339
|
+
|
|
340
|
+
expect(path).toEqual([1, 2, 3]);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
test("clear method removes all nodes", () => {
|
|
344
|
+
const graph = new Graph();
|
|
345
|
+
|
|
346
|
+
graph.addNode(1);
|
|
347
|
+
|
|
348
|
+
graph.clear();
|
|
349
|
+
|
|
350
|
+
expect(graph.nodeCount).toBe(0);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
test("clear method removes all edges", () => {
|
|
354
|
+
const graph = new Graph();
|
|
355
|
+
|
|
356
|
+
graph.addNode(1);
|
|
357
|
+
graph.addNode(2);
|
|
358
|
+
|
|
359
|
+
graph.createEdge(1, 2, EdgeDirectionType.Forward);
|
|
360
|
+
|
|
361
|
+
graph.clear();
|
|
362
|
+
|
|
363
|
+
expect(graph.edgeCount).toBe(0);
|
|
364
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { fract } from "./fract.js";
|
|
2
|
+
|
|
3
|
+
test("correctness", () => {
|
|
4
|
+
|
|
5
|
+
expect(fract(0)).toBeCloseTo(0);
|
|
6
|
+
expect(fract(0.1)).toBeCloseTo(0.1);
|
|
7
|
+
expect(fract(-0.1)).toBeCloseTo(-0.1);
|
|
8
|
+
expect(fract(1.1)).toBeCloseTo(0.1);
|
|
9
|
+
expect(fract(-1.1)).toBeCloseTo(-0.1);
|
|
10
|
+
|
|
11
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { isPowerOfTwo } from "./isPowerOrTwo.js";
|
|
2
|
+
|
|
3
|
+
test("correctness", () => {
|
|
4
|
+
expect(isPowerOfTwo(1)).toBe(true);
|
|
5
|
+
expect(isPowerOfTwo(2)).toBe(true);
|
|
6
|
+
expect(isPowerOfTwo(3)).toBe(false);
|
|
7
|
+
expect(isPowerOfTwo(4)).toBe(true);
|
|
8
|
+
expect(isPowerOfTwo(5)).toBe(false);
|
|
9
|
+
});
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import { assert } from "../assert.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Is the number a power of two?
|
|
3
5
|
* e.g. 2,4,8,16 etc.
|
|
6
|
+
* NOTE: only valid for non-negative integers
|
|
4
7
|
* @param {number} value
|
|
5
8
|
* @returns {boolean}
|
|
6
9
|
*/
|
|
7
10
|
export function isPowerOfTwo(value) {
|
|
11
|
+
assert.isNonNegativeInteger(value, 'value');
|
|
12
|
+
|
|
8
13
|
|
|
9
14
|
return (value & (value - 1)) === 0 && value !== 0;
|
|
10
15
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { pingpong } from "./pingpong.js";
|
|
2
|
+
|
|
3
|
+
test("correctness", () => {
|
|
4
|
+
|
|
5
|
+
expect(pingpong(0, 1)).toBe(0);
|
|
6
|
+
expect(pingpong(0.1, 1)).toBeCloseTo(0.1);
|
|
7
|
+
expect(pingpong(1, 1)).toBe(1);
|
|
8
|
+
expect(pingpong(1.1, 1)).toBeCloseTo(0.9);
|
|
9
|
+
expect(pingpong(2.1, 1)).toBeCloseTo(0.1);
|
|
10
|
+
|
|
11
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { randomUint8 } from "./randomUint8.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {Uint8Array} result
|
|
6
|
+
* @param {number} result_offset
|
|
7
|
+
* @param {function():number} random
|
|
8
|
+
* @param {number} count
|
|
9
|
+
*/
|
|
10
|
+
export function randomBytes(result, result_offset, random, count) {
|
|
11
|
+
for (let i = 0; i < count; i++) {
|
|
12
|
+
|
|
13
|
+
result[result_offset + i] = randomUint8(random);
|
|
14
|
+
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { returnOne, returnZero } from "../../function/Functions.js";
|
|
2
|
+
import { randomFloatBetween } from "./randomFloatBetween.js";
|
|
3
|
+
|
|
4
|
+
test("limits", () => {
|
|
5
|
+
|
|
6
|
+
expect(randomFloatBetween(returnZero, -3.11, 7.23)).toEqual(-3.11);
|
|
7
|
+
expect(randomFloatBetween(returnOne, -3.11, 7.23)).toEqual(7.23);
|
|
8
|
+
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { assert } from "../../assert.js";
|
|
2
|
-
import {
|
|
2
|
+
import { randomIntegerBetween } from "./randomIntegerBetween.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @template T
|
|
@@ -13,7 +13,7 @@ export function randomFromArray(random, array) {
|
|
|
13
13
|
|
|
14
14
|
const length = array.length;
|
|
15
15
|
|
|
16
|
-
const
|
|
16
|
+
const index = randomIntegerBetween(random, 0, length - 1);
|
|
17
17
|
|
|
18
|
-
return array[
|
|
18
|
+
return array[index];
|
|
19
19
|
}
|