webglmusti 0.0.0
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/.gitattributes +2 -0
- package/idea_list.txt +13 -0
- package/index.html +17 -0
- package/package.json +20 -0
- package/public/apple.png +0 -0
- package/public/base.png +0 -0
- package/public/car.png +0 -0
- package/public/drop.png +0 -0
- package/public/font16-Sheet.png +0 -0
- package/public/font16-Sheet.txt +52 -0
- package/public/letters-Sheet.png +0 -0
- package/public/letters-Sheet.txt +27 -0
- package/public/letters_Sheet.png +0 -0
- package/public/letters_Sheet.txt +4 -0
- package/public/vite.svg +1 -0
- package/src/App/ResourceSim/car.ts +172 -0
- package/src/App/ResourceSim/grid.ts +993 -0
- package/src/App/ResourceSim/grid_app.ts +1326 -0
- package/src/App/ResourceSim/grid_test.test.ts +18 -0
- package/src/App/ResourceSim/node_graph.ts +293 -0
- package/src/App/ResourceSim/nodes.ts +151 -0
- package/src/App/ResourceSim/resource.ts +8 -0
- package/src/App/ResourceSim/texts.ts +6 -0
- package/src/App/card/card.test.ts +22 -0
- package/src/App/card/card.ts +763 -0
- package/src/App/puzzle_box/app.ts +10 -0
- package/src/App/puzzle_box/engine.ts +374 -0
- package/src/App/puzzle_box/renderer.ts +102 -0
- package/src/App/puzzle_box/test.test.ts +49 -0
- package/src/App/water/water.ts +206 -0
- package/src/Interface/button.ts +345 -0
- package/src/Interface/interface_element.ts +30 -0
- package/src/Interface/internal_window.ts +100 -0
- package/src/Interface/options.ts +332 -0
- package/src/Interface/text_input.ts +183 -0
- package/src/WebGL/Matrix/matrix.test.ts +30 -0
- package/src/WebGL/Matrix/matrix.ts +293 -0
- package/src/WebGL/Shaders/Fragment/Program/circle.ts +49 -0
- package/src/WebGL/Shaders/Fragment/Program/circle_only.ts +47 -0
- package/src/WebGL/Shaders/Fragment/Program/circle_outline.ts +54 -0
- package/src/WebGL/Shaders/Fragment/Program/colour.ts +39 -0
- package/src/WebGL/Shaders/Fragment/Program/colour_alpha.ts +37 -0
- package/src/WebGL/Shaders/Fragment/Program/line.ts +39 -0
- package/src/WebGL/Shaders/Fragment/Program/multi_colour_centre_circle_path.ts +69 -0
- package/src/WebGL/Shaders/Fragment/Program/multi_colour_path.ts +69 -0
- package/src/WebGL/Shaders/Fragment/Program/path_centre_circle.ts +69 -0
- package/src/WebGL/Shaders/Fragment/Program/rect_outline.ts +39 -0
- package/src/WebGL/Shaders/Fragment/Program/solid_path.ts +64 -0
- package/src/WebGL/Shaders/Fragment/Program/sprite_sheet.ts +54 -0
- package/src/WebGL/Shaders/Fragment/Program/sprite_sheet_colour.ts +62 -0
- package/src/WebGL/Shaders/Fragment/Program/texture.ts +34 -0
- package/src/WebGL/Shaders/Fragment/Source/circle.frag +19 -0
- package/src/WebGL/Shaders/Fragment/Source/circle_only.frag +15 -0
- package/src/WebGL/Shaders/Fragment/Source/circle_outline.frag +23 -0
- package/src/WebGL/Shaders/Fragment/Source/colour.frag +9 -0
- package/src/WebGL/Shaders/Fragment/Source/colour_alpha.frag +7 -0
- package/src/WebGL/Shaders/Fragment/Source/fragment.frag +5 -0
- package/src/WebGL/Shaders/Fragment/Source/fragment_source.ts +15 -0
- package/src/WebGL/Shaders/Fragment/Source/line.frag +12 -0
- package/src/WebGL/Shaders/Fragment/Source/multi_colour_centre_circle_path.frag +36 -0
- package/src/WebGL/Shaders/Fragment/Source/multi_colour_path.frag +34 -0
- package/src/WebGL/Shaders/Fragment/Source/path_centre_circle.frag +29 -0
- package/src/WebGL/Shaders/Fragment/Source/rect_outline.frag +20 -0
- package/src/WebGL/Shaders/Fragment/Source/solid_path.frag +24 -0
- package/src/WebGL/Shaders/Fragment/Source/sprite_sheet.frag +17 -0
- package/src/WebGL/Shaders/Fragment/Source/sprite_sheet_colour.frag +19 -0
- package/src/WebGL/Shaders/Fragment/Source/texture.frag +11 -0
- package/src/WebGL/Shaders/Fragment/fragment.ts +43 -0
- package/src/WebGL/Shaders/Fragment/fragment_old.ts +261 -0
- package/src/WebGL/Shaders/Vertex/Program/mvp2d.ts +41 -0
- package/src/WebGL/Shaders/Vertex/Program/transform2d.ts +39 -0
- package/src/WebGL/Shaders/Vertex/Source/mvp2d.vert +17 -0
- package/src/WebGL/Shaders/Vertex/Source/mvp_i_2d.vert +18 -0
- package/src/WebGL/Shaders/Vertex/Source/simple.vert +9 -0
- package/src/WebGL/Shaders/Vertex/Source/transform2d.vert +13 -0
- package/src/WebGL/Shaders/Vertex/Source/transform2d_rel.vert +16 -0
- package/src/WebGL/Shaders/Vertex/Source/translate2d.vert +7 -0
- package/src/WebGL/Shaders/Vertex/Source/vertex_source.ts +13 -0
- package/src/WebGL/Shaders/Vertex/vertex.ts +10 -0
- package/src/WebGL/Shaders/Vertex/vertex_old.ts +289 -0
- package/src/WebGL/Shaders/custom.ts +129 -0
- package/src/WebGL/Shaders/shader.ts +197 -0
- package/src/WebGL/Shapes/Line.ts +29 -0
- package/src/WebGL/Shapes/Shapes.ts +189 -0
- package/src/WebGL/Texture/texture.ts +214 -0
- package/src/WebGL/Util/file.ts +24 -0
- package/src/WebGL/app.ts +150 -0
- package/src/WebGL/colour.ts +71 -0
- package/src/WebGL/globals.ts +353 -0
- package/src/WebGL/index.ts +3 -0
- package/src/WebGL/mixin.ts +2 -0
- package/src/global.d.ts +13 -0
- package/src/index.ts +4 -0
- package/src/main.ts +139 -0
- package/src/utils/array.ts +154 -0
- package/src/utils/assert.ts +8 -0
- package/src/utils/file.ts +0 -0
- package/src/utils/mixin.ts +22 -0
- package/src/utils/numbers.ts +11 -0
- package/src/utils/utils.test.ts +23 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +25 -0
|
@@ -0,0 +1,993 @@
|
|
|
1
|
+
import * as Matrix from "../../WebGL/Matrix/matrix";
|
|
2
|
+
import * as ArrayUtils from "../../utils/array";
|
|
3
|
+
import * as PQ from "@datastructures-js/priority-queue"
|
|
4
|
+
|
|
5
|
+
type Int32 = number;
|
|
6
|
+
type Float = number;
|
|
7
|
+
|
|
8
|
+
export class GridPosition{
|
|
9
|
+
x: Int32;
|
|
10
|
+
y: Int32;
|
|
11
|
+
constructor(x:Int32, y:Int32){
|
|
12
|
+
this.x = x;
|
|
13
|
+
this.y = y;
|
|
14
|
+
}
|
|
15
|
+
addCopy(gp: GridPosition): GridPosition{
|
|
16
|
+
return new GridPosition(this.x+gp.x, this.y+gp.y);
|
|
17
|
+
}
|
|
18
|
+
copy(): GridPosition{
|
|
19
|
+
return new GridPosition(this.x, this.y);
|
|
20
|
+
}
|
|
21
|
+
equals(gp: GridPosition): boolean{
|
|
22
|
+
return this.x == gp.x && this.y == gp.y;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static manhattanDistance(p1: GridPosition, p2: GridPosition): Int32{
|
|
26
|
+
return Math.abs(p1.x-p2.x) + Math.abs(p1.y-p2.y);
|
|
27
|
+
}
|
|
28
|
+
static euclidianDistanceSquared(p1: GridPosition, p2: GridPosition): Int32{
|
|
29
|
+
const dx = Math.abs(p1.x-p2.x);
|
|
30
|
+
const dy = Math.abs(p1.y-p2.y);
|
|
31
|
+
return dx*dx+dy*dy;
|
|
32
|
+
}
|
|
33
|
+
static euclidianDistance(p1: GridPosition, p2: GridPosition): Float{
|
|
34
|
+
return Math.sqrt(this.euclidianDistanceSquared(p1, p2));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static testEuclidianDistance(limit: Float){
|
|
38
|
+
type GridEucildianCompare = {
|
|
39
|
+
position: GridPosition;
|
|
40
|
+
distance_squared: Float;
|
|
41
|
+
};
|
|
42
|
+
const limit_sq = limit*limit;
|
|
43
|
+
const pq = new PQ.PriorityQueue((a:GridEucildianCompare,b:GridEucildianCompare) => a.distance_squared-b.distance_squared);
|
|
44
|
+
|
|
45
|
+
const p0 = new GridPosition(0, 0);
|
|
46
|
+
pq.enqueue({position: p0, distance_squared: this.euclidianDistanceSquared(p0, p0)});
|
|
47
|
+
const comps = [];
|
|
48
|
+
|
|
49
|
+
type PositionsAtDistance = {
|
|
50
|
+
positions: GridPosition[];
|
|
51
|
+
distance_squared: Float;
|
|
52
|
+
}
|
|
53
|
+
const positions_at_distance:PositionsAtDistance[] = [];
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
while(!pq.isEmpty()){
|
|
57
|
+
const top = pq.dequeue()!;
|
|
58
|
+
const pos = top.position.copy();
|
|
59
|
+
|
|
60
|
+
const positions: GridPosition[] = [];
|
|
61
|
+
if(pos.x == 0 && pos.y == 0){
|
|
62
|
+
positions.push(new GridPosition(pos.x, pos.y));
|
|
63
|
+
}/*else if(pos.x == 0){
|
|
64
|
+
positions.push(new GridPosition(pos.x, pos.y));
|
|
65
|
+
positions.push(new GridPosition(pos.x, -pos.y));
|
|
66
|
+
}*/else if(pos.y == 0){
|
|
67
|
+
positions.push(new GridPosition(pos.x, 0));
|
|
68
|
+
positions.push(new GridPosition(-pos.x, 0));
|
|
69
|
+
positions.push(new GridPosition(0, pos.x));
|
|
70
|
+
positions.push(new GridPosition(0, -pos.x));
|
|
71
|
+
}else{
|
|
72
|
+
positions.push(new GridPosition(pos.x, pos.y));
|
|
73
|
+
positions.push(new GridPosition(-pos.x, pos.y));
|
|
74
|
+
positions.push(new GridPosition(pos.x, -pos.y));
|
|
75
|
+
positions.push(new GridPosition(-pos.x, -pos.y));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
console.log(pos);
|
|
79
|
+
console.log(top.distance_squared);
|
|
80
|
+
comps.push({position: new GridPosition(pos.x, pos.y), distance_squared: top.distance_squared});
|
|
81
|
+
comps.push({position: new GridPosition(-pos.x, pos.y), distance_squared: top.distance_squared});
|
|
82
|
+
comps.push({position: new GridPosition(pos.x, -pos.y), distance_squared: top.distance_squared});
|
|
83
|
+
comps.push({position: new GridPosition(-pos.x, -pos.y), distance_squared: top.distance_squared});
|
|
84
|
+
|
|
85
|
+
const posx = new GridPosition(pos.x+1, pos.y);
|
|
86
|
+
const dsx = this.euclidianDistanceSquared(p0, posx);
|
|
87
|
+
if(dsx <= limit_sq){
|
|
88
|
+
pq.enqueue({position: posx, distance_squared: dsx});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if(pos.x != pos.y){
|
|
92
|
+
if(pos.y != 0){
|
|
93
|
+
positions.push(new GridPosition(pos.y, pos.x));
|
|
94
|
+
positions.push(new GridPosition(-pos.y, pos.x));
|
|
95
|
+
positions.push(new GridPosition(pos.y, -pos.x));
|
|
96
|
+
positions.push(new GridPosition(-pos.y, -pos.x));
|
|
97
|
+
}
|
|
98
|
+
comps.push({position: new GridPosition(pos.y, pos.x), distance_squared: top.distance_squared});
|
|
99
|
+
comps.push({position: new GridPosition(-pos.y, pos.x), distance_squared: top.distance_squared});
|
|
100
|
+
comps.push({position: new GridPosition(pos.y, -pos.x), distance_squared: top.distance_squared});
|
|
101
|
+
comps.push({position: new GridPosition(-pos.y, -pos.x), distance_squared: top.distance_squared});
|
|
102
|
+
//do y as well
|
|
103
|
+
const posy = new GridPosition(pos.x, pos.y+1);
|
|
104
|
+
const dsy = this.euclidianDistanceSquared(p0, posy);
|
|
105
|
+
if(!pq.isEmpty() && pq.front()!.distance_squared != dsy && dsy <= limit_sq){
|
|
106
|
+
pq.enqueue({position: posy, distance_squared: dsy});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
positions_at_distance.push({positions, distance_squared: top.distance_squared});
|
|
111
|
+
}
|
|
112
|
+
console.log(positions_at_distance);
|
|
113
|
+
console.log(comps);
|
|
114
|
+
return comps;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
//generates track from p1 to p2 with one turn only
|
|
119
|
+
static randomPointToPoint1TurnTrack(p1: GridPosition, p2: GridPosition): Track{
|
|
120
|
+
const rand = Math.random();
|
|
121
|
+
return this.oneTurnTrackFrom2Points(p1, p2, rand > 0.5);
|
|
122
|
+
/*
|
|
123
|
+
const track_part = new TrackPart();
|
|
124
|
+
//straight line conditions
|
|
125
|
+
const dir_x = p1.x > p2.x ? DirectionEnum.Left : DirectionEnum.Right;
|
|
126
|
+
const dir_y = p1.y > p2.y ? DirectionEnum.Up : DirectionEnum.Down;
|
|
127
|
+
const dist_x = Math.abs(p1.x-p2.x);
|
|
128
|
+
const dist_y= Math.abs(p1.y-p2.y);
|
|
129
|
+
if(p1.x === p2.x){
|
|
130
|
+
if(p1.y !== p2.y){
|
|
131
|
+
//only goes vertical
|
|
132
|
+
track_part.addMove(dist_y, dir_y);
|
|
133
|
+
}
|
|
134
|
+
}else if(p1.y === p2.y){
|
|
135
|
+
//horizontal
|
|
136
|
+
track_part.addMove(dist_x, dir_x);
|
|
137
|
+
}else{ // has turn
|
|
138
|
+
const rand = Math.random();
|
|
139
|
+
|
|
140
|
+
if(rand > 0.5){
|
|
141
|
+
//vertical first
|
|
142
|
+
track_part.addMove(dist_y, dir_y);
|
|
143
|
+
track_part.addMove(dist_x, dir_x);
|
|
144
|
+
}else{
|
|
145
|
+
//horizontal first
|
|
146
|
+
track_part.addMove(dist_x, dir_x);
|
|
147
|
+
track_part.addMove(dist_y, dir_y);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return new Track(track_part, p1);*/
|
|
152
|
+
}
|
|
153
|
+
static oneTurnTrackFrom2Points(p1: GridPosition, p2: GridPosition, horizontal_first: boolean=true): Track{
|
|
154
|
+
const dir_x = p1.x > p2.x ? DirectionEnum.Left : DirectionEnum.Right;
|
|
155
|
+
const dir_y = p1.y > p2.y ? DirectionEnum.Up : DirectionEnum.Down;
|
|
156
|
+
const dist_x = Math.abs(p1.x-p2.x);
|
|
157
|
+
const dist_y= Math.abs(p1.y-p2.y);
|
|
158
|
+
const track_part = new TrackPart();
|
|
159
|
+
if(dist_x == 0){
|
|
160
|
+
if(dist_y != 0){
|
|
161
|
+
track_part.addMove(dist_y, dir_y);
|
|
162
|
+
}
|
|
163
|
+
}else if(dist_y == 0){
|
|
164
|
+
track_part.addMove(dist_x, dir_x);
|
|
165
|
+
}else{
|
|
166
|
+
if(horizontal_first){
|
|
167
|
+
track_part.addMove(dist_x, dir_x);
|
|
168
|
+
track_part.addMove(dist_y, dir_y);
|
|
169
|
+
}else{
|
|
170
|
+
track_part.addMove(dist_y, dir_y);
|
|
171
|
+
track_part.addMove(dist_x, dir_x);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return new Track(track_part, p1);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
static filterInsideGrid(positions: GridPosition[], grid: RectGrid): GridPosition[]{
|
|
179
|
+
return positions.filter((p) => grid.isInsideGrid(p.x, p.y));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
static positionsExactDistanceAway(p: GridPosition, dist: Int32): GridPosition[]{
|
|
183
|
+
if(dist == 0){
|
|
184
|
+
return [new GridPosition(p.x, p.y)];
|
|
185
|
+
}
|
|
186
|
+
const positions: GridPosition[] = [];
|
|
187
|
+
positions.push(new GridPosition(p.x, p.y-dist));
|
|
188
|
+
for(let i = -dist+1; i < 0; i++){
|
|
189
|
+
const dx = i + dist;
|
|
190
|
+
positions.push(new GridPosition(p.x-dx, p.y-i));
|
|
191
|
+
positions.push(new GridPosition(p.x-dx, p.y+i));
|
|
192
|
+
}
|
|
193
|
+
positions.push(new GridPosition(p.x-dist, p.y));
|
|
194
|
+
positions.push(new GridPosition(p.x+dist, p.y));
|
|
195
|
+
for(let i = 1; i < dist; i++){
|
|
196
|
+
const dx = i - dist;
|
|
197
|
+
positions.push(new GridPosition(p.x-dx, p.y-i));
|
|
198
|
+
positions.push(new GridPosition(p.x-dx, p.y+i));
|
|
199
|
+
}
|
|
200
|
+
positions.push(new GridPosition(p.x, p.y+dist));
|
|
201
|
+
return positions;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
static allPositionsDistanceAway(p: GridPosition, dist: Int32): GridPosition[][]{
|
|
205
|
+
const positions = [];
|
|
206
|
+
for(let i = 0; i <= dist; i++){
|
|
207
|
+
positions.push(this.positionsExactDistanceAway(p, i));
|
|
208
|
+
}
|
|
209
|
+
return positions;
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
export const DirectionEnum = {
|
|
216
|
+
Up: 0, Right: 1, Down: 2, Left: 3
|
|
217
|
+
} as const;
|
|
218
|
+
|
|
219
|
+
export type GridDirection = (typeof DirectionEnum)[keyof typeof DirectionEnum];
|
|
220
|
+
|
|
221
|
+
export type ActiveDirections = {
|
|
222
|
+
left: boolean;
|
|
223
|
+
up: boolean;
|
|
224
|
+
right: boolean;
|
|
225
|
+
down: boolean;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export type GridPositionWithDirections = {
|
|
229
|
+
position: GridPosition;
|
|
230
|
+
directions: ActiveDirections;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export const TurnDirectionEnum = {
|
|
234
|
+
Straight: 0,
|
|
235
|
+
Clockwise: 1,
|
|
236
|
+
AntiClockwise: 2
|
|
237
|
+
} as const;
|
|
238
|
+
|
|
239
|
+
type TurnDirection = (typeof TurnDirectionEnum)[keyof typeof TurnDirectionEnum]
|
|
240
|
+
|
|
241
|
+
// Track - Physical space an object can move on (cannot go back on itself) e.g. left 2, right 2
|
|
242
|
+
// Path - Movement of an object (can go back on itself)
|
|
243
|
+
|
|
244
|
+
export class DirectionUtil{
|
|
245
|
+
static directions: GridPosition[] = [new GridPosition(0, 1), new GridPosition(1, 0), new GridPosition(0, -1), new GridPosition(-1, 0)];
|
|
246
|
+
static turnDirectionToRadians(dir: GridDirection): Float{
|
|
247
|
+
switch(dir){
|
|
248
|
+
case DirectionEnum.Up:
|
|
249
|
+
return 0;
|
|
250
|
+
case DirectionEnum.Right:
|
|
251
|
+
return Math.PI*0.5;
|
|
252
|
+
case DirectionEnum.Down:
|
|
253
|
+
return Math.PI;
|
|
254
|
+
case DirectionEnum.Left:
|
|
255
|
+
return Math.PI*1.5;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
static getTurnDirection(dir: GridDirection, rads: Float): TurnDirection{
|
|
259
|
+
rads %= (Math.PI*2);
|
|
260
|
+
switch(dir){
|
|
261
|
+
case DirectionEnum.Left:
|
|
262
|
+
rads -= Math.PI*1.5;
|
|
263
|
+
break;
|
|
264
|
+
case DirectionEnum.Down:
|
|
265
|
+
rads -= Math.PI;
|
|
266
|
+
break;
|
|
267
|
+
case DirectionEnum.Right:
|
|
268
|
+
rads -= Math.PI*0.5;
|
|
269
|
+
break;
|
|
270
|
+
case DirectionEnum.Up:
|
|
271
|
+
break;
|
|
272
|
+
default:
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
if(rads < 0){
|
|
276
|
+
rads += Math.PI*2;
|
|
277
|
+
}
|
|
278
|
+
if(rads === 0){
|
|
279
|
+
return TurnDirectionEnum.Straight;
|
|
280
|
+
}
|
|
281
|
+
return rads < Math.PI ? TurnDirectionEnum.AntiClockwise : TurnDirectionEnum.Clockwise;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
static isSameAxis(dir1: GridDirection, dir2: GridDirection): boolean{
|
|
285
|
+
if(dir1 == DirectionEnum.Left || dir1 == DirectionEnum.Right){
|
|
286
|
+
return dir2 == DirectionEnum.Left || dir2 == DirectionEnum.Right;
|
|
287
|
+
}
|
|
288
|
+
return dir2 == DirectionEnum.Up || dir2 == DirectionEnum.Down;
|
|
289
|
+
}
|
|
290
|
+
static opposite(direction: GridDirection): GridDirection{
|
|
291
|
+
switch(direction){
|
|
292
|
+
case DirectionEnum.Down:
|
|
293
|
+
return DirectionEnum.Up;
|
|
294
|
+
case DirectionEnum.Left:
|
|
295
|
+
return DirectionEnum.Right;
|
|
296
|
+
case DirectionEnum.Up:
|
|
297
|
+
return DirectionEnum.Down;
|
|
298
|
+
case DirectionEnum.Right:
|
|
299
|
+
return DirectionEnum.Left;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
static copyMovePosition(dir: GridDirection, pos: GridPosition, move: Int32=1): GridPosition{
|
|
303
|
+
const new_position = pos.copy();
|
|
304
|
+
if(dir === DirectionEnum.Right){
|
|
305
|
+
new_position.x += move;
|
|
306
|
+
}else if(dir === DirectionEnum.Left){
|
|
307
|
+
new_position.x -= move;
|
|
308
|
+
}else if(dir === DirectionEnum.Up){
|
|
309
|
+
new_position.y -= move;
|
|
310
|
+
}else if(dir === DirectionEnum.Down){
|
|
311
|
+
new_position.y += move;
|
|
312
|
+
}
|
|
313
|
+
return new_position;
|
|
314
|
+
}
|
|
315
|
+
static movePosition(dir: GridDirection, pos: GridPosition, move: Int32=1){
|
|
316
|
+
if(dir === DirectionEnum.Right){
|
|
317
|
+
pos.x += move;
|
|
318
|
+
}else if(dir === DirectionEnum.Left){
|
|
319
|
+
pos.x -= move;
|
|
320
|
+
}else if(dir === DirectionEnum.Up){
|
|
321
|
+
pos.y -= move;
|
|
322
|
+
}else if(dir === DirectionEnum.Down){
|
|
323
|
+
pos.y += move;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
static directionsBetween2Points(from: GridPosition, to: GridPosition): GridDirection[]{
|
|
327
|
+
const dirs: GridDirection[] = [];
|
|
328
|
+
if(from.x != to.x){
|
|
329
|
+
if(from.x < to.x){
|
|
330
|
+
dirs.push(DirectionEnum.Right);
|
|
331
|
+
}else{
|
|
332
|
+
dirs.push(DirectionEnum.Left);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if(from.y != to.y){
|
|
336
|
+
if(from.y < to.y){
|
|
337
|
+
dirs.push(DirectionEnum.Down);
|
|
338
|
+
}else{
|
|
339
|
+
dirs.push(DirectionEnum.Up);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return dirs;
|
|
343
|
+
}
|
|
344
|
+
static fromFloatsInGridDecimal(x: Float, y: Float): GridDirection {
|
|
345
|
+
if(x < 0) x = 1 + x;
|
|
346
|
+
if(y < 0) y = 1 + y;
|
|
347
|
+
const diag = 1 - x < y;
|
|
348
|
+
if(x > y){
|
|
349
|
+
return diag ? DirectionEnum.Right : DirectionEnum.Up;
|
|
350
|
+
}
|
|
351
|
+
return diag ? DirectionEnum.Down : DirectionEnum.Left;
|
|
352
|
+
}
|
|
353
|
+
static toString(dir: GridDirection): string{
|
|
354
|
+
switch(dir){
|
|
355
|
+
case DirectionEnum.Down:
|
|
356
|
+
return "Down";
|
|
357
|
+
case DirectionEnum.Left:
|
|
358
|
+
return "Left";
|
|
359
|
+
case DirectionEnum.Up:
|
|
360
|
+
return "Up";
|
|
361
|
+
case DirectionEnum.Right:
|
|
362
|
+
return "Right";
|
|
363
|
+
}
|
|
364
|
+
return "";
|
|
365
|
+
}
|
|
366
|
+
static blankActiveDirections(): ActiveDirections{
|
|
367
|
+
return {left: false, up: false, right: false, down: false};
|
|
368
|
+
}
|
|
369
|
+
static setActiveDirection(active_directions: ActiveDirections, value: boolean, direction: GridDirection){
|
|
370
|
+
switch(direction){
|
|
371
|
+
case DirectionEnum.Left:
|
|
372
|
+
active_directions.left = value;
|
|
373
|
+
break;
|
|
374
|
+
case DirectionEnum.Down:
|
|
375
|
+
active_directions.down = value;
|
|
376
|
+
break;
|
|
377
|
+
case DirectionEnum.Right:
|
|
378
|
+
active_directions.right = value;
|
|
379
|
+
break;
|
|
380
|
+
case DirectionEnum.Up:
|
|
381
|
+
active_directions.up = value;
|
|
382
|
+
break;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
static isActiveDirection(active_directions: ActiveDirections, direction:GridDirection): boolean{
|
|
386
|
+
switch(direction){
|
|
387
|
+
case DirectionEnum.Left:
|
|
388
|
+
return active_directions.left;
|
|
389
|
+
case DirectionEnum.Down:
|
|
390
|
+
return active_directions.down;
|
|
391
|
+
case DirectionEnum.Right:
|
|
392
|
+
return active_directions.right;
|
|
393
|
+
case DirectionEnum.Up:
|
|
394
|
+
return active_directions.up;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
//static isSameDirection(dir)
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
type GridStraightMove = {
|
|
401
|
+
direction: GridDirection;
|
|
402
|
+
distance: Int32;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
class StraightMoveUtil{
|
|
406
|
+
static mergeMove(){
|
|
407
|
+
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
export class TrackMap{
|
|
412
|
+
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
export class Track{
|
|
417
|
+
part: TrackPart;
|
|
418
|
+
starting_location: GridPosition;
|
|
419
|
+
constructor(tp: TrackPart, pos: GridPosition){
|
|
420
|
+
this.part = tp;
|
|
421
|
+
this.starting_location = pos.copy();
|
|
422
|
+
}
|
|
423
|
+
toPositions(): GridPosition[]{
|
|
424
|
+
const positions: GridPosition[] = [new GridPosition(this.starting_location.x, this.starting_location.y)];
|
|
425
|
+
for(const pt of this.part.getMoves()){
|
|
426
|
+
for(let i = 0; i < pt.distance; i++){
|
|
427
|
+
positions.push(DirectionUtil.copyMovePosition(pt.direction, positions.at(-1)!));
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
return positions;
|
|
431
|
+
}
|
|
432
|
+
endPoint(): GridPosition{
|
|
433
|
+
const p = this.starting_location.copy();
|
|
434
|
+
for(const part of this.part.getMoves()){
|
|
435
|
+
DirectionUtil.movePosition(part.direction, p, part.distance);
|
|
436
|
+
}
|
|
437
|
+
return p;
|
|
438
|
+
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
//
|
|
443
|
+
export class TrackPart{
|
|
444
|
+
private moves: GridStraightMove[];
|
|
445
|
+
constructor(){
|
|
446
|
+
this.moves = [];
|
|
447
|
+
}
|
|
448
|
+
addMove(distance: Int32, direction: GridDirection){
|
|
449
|
+
this.moves.push({direction, distance});
|
|
450
|
+
}
|
|
451
|
+
condenseToTrack(){
|
|
452
|
+
|
|
453
|
+
}
|
|
454
|
+
getMoves(): GridStraightMove[]{
|
|
455
|
+
return this.moves;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
export class RectGrid{
|
|
461
|
+
width: Int32; // cells across
|
|
462
|
+
height: Int32; // cells down
|
|
463
|
+
size: number;
|
|
464
|
+
|
|
465
|
+
half_size: number;
|
|
466
|
+
|
|
467
|
+
pixel_width: number; //
|
|
468
|
+
pixel_height: number;
|
|
469
|
+
|
|
470
|
+
x: number;
|
|
471
|
+
y: number;
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
constructor(w: Int32, h: Int32, s: number){
|
|
475
|
+
this.width = w;
|
|
476
|
+
this.height = h;
|
|
477
|
+
this.size = s;
|
|
478
|
+
this.half_size = s/2;
|
|
479
|
+
this.pixel_width = w*s;
|
|
480
|
+
this.pixel_height = h*s;
|
|
481
|
+
|
|
482
|
+
this.x = 0;
|
|
483
|
+
this.y = 0;
|
|
484
|
+
}
|
|
485
|
+
isInsideGrid(x:number, y:number): boolean{
|
|
486
|
+
return x >= 0 && x < this.width && y >= 0 && y < this.height;
|
|
487
|
+
}
|
|
488
|
+
isInsidePixel(x: number, y: number): boolean{
|
|
489
|
+
const right = this.x + this.pixel_width;
|
|
490
|
+
const bottom = this.y + this.pixel_height;
|
|
491
|
+
return x >= this.x && x <= right && y >= this.y && y <= bottom;
|
|
492
|
+
}
|
|
493
|
+
getPosition(x: number, y: number): GridPosition | undefined{
|
|
494
|
+
if(!this.isInsidePixel(x, y)) return undefined;
|
|
495
|
+
const gx = Math.floor((x - this.x)/this.size);
|
|
496
|
+
const gy = Math.floor((y - this.y)/this.size);
|
|
497
|
+
return new GridPosition(gx, gy);
|
|
498
|
+
}
|
|
499
|
+
getTransformation(x: number, y: number): Matrix.TransformationMatrix3x3{
|
|
500
|
+
const model = Matrix.TransformationMatrix3x3.translate(this.x+x*this.size, this.y+y*this.size);
|
|
501
|
+
model.multiply(Matrix.TransformationMatrix3x3.scale(this.size, this.size));
|
|
502
|
+
return model;
|
|
503
|
+
}
|
|
504
|
+
getCenterTransformation(x: number, y: number): Matrix.TransformationMatrix3x3{
|
|
505
|
+
const model = Matrix.TransformationMatrix3x3.translate(this.x+this.half_size+x*this.size, this.y+this.half_size+y*this.size);
|
|
506
|
+
model.multiply(Matrix.TransformationMatrix3x3.scale(this.size, this.size));
|
|
507
|
+
return model;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
export const TileStateEnum = {
|
|
512
|
+
Nothing: 0, Path: 1, Highlight: 2, Preview: 3
|
|
513
|
+
} as const;
|
|
514
|
+
|
|
515
|
+
export type TileState = (typeof TileStateEnum)[keyof typeof TileStateEnum];
|
|
516
|
+
|
|
517
|
+
function randomTileState(): TileState{
|
|
518
|
+
let r = Math.random();
|
|
519
|
+
return Math.floor(r*Object.keys(TileStateEnum).length) as TileState;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
export class WallTile{
|
|
523
|
+
left: TileState;
|
|
524
|
+
top: TileState;
|
|
525
|
+
right: TileState;
|
|
526
|
+
bottom: TileState;
|
|
527
|
+
is_key: boolean;
|
|
528
|
+
node_id: Int32 | undefined;
|
|
529
|
+
is_selected: boolean;
|
|
530
|
+
constructor(){
|
|
531
|
+
this.left = TileStateEnum.Nothing;
|
|
532
|
+
this.bottom = TileStateEnum.Nothing;
|
|
533
|
+
this.right = TileStateEnum.Nothing;
|
|
534
|
+
this.top = TileStateEnum.Nothing;
|
|
535
|
+
this.is_key = false;
|
|
536
|
+
this.is_selected = false;
|
|
537
|
+
}
|
|
538
|
+
/* no longer a thing
|
|
539
|
+
setDirection(direction: GridDirection, value: boolean){
|
|
540
|
+
switch(direction){
|
|
541
|
+
case DirectionEnum.Down:
|
|
542
|
+
this.bottom = Tile;
|
|
543
|
+
break;
|
|
544
|
+
case DirectionEnum.Left:
|
|
545
|
+
this.left = TileStateEnum.Nothing;
|
|
546
|
+
break;
|
|
547
|
+
case DirectionEnum.Up:
|
|
548
|
+
this.top = value;
|
|
549
|
+
break;
|
|
550
|
+
case DirectionEnum.Right:
|
|
551
|
+
this.right = TileStateEnum.Nothing;
|
|
552
|
+
break;
|
|
553
|
+
}
|
|
554
|
+
}*/
|
|
555
|
+
clear(){
|
|
556
|
+
this.left = TileStateEnum.Nothing;
|
|
557
|
+
this.bottom = TileStateEnum.Nothing;
|
|
558
|
+
this.right = TileStateEnum.Nothing;
|
|
559
|
+
this.top = TileStateEnum.Nothing;
|
|
560
|
+
this.is_key = false;
|
|
561
|
+
this.is_selected = false;
|
|
562
|
+
}
|
|
563
|
+
getDirections(): GridDirection[]{
|
|
564
|
+
const dirs: GridDirection[] = [];
|
|
565
|
+
if(this.left !== TileStateEnum.Nothing){
|
|
566
|
+
dirs.push(DirectionEnum.Left);
|
|
567
|
+
}
|
|
568
|
+
if(this.top !== TileStateEnum.Nothing){
|
|
569
|
+
dirs.push(DirectionEnum.Up);
|
|
570
|
+
}
|
|
571
|
+
if(this.right !== TileStateEnum.Nothing){
|
|
572
|
+
dirs.push(DirectionEnum.Right);
|
|
573
|
+
}
|
|
574
|
+
if(this.bottom !== TileStateEnum.Nothing){
|
|
575
|
+
dirs.push(DirectionEnum.Down);
|
|
576
|
+
}
|
|
577
|
+
return dirs;
|
|
578
|
+
}
|
|
579
|
+
getDirectionsOtherThan(not_dir: GridDirection): GridDirection[]{
|
|
580
|
+
const dirs: GridDirection[] = [];
|
|
581
|
+
if(not_dir !== DirectionEnum.Left && this.left !== TileStateEnum.Nothing){
|
|
582
|
+
dirs.push(DirectionEnum.Left);
|
|
583
|
+
}
|
|
584
|
+
if(not_dir !== DirectionEnum.Up && this.top !== TileStateEnum.Nothing){
|
|
585
|
+
dirs.push(DirectionEnum.Up);
|
|
586
|
+
}
|
|
587
|
+
if(not_dir !== DirectionEnum.Right && this.right !== TileStateEnum.Nothing){
|
|
588
|
+
dirs.push(DirectionEnum.Right);
|
|
589
|
+
}
|
|
590
|
+
if(not_dir !== DirectionEnum.Down && this.bottom !== TileStateEnum.Nothing){
|
|
591
|
+
dirs.push(DirectionEnum.Down);
|
|
592
|
+
}
|
|
593
|
+
return dirs;
|
|
594
|
+
}
|
|
595
|
+
getSideState(side: GridDirection): TileState{
|
|
596
|
+
switch(side){
|
|
597
|
+
case DirectionEnum.Left:
|
|
598
|
+
return this.left;
|
|
599
|
+
case DirectionEnum.Down:
|
|
600
|
+
return this.bottom;
|
|
601
|
+
case DirectionEnum.Right:
|
|
602
|
+
return this.right;
|
|
603
|
+
case DirectionEnum.Up:
|
|
604
|
+
return this.top;
|
|
605
|
+
}
|
|
606
|
+
return TileStateEnum.Nothing;
|
|
607
|
+
}
|
|
608
|
+
setNodeId(id: Int32){
|
|
609
|
+
this.is_key = true;
|
|
610
|
+
this.node_id = id;
|
|
611
|
+
}
|
|
612
|
+
clearKey(){
|
|
613
|
+
this.is_key = false;
|
|
614
|
+
this.node_id = undefined;
|
|
615
|
+
}
|
|
616
|
+
clearNode(){
|
|
617
|
+
this.is_key = false;
|
|
618
|
+
this.node_id = undefined;
|
|
619
|
+
this.is_selected = false;
|
|
620
|
+
this.left = TileStateEnum.Nothing;
|
|
621
|
+
this.top = TileStateEnum.Nothing;
|
|
622
|
+
this.bottom = TileStateEnum.Nothing;
|
|
623
|
+
this.right = TileStateEnum.Nothing;
|
|
624
|
+
}
|
|
625
|
+
setTileActiveDirection(active: ActiveDirections, value: TileState){
|
|
626
|
+
if(active.left){
|
|
627
|
+
this.left = value;
|
|
628
|
+
}
|
|
629
|
+
if(active.down){
|
|
630
|
+
this.bottom = value;
|
|
631
|
+
}
|
|
632
|
+
if(active.right){
|
|
633
|
+
this.right = value;
|
|
634
|
+
}
|
|
635
|
+
if(active.up){
|
|
636
|
+
this.top = value;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
setTileState(direction: GridDirection, value: TileState){
|
|
640
|
+
switch(direction){
|
|
641
|
+
case DirectionEnum.Down:
|
|
642
|
+
this.bottom = value;
|
|
643
|
+
break;
|
|
644
|
+
case DirectionEnum.Left:
|
|
645
|
+
this.left = value;
|
|
646
|
+
break;
|
|
647
|
+
case DirectionEnum.Up:
|
|
648
|
+
this.top = value;
|
|
649
|
+
break;
|
|
650
|
+
case DirectionEnum.Right:
|
|
651
|
+
this.right = value;
|
|
652
|
+
break;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
static tileStateIsPath(state: TileState): boolean{
|
|
656
|
+
return state == TileStateEnum.Highlight || state == TileStateEnum.Path;
|
|
657
|
+
}
|
|
658
|
+
directionHasPath(dir: GridDirection): boolean{
|
|
659
|
+
switch(dir){
|
|
660
|
+
case DirectionEnum.Left:
|
|
661
|
+
return WallTile.tileStateIsPath(this.left);
|
|
662
|
+
case DirectionEnum.Up:
|
|
663
|
+
return WallTile.tileStateIsPath(this.top);
|
|
664
|
+
case DirectionEnum.Right:
|
|
665
|
+
return WallTile.tileStateIsPath(this.right);
|
|
666
|
+
case DirectionEnum.Down:
|
|
667
|
+
return WallTile.tileStateIsPath(this.bottom);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
randomise(){
|
|
671
|
+
this.left = randomTileState();
|
|
672
|
+
this.right = randomTileState();
|
|
673
|
+
this.bottom = randomTileState();
|
|
674
|
+
this.top = randomTileState();
|
|
675
|
+
}
|
|
676
|
+
isKeyNode(): boolean{
|
|
677
|
+
return this.node_id != undefined;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
export class WallGrid{
|
|
682
|
+
width: Int32; //num squares across
|
|
683
|
+
height: Int32; // num squares down
|
|
684
|
+
grid: WallTile[][];
|
|
685
|
+
constructor(w: Int32, h: Int32){
|
|
686
|
+
this.width = w;
|
|
687
|
+
this.height = h;
|
|
688
|
+
this.grid = Array.from({length: h}, () => Array.from({length: w}, () => new WallTile()));
|
|
689
|
+
}
|
|
690
|
+
clear(){
|
|
691
|
+
for(let x = 0; x < this.width; x++){
|
|
692
|
+
for(let y = 0; y < this.height; y++){
|
|
693
|
+
this.grid[y][x].clear();
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
setSelected(x: Int32, y: Int32, select: boolean){
|
|
698
|
+
this.grid[y][x].is_selected = select;
|
|
699
|
+
}
|
|
700
|
+
setNodeId(x: Int32, y: Int32, id: Int32){
|
|
701
|
+
this.grid[y][x].setNodeId(id);
|
|
702
|
+
}
|
|
703
|
+
getNodeId(x: Int32, y: Int32): Int32 | undefined{
|
|
704
|
+
return this.grid[y][x].node_id;
|
|
705
|
+
}
|
|
706
|
+
clearNode(x: Int32, y: Int32){
|
|
707
|
+
this.grid[y][x].clearNode();
|
|
708
|
+
}
|
|
709
|
+
setCellKeyNode(x: Int32, y: Int32, val: boolean){
|
|
710
|
+
this.grid[y][x].is_key = val;
|
|
711
|
+
}
|
|
712
|
+
getTile(x: Int32, y: Int32): WallTile | undefined{
|
|
713
|
+
if(!this.isInside(x, y)) return undefined;
|
|
714
|
+
return this.grid[y][x];
|
|
715
|
+
}
|
|
716
|
+
getTileFromPosition(pos: GridPosition): WallTile | undefined{
|
|
717
|
+
return this.getTile(pos.x, pos.y);
|
|
718
|
+
}
|
|
719
|
+
randomise(){
|
|
720
|
+
for(let y = 0; y < this.height; y++){
|
|
721
|
+
for(let x = 0; x < this.width; x++){
|
|
722
|
+
this.grid[y][x].randomise();
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
isInside(x: Int32, y: Int32): boolean{
|
|
727
|
+
return x >= 0 && x < this.width && y >= 0 && y < this.height;
|
|
728
|
+
}
|
|
729
|
+
setCellState(x: Int32, y: Int32, direction: GridDirection, state: TileState){
|
|
730
|
+
this.grid[y][x].setTileState(direction, state);
|
|
731
|
+
}
|
|
732
|
+
setCellStateFromActive(x: Int32, y: Int32, active: ActiveDirections, state: TileState){
|
|
733
|
+
this.grid[y][x].setTileActiveDirection(active, state);
|
|
734
|
+
/*if(state == TileStateEnum.Highlight){
|
|
735
|
+
this.grid[y][x].is_selected = true;
|
|
736
|
+
}else{
|
|
737
|
+
this.grid[y][x].is_selected = false;
|
|
738
|
+
}*/
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
addTrack(track: Track){
|
|
742
|
+
console.log(track);
|
|
743
|
+
let last_direction: GridDirection | undefined = undefined;
|
|
744
|
+
const current = track.starting_location.copy();
|
|
745
|
+
for(const pt of track.part.getMoves()){
|
|
746
|
+
for(let i = 0; i < pt.distance; i++){
|
|
747
|
+
if(last_direction != undefined){
|
|
748
|
+
this.grid[current.y][current.x].setTileState(DirectionUtil.opposite(last_direction), TileStateEnum.Path);
|
|
749
|
+
}
|
|
750
|
+
this.grid[current.y][current.x].setTileState(pt.direction, TileStateEnum.Path);
|
|
751
|
+
DirectionUtil.movePosition(pt.direction, current);
|
|
752
|
+
last_direction = pt.direction;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
if(last_direction != undefined){
|
|
756
|
+
this.grid[current.y][current.x].setTileState(DirectionUtil.opposite(last_direction), TileStateEnum.Path);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
shortestPath(start: GridPosition, end: GridPosition): GridPosition[] | undefined{
|
|
760
|
+
const last_position: (GridPosition | undefined)[][] = Array.from({length: this.height}, () => Array.from({length: this.width}, () => undefined));
|
|
761
|
+
last_position[start.y][start.x] = start;
|
|
762
|
+
if(start.equals(end)){
|
|
763
|
+
return [start];
|
|
764
|
+
}
|
|
765
|
+
let queue: GridPosition[] = [];
|
|
766
|
+
queue.push(start);
|
|
767
|
+
let times = 0; // can remove
|
|
768
|
+
while(queue.length > 0){
|
|
769
|
+
console.log(queue);
|
|
770
|
+
times++;
|
|
771
|
+
const next_q = [];
|
|
772
|
+
for(let i = 0; i < queue.length; i++){
|
|
773
|
+
const curr = queue[i];
|
|
774
|
+
if(curr.equals(end)){
|
|
775
|
+
//found path
|
|
776
|
+
const path: GridPosition[] = [end];
|
|
777
|
+
let pl = path.at(-1)!;
|
|
778
|
+
let last = last_position[pl.y][pl.x]!;
|
|
779
|
+
while(!last.equals(start)){
|
|
780
|
+
path.push(last);
|
|
781
|
+
pl = path.at(-1)!;
|
|
782
|
+
last = last_position[pl.y][pl.x]!;
|
|
783
|
+
}
|
|
784
|
+
path.push(start);
|
|
785
|
+
ArrayUtils.reverse(path);
|
|
786
|
+
return path;
|
|
787
|
+
//backtrack
|
|
788
|
+
}
|
|
789
|
+
const wall_tile = this.grid[curr.y][curr.x];
|
|
790
|
+
if(wall_tile.left != TileStateEnum.Nothing && last_position[curr.y][curr.x-1] == undefined){
|
|
791
|
+
const new_pos = new GridPosition(curr.x-1, curr.y);
|
|
792
|
+
next_q.push(new_pos);
|
|
793
|
+
last_position[curr.y][curr.x-1] = curr;
|
|
794
|
+
}if(wall_tile.top && last_position[curr.y-1][curr.x] == undefined){
|
|
795
|
+
const new_pos = new GridPosition(curr.x, curr.y-1);
|
|
796
|
+
next_q.push(new_pos);
|
|
797
|
+
last_position[curr.y-1][curr.x] = curr;
|
|
798
|
+
}if(wall_tile.right != TileStateEnum.Nothing && last_position[curr.y][curr.x+1] == undefined){
|
|
799
|
+
const new_pos = new GridPosition(curr.x+1, curr.y);
|
|
800
|
+
next_q.push(new_pos);
|
|
801
|
+
last_position[curr.y][curr.x+1] = curr;
|
|
802
|
+
//console.log("right");
|
|
803
|
+
}if(wall_tile.bottom && last_position[curr.y+1][curr.x] == undefined){
|
|
804
|
+
const new_pos = new GridPosition(curr.x, curr.y+1);
|
|
805
|
+
next_q.push(new_pos);
|
|
806
|
+
last_position[curr.y+1][curr.x] = curr;
|
|
807
|
+
//console.log("bot");
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
queue = next_q;
|
|
811
|
+
}
|
|
812
|
+
return undefined;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
type PositionsAtDistance = {
|
|
817
|
+
positions: GridPosition[];
|
|
818
|
+
distance_squared: Float;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
type GridEucildianCompare = {
|
|
822
|
+
position: GridPosition;
|
|
823
|
+
distance_squared: Float;
|
|
824
|
+
};
|
|
825
|
+
|
|
826
|
+
export class GridAlgorithms{
|
|
827
|
+
static positionsAtDistance:PositionsAtDistance[] = [];
|
|
828
|
+
private static distanceQueue = new PQ.PriorityQueue((a:GridEucildianCompare,b:GridEucildianCompare) => a.distance_squared-b.distance_squared);
|
|
829
|
+
private static distancesSeen: number[] = [];
|
|
830
|
+
|
|
831
|
+
static pathToTrack(path: GridPosition[]): Track{
|
|
832
|
+
const part = new TrackPart();
|
|
833
|
+
let direction = DirectionUtil.directionsBetween2Points(path[0], path[1])[0];
|
|
834
|
+
let dist = 1;
|
|
835
|
+
for(let i = 2; i < path.length; i++){
|
|
836
|
+
const c_dir = DirectionUtil.directionsBetween2Points(path[i-1], path[i])[0];
|
|
837
|
+
if(c_dir === direction){
|
|
838
|
+
dist += 1;
|
|
839
|
+
}else{
|
|
840
|
+
part.addMove(dist, direction);
|
|
841
|
+
direction = c_dir;
|
|
842
|
+
dist = 1;
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
const track = new Track(part, path[0]);
|
|
846
|
+
return track;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
static greatestPositionAtDistance(): Int32 | undefined{
|
|
850
|
+
if(GridAlgorithms.positionsAtDistance.length == 0) return undefined;
|
|
851
|
+
return GridAlgorithms.positionsAtDistance.at(-1)!.distance_squared;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
static generatePositionsAtDistance(limit: Float){
|
|
855
|
+
const limit_sq = limit*limit;
|
|
856
|
+
//const pq = new PQ.PriorityQueue((a:GridEucildianCompare,b:GridEucildianCompare) => a.distance_squared-b.distance_squared);
|
|
857
|
+
const pq = GridAlgorithms.distanceQueue;
|
|
858
|
+
const p0 = new GridPosition(0, 0);
|
|
859
|
+
if(pq.isEmpty()){
|
|
860
|
+
pq.enqueue({position: p0, distance_squared: GridPosition.euclidianDistanceSquared(p0, p0)});
|
|
861
|
+
GridAlgorithms.distancesSeen.push(0);
|
|
862
|
+
}
|
|
863
|
+
while(pq.front()!.distance_squared <= limit_sq){
|
|
864
|
+
const top = pq.dequeue()!;
|
|
865
|
+
const pos = top.position.copy();
|
|
866
|
+
|
|
867
|
+
const positions: GridPosition[] = [];
|
|
868
|
+
if(pos.x == 0 && pos.y == 0){
|
|
869
|
+
positions.push(new GridPosition(pos.x, pos.y));
|
|
870
|
+
}else if(pos.y == 0){
|
|
871
|
+
positions.push(new GridPosition(pos.x, 0));
|
|
872
|
+
positions.push(new GridPosition(-pos.x, 0));
|
|
873
|
+
positions.push(new GridPosition(0, pos.x));
|
|
874
|
+
positions.push(new GridPosition(0, -pos.x));
|
|
875
|
+
}else{
|
|
876
|
+
positions.push(new GridPosition(pos.x, pos.y));
|
|
877
|
+
positions.push(new GridPosition(-pos.x, pos.y));
|
|
878
|
+
positions.push(new GridPosition(pos.x, -pos.y));
|
|
879
|
+
positions.push(new GridPosition(-pos.x, -pos.y));
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
const posx = new GridPosition(pos.x+1, pos.y);
|
|
883
|
+
const dsx = GridPosition.euclidianDistanceSquared(p0, posx);
|
|
884
|
+
|
|
885
|
+
console.log(`${this.distancesSeen} - ${pos.x}, ${pos.y}`);
|
|
886
|
+
|
|
887
|
+
if(posx.x >= GridAlgorithms.distancesSeen.length || posx.y > GridAlgorithms.distancesSeen[posx.x]){
|
|
888
|
+
pq.enqueue({position: posx, distance_squared: dsx});
|
|
889
|
+
if(GridAlgorithms.distancesSeen.length == posx.x){
|
|
890
|
+
GridAlgorithms.distancesSeen.push(0);
|
|
891
|
+
}else{
|
|
892
|
+
GridAlgorithms.distancesSeen[posx.x] = Math.max(GridAlgorithms.distancesSeen[posx.x], posx.y);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
if(pos.x != pos.y){
|
|
897
|
+
if(pos.y != 0){
|
|
898
|
+
positions.push(new GridPosition(pos.y, pos.x));
|
|
899
|
+
positions.push(new GridPosition(-pos.y, pos.x));
|
|
900
|
+
positions.push(new GridPosition(pos.y, -pos.x));
|
|
901
|
+
positions.push(new GridPosition(-pos.y, -pos.x));
|
|
902
|
+
}
|
|
903
|
+
//do y as well
|
|
904
|
+
const posy = new GridPosition(pos.x, pos.y+1);
|
|
905
|
+
const dsy = GridPosition.euclidianDistanceSquared(p0, posy);
|
|
906
|
+
if(posy.x >= GridAlgorithms.distancesSeen.length || posy.y > GridAlgorithms.distancesSeen[pos.x]){
|
|
907
|
+
pq.enqueue({position: posy, distance_squared: dsy});
|
|
908
|
+
if(GridAlgorithms.distancesSeen.length == posy.x){
|
|
909
|
+
GridAlgorithms.distancesSeen.push(0);
|
|
910
|
+
}else{
|
|
911
|
+
GridAlgorithms.distancesSeen[posy.x] = Math.max(GridAlgorithms.distancesSeen[posy.x], posy.y);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
if(GridAlgorithms.positionsAtDistance.length > 0 && GridAlgorithms.positionsAtDistance.at(-1)!.distance_squared === top.distance_squared){
|
|
916
|
+
const last = GridAlgorithms.positionsAtDistance.at(-1)!;
|
|
917
|
+
//console.log(`same distance sq ${pos.x}, ${pos.y} == ${last.positions[0].x}, ${last.positions[0].y} ${top.distance_squared}`);
|
|
918
|
+
GridAlgorithms.positionsAtDistance[GridAlgorithms.positionsAtDistance.length-1].positions = last.positions.concat(positions);
|
|
919
|
+
}else{
|
|
920
|
+
GridAlgorithms.positionsAtDistance.push({positions, distance_squared: top.distance_squared});
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
static positionPathToDirectionPath(path: GridPosition[]):GridPositionWithDirections[]{
|
|
925
|
+
const direction_path:GridPositionWithDirections[] = [];
|
|
926
|
+
for(let i = 0; i < path.length; i++){
|
|
927
|
+
const active = {
|
|
928
|
+
left: false,
|
|
929
|
+
down: false,
|
|
930
|
+
right: false,
|
|
931
|
+
up: false
|
|
932
|
+
}
|
|
933
|
+
if(i != 0){
|
|
934
|
+
const back_directions = DirectionUtil.directionsBetween2Points(path[i], path[i-1]);
|
|
935
|
+
for(const dir of back_directions){
|
|
936
|
+
DirectionUtil.setActiveDirection(active, true, dir);
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
if(i != path.length-1){
|
|
940
|
+
const forward_directions = DirectionUtil.directionsBetween2Points(path[i], path[i+1]);
|
|
941
|
+
for(const dir of forward_directions){
|
|
942
|
+
DirectionUtil.setActiveDirection(active, true, dir);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
direction_path.push({position: path[i], directions: active});
|
|
946
|
+
}
|
|
947
|
+
return direction_path;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
static positionsWithinRange(limit_squared: Float): GridPosition[]{
|
|
951
|
+
const greatest_distance = GridAlgorithms.greatestPositionAtDistance();
|
|
952
|
+
if(greatest_distance == undefined || greatest_distance < limit_squared){
|
|
953
|
+
GridAlgorithms.generatePositionsAtDistance(limit_squared);
|
|
954
|
+
let positions: GridPosition[] = [];
|
|
955
|
+
for(const pd of GridAlgorithms.positionsAtDistance){
|
|
956
|
+
positions = positions.concat(pd.positions);
|
|
957
|
+
}
|
|
958
|
+
return positions;
|
|
959
|
+
}
|
|
960
|
+
//search for limit index
|
|
961
|
+
const find_index = ArrayUtils.binarySearchLowerBound(GridAlgorithms.positionsAtDistance, (e:PositionsAtDistance) => limit_squared-e.distance_squared);
|
|
962
|
+
//console.log(find_index);
|
|
963
|
+
let positions: GridPosition[] = [];
|
|
964
|
+
for(let i = 0; i < find_index; i++){
|
|
965
|
+
positions = positions.concat(GridAlgorithms.positionsAtDistance[i].positions);
|
|
966
|
+
}
|
|
967
|
+
return positions;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
static positionsWithin2Ranges(lower_range_squared: Float, upper_range_squared: Float): GridPosition[]{
|
|
971
|
+
if(lower_range_squared > upper_range_squared){
|
|
972
|
+
const tmp = lower_range_squared;
|
|
973
|
+
lower_range_squared = upper_range_squared;
|
|
974
|
+
upper_range_squared = tmp;
|
|
975
|
+
}
|
|
976
|
+
const greatest_distance = GridAlgorithms.greatestPositionAtDistance();
|
|
977
|
+
if(greatest_distance == undefined || greatest_distance < upper_range_squared){
|
|
978
|
+
GridAlgorithms.generatePositionsAtDistance(upper_range_squared);
|
|
979
|
+
}
|
|
980
|
+
const hi_index = ArrayUtils.binarySearchLowerBound(GridAlgorithms.positionsAtDistance,
|
|
981
|
+
(e:PositionsAtDistance) => upper_range_squared-e.distance_squared
|
|
982
|
+
);
|
|
983
|
+
const lo_index = ArrayUtils.binarySearchUpperBound(GridAlgorithms.positionsAtDistance,
|
|
984
|
+
(e:PositionsAtDistance) => lower_range_squared-e.distance_squared
|
|
985
|
+
);
|
|
986
|
+
let positions: GridPosition[] = [];
|
|
987
|
+
for(let i = lo_index; i <= hi_index; i++){
|
|
988
|
+
//console.log(GridAlgorithms.positionsAtDistance[i]);
|
|
989
|
+
positions = positions.concat(GridAlgorithms.positionsAtDistance[i].positions);
|
|
990
|
+
}
|
|
991
|
+
return positions;
|
|
992
|
+
}
|
|
993
|
+
}
|