squishjs 0.6.41 → 0.7.1
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/.github/workflows/node.js.yml +1 -1
- package/LICENSE.md +21 -0
- package/README.md +116 -42
- package/index.js +11 -1
- package/oldsvgexport.js +89 -0
- package/package.json +1 -1
- package/render-tester.js +120 -0
- package/src/BaseNode.js +101 -0
- package/src/Game.js +15 -3
- package/src/GameNode.js +82 -79
- package/src/InternalGameNode.js +4 -3
- package/src/Squisher.js +224 -0
- package/src/ViewableGame.js +60 -0
- package/src/node-types.js +15 -0
- package/src/squish.js +90 -349
- package/src/squishHelpers/asset.js +63 -0
- package/src/squishHelpers/border.js +16 -0
- package/src/squishHelpers/color.js +16 -0
- package/src/squishHelpers/coordinates2d.js +98 -0
- package/src/squishHelpers/effect.js +55 -0
- package/src/squishHelpers/fill.js +16 -0
- package/src/squishHelpers/handleClick.js +16 -0
- package/src/squishHelpers/id.js +16 -0
- package/src/squishHelpers/input.js +22 -0
- package/src/squishHelpers/playerIds.js +12 -0
- package/src/squishHelpers/pos.js +23 -0
- package/src/squishHelpers/size.js +23 -0
- package/src/squishHelpers/subType.js +16 -0
- package/src/squishHelpers/text.js +154 -0
- package/src/subtype-mappings.js +10 -0
- package/src/subtypes.js +7 -0
- package/src/terrain/defs.ts +16 -0
- package/src/terrain/index.ts +156 -0
- package/src/terrain/terrainFunctions.ts +142 -0
- package/src/util/geometry.js +45 -0
- package/src/util/index.ts +6 -0
- package/src/util/listenable.ts +20 -0
- package/src/util/shapes.ts +18 -0
- package/src/util/views.js +108 -0
- package/test/Layers.test.js +63 -0
- package/test/Scale.test.js +235 -0
- package/test/Squisher.test.js +49 -0
- package/test/StateUpdates.js +10 -0
- package/test/Terrain.test.js +0 -1
- package/test/main.test.js +55 -35
- package/test/utils.js +91 -0
- package/testapp.html +26 -0
- package/testapp.js +988 -0
- package/tsconfig.json +22 -0
- package/license.txt +0 -674
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const EFFECTS_SUBTYPE = 49;
|
|
2
|
+
|
|
3
|
+
const squishEffect = {
|
|
4
|
+
type: EFFECTS_SUBTYPE,
|
|
5
|
+
squish: (a) => {
|
|
6
|
+
if (a['shadow']) {
|
|
7
|
+
const assetKey = 'shadow';
|
|
8
|
+
let squishedLength = assetKey.length + 4; // + 4 for color
|
|
9
|
+
if (a['shadow'].blur) {
|
|
10
|
+
squishedLength += 2;
|
|
11
|
+
}
|
|
12
|
+
const squishedEffects = new Array(squishedLength);
|
|
13
|
+
for (let i = 0; i < assetKey.length; i++) {
|
|
14
|
+
squishedEffects[i] = assetKey.codePointAt(i);
|
|
15
|
+
}
|
|
16
|
+
squishedEffects[assetKey.length] = a.shadow.color[0];
|
|
17
|
+
squishedEffects[assetKey.length + 1] = a.shadow.color[1];
|
|
18
|
+
squishedEffects[assetKey.length + 2] = a.shadow.color[2];
|
|
19
|
+
squishedEffects[assetKey.length + 3] = a.shadow.color[3];
|
|
20
|
+
|
|
21
|
+
if (a.shadow.blur) {
|
|
22
|
+
squishedEffects[assetKey.length + 4] = Math.floor(a.shadow.blur / 10)
|
|
23
|
+
squishedEffects[assetKey.length + 5] = a.shadow.blur % 10
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return squishedEffects;
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
unsquish: (squished) => {
|
|
30
|
+
// 'shadow' is all (for now)
|
|
31
|
+
const assetKey = String.fromCodePoint.apply(null, squished.slice(0, 6));
|
|
32
|
+
const color = squished.slice(6, 10);
|
|
33
|
+
let blur;
|
|
34
|
+
if (squished.length > 10) {
|
|
35
|
+
blur = squished[10] * 10 + squished[11];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const unsquished = {
|
|
39
|
+
[assetKey]: {
|
|
40
|
+
color
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
if (blur) {
|
|
45
|
+
unsquished[assetKey].blur = blur;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return unsquished;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = {
|
|
53
|
+
EFFECTS_SUBTYPE,
|
|
54
|
+
squishEffect
|
|
55
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const FILL_SUBTYPE = 53;
|
|
2
|
+
|
|
3
|
+
const squishFill = {
|
|
4
|
+
type: FILL_SUBTYPE,
|
|
5
|
+
squish: (c) => {
|
|
6
|
+
return [c[0], c[1], c[2], c[3]];
|
|
7
|
+
},
|
|
8
|
+
unsquish: (squished) => {
|
|
9
|
+
return [squished[0], squished[1], squished[2], squished[3]];
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
module.exports = {
|
|
14
|
+
FILL_SUBTYPE,
|
|
15
|
+
squishFill
|
|
16
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const ONCLICK_SUBTYPE = 50;
|
|
2
|
+
|
|
3
|
+
const squishHandleClick = {
|
|
4
|
+
type: ONCLICK_SUBTYPE,
|
|
5
|
+
squish: (a) => {
|
|
6
|
+
return a ? [1] : [0];
|
|
7
|
+
},
|
|
8
|
+
unsquish: (a) => {
|
|
9
|
+
return a[0] === 1;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
module.exports = {
|
|
14
|
+
ONCLICK_SUBTYPE,
|
|
15
|
+
squishHandleClick
|
|
16
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const INPUT_SUBTYPE = 51;
|
|
2
|
+
|
|
3
|
+
const squishInput = {
|
|
4
|
+
type: INPUT_SUBTYPE,
|
|
5
|
+
squish: (a) => {
|
|
6
|
+
const squished = new Array(a.type.length);
|
|
7
|
+
for (let i = 0; i < a.type.length; i++) {
|
|
8
|
+
squished[i] = a.type.codePointAt(i);
|
|
9
|
+
}
|
|
10
|
+
return squished;
|
|
11
|
+
},
|
|
12
|
+
unsquish: (squished) => {
|
|
13
|
+
return {
|
|
14
|
+
type: String.fromCodePoint.apply(null, squished)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = {
|
|
20
|
+
INPUT_SUBTYPE,
|
|
21
|
+
squishInput
|
|
22
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const POS_SUBTYPE = 45;
|
|
2
|
+
|
|
3
|
+
const squishHelper = (position) => {
|
|
4
|
+
return Math.round(100 * (position - Math.floor(position)))
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const squishPos = {
|
|
8
|
+
type: POS_SUBTYPE,
|
|
9
|
+
squish: (p) => {
|
|
10
|
+
return [Math.floor(p.x), squishHelper(p.x), Math.floor(p.y), squishHelper(p.y)]
|
|
11
|
+
},
|
|
12
|
+
unsquish: (squished) => {
|
|
13
|
+
return {
|
|
14
|
+
x: squished[0] + squished[1] / 100,
|
|
15
|
+
y: squished[2] + squished[3] / 100
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = {
|
|
21
|
+
POS_SUBTYPE,
|
|
22
|
+
squishPos
|
|
23
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const SIZE_SUBTYPE = 46;
|
|
2
|
+
|
|
3
|
+
const squishHelper = (size) => {
|
|
4
|
+
Math.round(100 * (size- Math.floor(size)))
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const squishSize = {
|
|
8
|
+
type: SIZE_SUBTYPE,
|
|
9
|
+
squish: (s) => {
|
|
10
|
+
return [Math.floor(s.x), squishHelper(s.x), Math.floor(s.y), squishHelper(s.y)]
|
|
11
|
+
},
|
|
12
|
+
unsquish: (squished) => {
|
|
13
|
+
return {
|
|
14
|
+
x: squished[0] + squished[1] / 100,
|
|
15
|
+
y: squished[2] + squished[3] / 100
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = {
|
|
21
|
+
SIZE_SUBTYPE,
|
|
22
|
+
squishSize
|
|
23
|
+
};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
const { hypLength } = require('../util')
|
|
2
|
+
const Colors = require('../Colors');
|
|
3
|
+
const { squishColor } = require('./color')
|
|
4
|
+
|
|
5
|
+
const TEXT_SUBTYPE = 47;
|
|
6
|
+
|
|
7
|
+
const squishText = {
|
|
8
|
+
type: TEXT_SUBTYPE,
|
|
9
|
+
squish: (t, scale) => {
|
|
10
|
+
const textX = scale ? (t.x * scale.x) + Math.round(100 * (1 - scale.x)) / 2 : t.x;
|
|
11
|
+
const textY = scale ? (t.y * scale.y) + Math.round(100 * (1 - scale.y)) / 2 : t.y;
|
|
12
|
+
|
|
13
|
+
const align = t.align || 'left';
|
|
14
|
+
const squishedText = new Array(t.text.length + 10 + align.length);
|
|
15
|
+
|
|
16
|
+
squishedText[0] = Math.floor(textX);
|
|
17
|
+
squishedText[1] = Math.round(100 * (textX - Math.floor(textX)));
|
|
18
|
+
|
|
19
|
+
squishedText[2] = Math.floor(textY);
|
|
20
|
+
squishedText[3] = Math.round(100 * (textY - Math.floor(textY)));
|
|
21
|
+
|
|
22
|
+
const textSize = t.size || 1;
|
|
23
|
+
const scaledTextSize = scale ? textSize * hypLength(scale.x, scale.y) : textSize;
|
|
24
|
+
|
|
25
|
+
squishedText[4] = Math.floor(scaledTextSize);
|
|
26
|
+
squishedText[5] = Math.round(100 * (scaledTextSize - Math.floor(scaledTextSize)));
|
|
27
|
+
|
|
28
|
+
const textColor = t.color || Colors.BLACK;
|
|
29
|
+
const squishedTextColor = squishColor.squish(textColor);
|
|
30
|
+
|
|
31
|
+
for (let i = 0; i < squishedTextColor.length; i++) {
|
|
32
|
+
squishedText[6 + i] = squishedTextColor[i];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
squishedText[6 + squishedTextColor.length] = 3 * [...align].length;
|
|
36
|
+
|
|
37
|
+
let j = 0;
|
|
38
|
+
for (let i = 0; i < [...align].length; i++) {
|
|
39
|
+
const codePointToInsert = [...align][i].codePointAt(0);
|
|
40
|
+
const codePointString = codePointToInsert.toString();
|
|
41
|
+
let ting;
|
|
42
|
+
if (codePointString.length == 1) {
|
|
43
|
+
ting = [`00`, `00`, `0${codePointString}`];
|
|
44
|
+
} else if (codePointString.length == 2) {
|
|
45
|
+
ting = [`00`, `00`, `${codePointString}`];
|
|
46
|
+
} else if (codePointString.length == 3) {
|
|
47
|
+
ting = [`00`, `0${codePointString.charAt(0)}`, `${codePointString.charAt(1)}${codePointString.charAt(2)}`];
|
|
48
|
+
} else if (codePointString.length == 4) {
|
|
49
|
+
ting = [`00`, `${codePointString.charAt(0)}${codePointString.charAt(1)}`, `${codePointString.charAt(2)}${codePointString.charAt(3)}`];
|
|
50
|
+
} else if (codePointString.length == 5) {
|
|
51
|
+
ting = [`0${codePointString.charAt(0)}`, `${codePointString.charAt(1)}${codePointString.charAt(2)}`, `${codePointString.charAt(3)}${codePointString.charAt(4)}`];
|
|
52
|
+
} else {
|
|
53
|
+
ting = [`${codePointString.charAt(0)}${codePointString.charAt(1)}`, `${codePointString.charAt(2)}${codePointString.charAt(3)}`, `${codePointString.charAt(4)}${codePointString.charAt(5)}`];
|
|
54
|
+
}
|
|
55
|
+
squishedText[6 + squishedTextColor.length + 1 + j] = Number(ting[0]);
|
|
56
|
+
squishedText[6 + squishedTextColor.length + 1 + j + 1] = Number(ting[1]);
|
|
57
|
+
squishedText[6 + squishedTextColor.length + 1 + j + 2] = Number(ting[2]);
|
|
58
|
+
j += 3;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let k = 0;
|
|
62
|
+
for (let i = 0; i < [...t.text].length; i++) {
|
|
63
|
+
const codePointToInsert = [...t.text][i].codePointAt(0);
|
|
64
|
+
const codePointString = codePointToInsert.toString();
|
|
65
|
+
let ting;
|
|
66
|
+
if (codePointString.length == 1) {
|
|
67
|
+
ting = [`00`, `00`, `0${codePointString}`];
|
|
68
|
+
} else if (codePointString.length == 2) {
|
|
69
|
+
ting = [`00`, `00`, `${codePointString}`];
|
|
70
|
+
} else if (codePointString.length == 3) {
|
|
71
|
+
ting = [`00`, `0${codePointString.charAt(0)}`, `${codePointString.charAt(1)}${codePointString.charAt(2)}`];
|
|
72
|
+
} else if (codePointString.length == 4) {
|
|
73
|
+
ting = [`00`, `${codePointString.charAt(0)}${codePointString.charAt(1)}`, `${codePointString.charAt(2)}${codePointString.charAt(3)}`];
|
|
74
|
+
} else if (codePointString.length == 5) {
|
|
75
|
+
ting = [`0${codePointString.charAt(0)}`, `${codePointString.charAt(1)}${codePointString.charAt(2)}`, `${codePointString.charAt(3)}${codePointString.charAt(4)}`];
|
|
76
|
+
} else {
|
|
77
|
+
ting = [`${codePointString.charAt(0)}${codePointString.charAt(1)}`, `${codePointString.charAt(2)}${codePointString.charAt(3)}`, `${codePointString.charAt(4)}${codePointString.charAt(5)}`];
|
|
78
|
+
}
|
|
79
|
+
squishedText[6 + squishedTextColor.length + 1 + j + k] = Number(ting[0]);
|
|
80
|
+
squishedText[6 + squishedTextColor.length + 1 + j + k + 1] = Number(ting[1]);
|
|
81
|
+
squishedText[6 + squishedTextColor.length + 1 + j + k + 2] = Number(ting[2]);
|
|
82
|
+
|
|
83
|
+
k += 3;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return squishedText;
|
|
87
|
+
},
|
|
88
|
+
unsquish: (squished) => {
|
|
89
|
+
const textPosX = squished[0] + squished[1] / 100;
|
|
90
|
+
const textPosY = squished[2] + squished[3] / 100;
|
|
91
|
+
const textSize = squished[4] + squished[5] / 100;
|
|
92
|
+
const textColor = squished.slice(6, 10);
|
|
93
|
+
const textAlignLength = squished[10];
|
|
94
|
+
const textAlignVal = squished.slice(11, 11 + textAlignLength);
|
|
95
|
+
const textVal = squished.slice(11 + textAlignLength);
|
|
96
|
+
|
|
97
|
+
let alignCodePoints = [];
|
|
98
|
+
for (let i = 0; i < textAlignVal.length; i+=3) {
|
|
99
|
+
let firstChunk = textAlignVal[i].toString();
|
|
100
|
+
if (firstChunk.length == 1) {
|
|
101
|
+
firstChunk = `0${firstChunk}`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let secondChunk = textAlignVal[i + 1].toString();
|
|
105
|
+
if (secondChunk.length == 1) {
|
|
106
|
+
secondChunk = `0${secondChunk}`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
let thirdChunk = textAlignVal[i + 2].toString();
|
|
110
|
+
if (thirdChunk.length == 1) {
|
|
111
|
+
thirdChunk = `0${thirdChunk}`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const codePoint = firstChunk + secondChunk + thirdChunk;
|
|
115
|
+
alignCodePoints.push(codePoint);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const textCodePoints = [];
|
|
119
|
+
for (let i = 0; i < textVal.length; i+=3) {
|
|
120
|
+
let firstChunk = textVal[i].toString();
|
|
121
|
+
if (firstChunk.length == 1) {
|
|
122
|
+
firstChunk = `0${firstChunk}`;
|
|
123
|
+
}
|
|
124
|
+
let secondChunk = textVal[i + 1].toString();
|
|
125
|
+
if (secondChunk.length == 1) {
|
|
126
|
+
secondChunk = `0${secondChunk}`;
|
|
127
|
+
}
|
|
128
|
+
let thirdChunk = textVal[i + 2].toString();
|
|
129
|
+
if (thirdChunk.length == 1) {
|
|
130
|
+
thirdChunk = `0${thirdChunk}`;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const codePoint = firstChunk + secondChunk + thirdChunk;
|
|
134
|
+
textCodePoints.push(codePoint);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const align = String.fromCodePoint.apply(null, alignCodePoints);
|
|
138
|
+
const text = String.fromCodePoint.apply(null, textCodePoints);
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
x: textPosX,
|
|
142
|
+
y: textPosY,
|
|
143
|
+
text: text,
|
|
144
|
+
size: textSize,
|
|
145
|
+
color: textColor,
|
|
146
|
+
align
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
module.exports = {
|
|
152
|
+
TEXT_SUBTYPE,
|
|
153
|
+
squishText
|
|
154
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const { GameNode } = require('./GameNode');
|
|
2
|
+
const subtypes = require('./subtypes');
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
[[subtypes.ASSET]]: GameNode.Asset,
|
|
6
|
+
[[subtypes.TEXT]]: GameNode.Text,
|
|
7
|
+
[[subtypes.SHAPE_2D_POLYGON]]: GameNode.Shape,
|
|
8
|
+
[[subtypes.SHAPE_2D_CIRCLE]]: GameNode.Shape,
|
|
9
|
+
[[subtypes.SHAPE_2D_LINE]]: GameNode.Shape
|
|
10
|
+
};
|
package/src/subtypes.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface pointDef {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export interface boardInfo {
|
|
7
|
+
filled: boolean;
|
|
8
|
+
north: boolean;
|
|
9
|
+
south: boolean;
|
|
10
|
+
east: boolean;
|
|
11
|
+
west: boolean;
|
|
12
|
+
wentSouth?: boolean;
|
|
13
|
+
wentEast?: boolean;
|
|
14
|
+
wentNorth?: boolean;
|
|
15
|
+
wentWest?: boolean;
|
|
16
|
+
};
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { getRandomTerrain, getRandomStartPoint } from './terrainFunctions';
|
|
2
|
+
import { pointDef, boardInfo } from './defs';
|
|
3
|
+
|
|
4
|
+
interface dimensionDef {
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const terrainGenerator = (boardBounds: pointDef = { x: 100, y: 100 }, terrainBounds: pointDef = { x: 5, y: 5 }, numberOfTerrainElements = 5) => {
|
|
10
|
+
const { width, height } = getBoardDimensions(boardBounds, terrainBounds);
|
|
11
|
+
let board = initializeBoard(width, height);
|
|
12
|
+
const keyPoint = {
|
|
13
|
+
x: Math.floor(Math.random() * width),
|
|
14
|
+
y: Math.floor(Math.random() * height)
|
|
15
|
+
};
|
|
16
|
+
board = generateTerrain(board, keyPoint, numberOfTerrainElements, width, height);
|
|
17
|
+
return board;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const getBoardDimensions = (boardBounds: pointDef, terrainBounds: pointDef): dimensionDef => {
|
|
21
|
+
const boardX = boardBounds.x;
|
|
22
|
+
const boardY = boardBounds.y;
|
|
23
|
+
const terrainX = terrainBounds.x;
|
|
24
|
+
const terrainY = terrainBounds.y;
|
|
25
|
+
return {
|
|
26
|
+
width: Math.floor(boardX/terrainX),
|
|
27
|
+
height: Math.floor(boardY/terrainY)
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const initializeBoard = (width: number, height: number): boardInfo[][] => {
|
|
32
|
+
const board: boardInfo[][] = [];
|
|
33
|
+
|
|
34
|
+
const defaultInfo: boardInfo = {
|
|
35
|
+
filled: false,
|
|
36
|
+
north: true,
|
|
37
|
+
south: true,
|
|
38
|
+
east: true,
|
|
39
|
+
west: true
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
for(let i = 0; i < width; i++) {
|
|
43
|
+
board[i] = [];
|
|
44
|
+
for (let j = 0; j < height; j++) {
|
|
45
|
+
const info = { ...defaultInfo };
|
|
46
|
+
if (i === 0) {
|
|
47
|
+
info.west = false;
|
|
48
|
+
} else if (i === width - 1) {
|
|
49
|
+
info.east = false;
|
|
50
|
+
}
|
|
51
|
+
if (j === 0) {
|
|
52
|
+
info.north = false;
|
|
53
|
+
} else if (j === height - 1) {
|
|
54
|
+
info.south = false;
|
|
55
|
+
}
|
|
56
|
+
board[i].push(info);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return board;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const deepClone = (toCopy: boardInfo[][]) => {
|
|
63
|
+
const toReturn: boardInfo[][] = [];
|
|
64
|
+
toCopy.forEach((row, rowNum) => {
|
|
65
|
+
toReturn[rowNum] = [];
|
|
66
|
+
row.forEach(elem => {
|
|
67
|
+
toReturn[rowNum].push({ ...elem });
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
return toReturn;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const cleanUpBoard = (board: boardInfo[][]) => {
|
|
74
|
+
for (let i = 0; i < board.length; i++) {
|
|
75
|
+
for (let j = 0; j < board[i].length; j++) {
|
|
76
|
+
board[i][j] = {
|
|
77
|
+
filled: board[i][j].filled,
|
|
78
|
+
north: board[i][j].north,
|
|
79
|
+
south: board[i][j].south,
|
|
80
|
+
east: board[i][j].east,
|
|
81
|
+
west: board[i][j].west
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const verifyKeyPoint = (board: boardInfo[][], keyPoint: pointDef, boardWidth: number, boardHeight: number) => {
|
|
88
|
+
const pointsVerified = [];
|
|
89
|
+
for (let x = 0; x < boardWidth; x++) {
|
|
90
|
+
for (let y = 0; y < boardHeight; y++) {
|
|
91
|
+
const pointsOnCurrentPath = [];
|
|
92
|
+
const currentPoint = { x, y };
|
|
93
|
+
while(true) {
|
|
94
|
+
const boardPoint = board[currentPoint.x][currentPoint.y];
|
|
95
|
+
if (
|
|
96
|
+
(pointsVerified.findIndex(point => point.x === currentPoint.x && point.y === currentPoint.y) > -1) ||
|
|
97
|
+
(currentPoint.x === keyPoint.x && currentPoint.y === keyPoint.y) ||
|
|
98
|
+
(boardPoint.filled)
|
|
99
|
+
) {
|
|
100
|
+
/*
|
|
101
|
+
if we already know we can reach the keyPoint from our test point or
|
|
102
|
+
if we are at the key point or
|
|
103
|
+
if we are in a filled point, just skip the iteration, no need to test this point further
|
|
104
|
+
*/
|
|
105
|
+
pointsVerified.push(...pointsOnCurrentPath);
|
|
106
|
+
break;
|
|
107
|
+
} else if(
|
|
108
|
+
(!boardPoint.north || boardPoint.wentNorth) &&
|
|
109
|
+
(!boardPoint.south || boardPoint.wentSouth) &&
|
|
110
|
+
(!boardPoint.east || boardPoint.wentEast) &&
|
|
111
|
+
(!boardPoint.west || boardPoint.wentWest)
|
|
112
|
+
) {
|
|
113
|
+
/*
|
|
114
|
+
if we have exhausted all possible movements for a point, and not reached the keypoint
|
|
115
|
+
then this possibleBoard is not workable
|
|
116
|
+
*/
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
pointsOnCurrentPath.push({ ...currentPoint });
|
|
120
|
+
if (boardPoint.south && !boardPoint.wentSouth) {
|
|
121
|
+
boardPoint.wentSouth = true;
|
|
122
|
+
currentPoint.y = currentPoint.y + 1;
|
|
123
|
+
} else if (boardPoint.east && !boardPoint.wentEast) {
|
|
124
|
+
boardPoint.wentEast = true;
|
|
125
|
+
currentPoint.x = currentPoint.x + 1;
|
|
126
|
+
} else if (boardPoint.north && !boardPoint.wentNorth) {
|
|
127
|
+
boardPoint.wentNorth = true;
|
|
128
|
+
currentPoint.y = currentPoint.y - 1;
|
|
129
|
+
} else if (boardPoint.west && !boardPoint.wentWest) {
|
|
130
|
+
boardPoint.wentWest = true;
|
|
131
|
+
currentPoint.x = currentPoint.x - 1;
|
|
132
|
+
} else {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
cleanUpBoard(board);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return true;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const generateTerrain = (board: boardInfo[][], keyPoint: pointDef, toPlace: number, boardWidth: number, boardHeight: number, numberOfIterations = 0): boardInfo[][] => {
|
|
143
|
+
if (toPlace === 0 || numberOfIterations === 3) {
|
|
144
|
+
return board;
|
|
145
|
+
}
|
|
146
|
+
const possibleBoard = deepClone(board);
|
|
147
|
+
const terrainFunction = getRandomTerrain();
|
|
148
|
+
const terrainStartPoint = getRandomStartPoint(boardWidth, boardHeight, keyPoint);
|
|
149
|
+
terrainFunction(possibleBoard, terrainStartPoint, boardWidth, boardHeight, keyPoint);
|
|
150
|
+
const temp = verifyKeyPoint(possibleBoard, keyPoint, boardWidth, boardHeight);
|
|
151
|
+
if (temp) {
|
|
152
|
+
return generateTerrain(possibleBoard, keyPoint, toPlace - 1, boardWidth, boardHeight, 0);
|
|
153
|
+
} else {
|
|
154
|
+
return generateTerrain(board, keyPoint, toPlace, boardWidth, boardHeight, numberOfIterations + 1);
|
|
155
|
+
}
|
|
156
|
+
};
|