volleyballsimtypes 0.0.507 → 0.0.509
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/dist/cjs/src/service/team/default-base-config.js +91 -78
- package/dist/cjs/src/service/team/index.d.ts +1 -0
- package/dist/cjs/src/service/team/index.js +1 -0
- package/dist/cjs/src/service/team/receive-overlap.d.ts +33 -0
- package/dist/cjs/src/service/team/receive-overlap.js +97 -0
- package/dist/esm/src/service/team/default-base-config.js +91 -78
- package/dist/esm/src/service/team/index.d.ts +1 -0
- package/dist/esm/src/service/team/index.js +1 -0
- package/dist/esm/src/service/team/receive-overlap.d.ts +33 -0
- package/dist/esm/src/service/team/receive-overlap.js +90 -0
- package/package.json +1 -1
|
@@ -2,89 +2,90 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.defaultReceiveMap = defaultReceiveMap;
|
|
4
4
|
exports.defaultBaseConfig = defaultBaseConfig;
|
|
5
|
+
const rotation_system_1 = require("./rotation-system");
|
|
5
6
|
const lineup_function_1 = require("./lineup-function");
|
|
6
7
|
const player_1 = require("../player");
|
|
7
8
|
const match_1 = require("../match");
|
|
8
9
|
const COORDS = {
|
|
9
10
|
SERVE: {
|
|
10
|
-
1: { 1: { d: 10
|
|
11
|
-
2: { 1: { d:
|
|
12
|
-
3: { 1: { d:
|
|
13
|
-
4: { 1: { d: 10
|
|
14
|
-
5: { 1: { d:
|
|
15
|
-
6: { 1: { d:
|
|
11
|
+
1: { 1: { d: 10, r: 3.5 }, 2: { d: 0.5, r: -2.5 }, 3: { d: 0.5, r: 0 }, 4: { d: 0.5, r: 2.5 }, 5: { d: 6.5, r: 0 }, 6: { d: 5, r: -2.5 } },
|
|
12
|
+
2: { 1: { d: 9.8, r: -2.7 }, 2: { d: 0.6, r: 2.35 }, 3: { d: 0.6, r: -2.55 }, 4: { d: 0.5, r: -0.2 }, 5: { d: 5, r: 3.25 }, 6: { d: 7.4, r: 0.15 } },
|
|
13
|
+
3: { 1: { d: 9.85, r: 3.3 }, 2: { d: 0.55, r: -0.05 }, 3: { d: 0.6, r: 2.45 }, 4: { d: 0.6, r: -2.7 }, 5: { d: 5.3, r: -2.75 }, 6: { d: 5.3, r: 2.7 } },
|
|
14
|
+
4: { 1: { d: 10, r: 3.5 }, 2: { d: 0.5, r: -2.5 }, 3: { d: 0.5, r: 0 }, 4: { d: 0.5, r: 2.4 }, 5: { d: 6.5, r: 0 }, 6: { d: 5, r: -2.5 } },
|
|
15
|
+
5: { 1: { d: 9.75, r: 3.25 }, 2: { d: 0.65, r: 2.8 }, 3: { d: 0.8, r: -2.85 }, 4: { d: 0.6, r: 0.05 }, 5: { d: 4.75, r: 2.85 }, 6: { d: 6.95, r: 0 } },
|
|
16
|
+
6: { 1: { d: 9.8, r: 3.05 }, 2: { d: 0.45, r: 0.05 }, 3: { d: 0.5, r: 2.45 }, 4: { d: 0.45, r: -2.8 }, 5: { d: 4.6, r: -2.65 }, 6: { d: 4.7, r: 3 } }
|
|
16
17
|
},
|
|
17
18
|
RECEIVE: {
|
|
18
|
-
1: { 1: { d: 6.
|
|
19
|
-
2: { 1: { d:
|
|
20
|
-
3: { 1: { d: 6
|
|
21
|
-
4: { 1: { d: 8.
|
|
22
|
-
5: { 1: { d: 6.
|
|
23
|
-
6: { 1: { d: 6
|
|
19
|
+
1: { 1: { d: 6.5, r: 3.5 }, 2: { d: 6, r: 3 }, 3: { d: 3, r: -3.5 }, 4: { d: 3.5, r: -4 }, 5: { d: 6, r: -3 }, 6: { d: 6.5, r: 0 } },
|
|
20
|
+
2: { 1: { d: 5.65, r: 2.3 }, 2: { d: 0.65, r: 2.1 }, 3: { d: 6, r: -2.3 }, 4: { d: 2.75, r: -3.9 }, 5: { d: 7.85, r: -1.7 }, 6: { d: 6.75, r: 0.1 } },
|
|
21
|
+
3: { 1: { d: 6, r: 3 }, 2: { d: 2.5, r: 3.95 }, 3: { d: 0.75, r: 1 }, 4: { d: 5.55, r: -2.75 }, 5: { d: 6.1, r: 0.1 }, 6: { d: 7.8, r: 1.65 } },
|
|
22
|
+
4: { 1: { d: 8.5, r: 4 }, 2: { d: 6, r: -3 }, 3: { d: 1.25, r: -4 }, 4: { d: 0.75, r: -4.05 }, 5: { d: 6.5, r: 0 }, 6: { d: 6, r: 3 } },
|
|
23
|
+
5: { 1: { d: 6.1, r: 2.6 }, 2: { d: 3.25, r: 3.9 }, 3: { d: 5.8, r: -2.75 }, 4: { d: 0.75, r: -3.85 }, 5: { d: 1.9, r: -1.7 }, 6: { d: 6.75, r: -0.1 } },
|
|
24
|
+
6: { 1: { d: 6, r: 3 }, 2: { d: 2.6, r: 3.85 }, 3: { d: 0.5, r: 0.4 }, 4: { d: 5.9, r: -2.9 }, 5: { d: 6.55, r: 0 }, 6: { d: 1.6, r: 0.9 } }
|
|
24
25
|
},
|
|
25
26
|
DEFENCE: {
|
|
26
|
-
1: { 1: { d: 5
|
|
27
|
-
2: { 1: { d:
|
|
28
|
-
3: { 1: { d:
|
|
29
|
-
4: { 1: { d: 5
|
|
30
|
-
5: { 1: { d:
|
|
31
|
-
6: { 1: { d:
|
|
27
|
+
1: { 1: { d: 5, r: 3 }, 2: { d: 0.5, r: -2.5 }, 3: { d: 0.5, r: 0 }, 4: { d: 0.5, r: 2.5 }, 5: { d: 7, r: 0 }, 6: { d: 5, r: -3 } },
|
|
28
|
+
2: { 1: { d: 4.9, r: -3 }, 2: { d: 0.6, r: 2.65 }, 3: { d: 0.65, r: -3 }, 4: { d: 0.65, r: -0.1 }, 5: { d: 5, r: 3.05 }, 6: { d: 6.75, r: 0.2 } },
|
|
29
|
+
3: { 1: { d: 7, r: 0.05 }, 2: { d: 0.5, r: 0.2 }, 3: { d: 0.6, r: 2.65 }, 4: { d: 0.5, r: -2.7 }, 5: { d: 4.7, r: -2.3 }, 6: { d: 4.85, r: 2.6 } },
|
|
30
|
+
4: { 1: { d: 5, r: 3 }, 2: { d: 0.5, r: -2.5 }, 3: { d: 0.5, r: 0 }, 4: { d: 0.5, r: 2.5 }, 5: { d: 7, r: 0 }, 6: { d: 5, r: -3 } },
|
|
31
|
+
5: { 1: { d: 4.8, r: -3.15 }, 2: { d: 0.6, r: 2.5 }, 3: { d: 0.65, r: -2.85 }, 4: { d: 0.65, r: -0.15 }, 5: { d: 5, r: 2.75 }, 6: { d: 6.75, r: 0.05 } },
|
|
32
|
+
6: { 1: { d: 7.2, r: -0.05 }, 2: { d: 0.45, r: -0.4 }, 3: { d: 0.55, r: 2.45 }, 4: { d: 0.55, r: -3 }, 5: { d: 4.85, r: -2.85 }, 6: { d: 4.8, r: 2.25 } }
|
|
32
33
|
},
|
|
33
34
|
DEF_L: {
|
|
34
|
-
1: { 1: { d: 5
|
|
35
|
-
2: { 1: { d:
|
|
36
|
-
3: { 1: { d:
|
|
37
|
-
4: { 1: { d: 5
|
|
38
|
-
5: { 1: { d:
|
|
39
|
-
6: { 1: { d:
|
|
35
|
+
1: { 1: { d: 5, r: 1.5 }, 2: { d: 0.25, r: -4 }, 3: { d: 0.25, r: -3.25 }, 4: { d: 1.75, r: 1.25 }, 5: { d: 8, r: -0.5 }, 6: { d: 5, r: -4.2 } },
|
|
36
|
+
2: { 1: { d: 4.45, r: -3.95 }, 2: { d: 1.9, r: 1.3 }, 3: { d: 0.4, r: -3.8 }, 4: { d: 0.4, r: -2.9 }, 5: { d: 5.05, r: 2.45 }, 6: { d: 7.6, r: -0.05 } },
|
|
37
|
+
3: { 1: { d: 8.2, r: -0.7 }, 2: { d: 0.4, r: -2.65 }, 3: { d: 2.1, r: 0.8 }, 4: { d: 0.45, r: -3.8 }, 5: { d: 5.1, r: -3.85 }, 6: { d: 5.2, r: 1.8 } },
|
|
38
|
+
4: { 1: { d: 5, r: 1.5 }, 2: { d: 0.25, r: -4 }, 3: { d: 0.25, r: -3.25 }, 4: { d: 1.75, r: 1.25 }, 5: { d: 8, r: -0.5 }, 6: { d: 5, r: -4.2 } },
|
|
39
|
+
5: { 1: { d: 5.05, r: -3.9 }, 2: { d: 2.2, r: 0.65 }, 3: { d: 0.65, r: -3.8 }, 4: { d: 0.65, r: -2.75 }, 5: { d: 4.65, r: 1.1 }, 6: { d: 7.7, r: -0.75 } },
|
|
40
|
+
6: { 1: { d: 7.15, r: 0.25 }, 2: { d: 0.5, r: -2.7 }, 3: { d: 1.8, r: 1.1 }, 4: { d: 0.5, r: -3.8 }, 5: { d: 4.75, r: -3.85 }, 6: { d: 4.95, r: 1.6 } }
|
|
40
41
|
},
|
|
41
42
|
DEF_M: {
|
|
42
|
-
1: { 1: { d: 5
|
|
43
|
-
2: { 1: { d:
|
|
44
|
-
3: { 1: { d:
|
|
45
|
-
4: { 1: { d: 5
|
|
46
|
-
5: { 1: { d:
|
|
47
|
-
6: { 1: { d:
|
|
43
|
+
1: { 1: { d: 5, r: 2.5 }, 2: { d: 1.75, r: -2.5 }, 3: { d: 0.25, r: 0 }, 4: { d: 1.75, r: 2.5 }, 5: { d: 7, r: 0 }, 6: { d: 5, r: -2.5 } },
|
|
44
|
+
2: { 1: { d: 5, r: -2.8 }, 2: { d: 1.85, r: 2.5 }, 3: { d: 1.85, r: -2.4 }, 4: { d: 0.4, r: 0.15 }, 5: { d: 5, r: 2.65 }, 6: { d: 7, r: 0.05 } },
|
|
45
|
+
3: { 1: { d: 7.15, r: 0.1 }, 2: { d: 0.5, r: 0.1 }, 3: { d: 1.95, r: 2.45 }, 4: { d: 1.8, r: -2.55 }, 5: { d: 5.25, r: -2.45 }, 6: { d: 5.2, r: 2.8 } },
|
|
46
|
+
4: { 1: { d: 5, r: 2.5 }, 2: { d: 1.75, r: -2.5 }, 3: { d: 0.25, r: 0 }, 4: { d: 1.75, r: 2.5 }, 5: { d: 7, r: 0 }, 6: { d: 5, r: -2.5 } },
|
|
47
|
+
5: { 1: { d: 4.9, r: -2.35 }, 2: { d: 1.95, r: 2.4 }, 3: { d: 1.85, r: -2.6 }, 4: { d: 0.55, r: -0.2 }, 5: { d: 4.9, r: 2.45 }, 6: { d: 6.7, r: -0.1 } },
|
|
48
|
+
6: { 1: { d: 7.35, r: 0.05 }, 2: { d: 0.6, r: 0.1 }, 3: { d: 2, r: 2.45 }, 4: { d: 2.25, r: -1.95 }, 5: { d: 5.2, r: -2.05 }, 6: { d: 5.3, r: 2.5 } }
|
|
48
49
|
},
|
|
49
50
|
DEF_R: {
|
|
50
|
-
1: { 1: { d: 5
|
|
51
|
-
2: { 1: { d:
|
|
52
|
-
3: { 1: { d:
|
|
53
|
-
4: { 1: { d: 5
|
|
54
|
-
5: { 1: { d:
|
|
55
|
-
6: { 1: { d:
|
|
51
|
+
1: { 1: { d: 5, r: 4.2 }, 2: { d: 1.75, r: -1.25 }, 3: { d: 0.25, r: 3.25 }, 4: { d: 0.25, r: 4 }, 5: { d: 8, r: 0.5 }, 6: { d: 5, r: -1.5 } },
|
|
52
|
+
2: { 1: { d: 4.65, r: -1 }, 2: { d: 0.25, r: 3.85 }, 3: { d: 1.75, r: -1.4 }, 4: { d: 0.3, r: 2.95 }, 5: { d: 4.3, r: 3.95 }, 6: { d: 8.15, r: 0.5 } },
|
|
53
|
+
3: { 1: { d: 8.05, r: 0.4 }, 2: { d: 0.4, r: 2.95 }, 3: { d: 0.4, r: 3.85 }, 4: { d: 2, r: -2 }, 5: { d: 4.65, r: -1.15 }, 6: { d: 4.75, r: 4 } },
|
|
54
|
+
4: { 1: { d: 5, r: 4.2 }, 2: { d: 1.75, r: -1.25 }, 3: { d: 0.25, r: 3.25 }, 4: { d: 0.25, r: 4 }, 5: { d: 8, r: 0.5 }, 6: { d: 5, r: -1.5 } },
|
|
55
|
+
5: { 1: { d: 5.35, r: -2 }, 2: { d: 0.5, r: 3.65 }, 3: { d: 2.1, r: -1.25 }, 4: { d: 0.5, r: 2.6 }, 5: { d: 5.4, r: 3.85 }, 6: { d: 7.75, r: -0.15 } },
|
|
56
|
+
6: { 1: { d: 7.8, r: 0.75 }, 2: { d: 0.45, r: 2.9 }, 3: { d: 0.45, r: 3.95 }, 4: { d: 1.75, r: -0.25 }, 5: { d: 5.15, r: -1.4 }, 6: { d: 4.9, r: 4 } }
|
|
56
57
|
},
|
|
57
58
|
ATTACK: {
|
|
58
|
-
1: { 1: { d: 0.
|
|
59
|
-
2: { 1: { d:
|
|
60
|
-
3: { 1: { d:
|
|
61
|
-
4: { 1: { d: 6.
|
|
62
|
-
5: { 1: { d:
|
|
63
|
-
6: { 1: { d:
|
|
59
|
+
1: { 1: { d: 0.5, r: 1.5 }, 2: { d: 3.75, r: -5 }, 3: { d: 3, r: 0.25 }, 4: { d: 3.75, r: 5 }, 5: { d: 6.5, r: 0 }, 6: { d: 4.5, r: -2.5 } },
|
|
60
|
+
2: { 1: { d: 5.1, r: -2 }, 2: { d: 0.45, r: 1.55 }, 3: { d: 3.6, r: -5.2 }, 4: { d: 2.8, r: 0.2 }, 5: { d: 6.4, r: 5.05 }, 6: { d: 6.55, r: -0.6 } },
|
|
61
|
+
3: { 1: { d: 6.5, r: -0.15 }, 2: { d: 3, r: 0.35 }, 3: { d: 0.5, r: 1.6 }, 4: { d: 2.4, r: -5.15 }, 5: { d: 4.6, r: -2.55 }, 6: { d: 5.4, r: 5.2 } },
|
|
62
|
+
4: { 1: { d: 6.5, r: 4.9 }, 2: { d: 3.75, r: -5 }, 3: { d: 3, r: 0.25 }, 4: { d: 0.5, r: 1.5 }, 5: { d: 6.5, r: 0 }, 6: { d: 4.5, r: -2.5 } },
|
|
63
|
+
5: { 1: { d: 4.65, r: -2.35 }, 2: { d: 3.65, r: 4.8 }, 3: { d: 2.9, r: -5.15 }, 4: { d: 3.05, r: 0.4 }, 5: { d: 0.75, r: 1.7 }, 6: { d: 6.4, r: -0.05 } },
|
|
64
|
+
6: { 1: { d: 6.2, r: -0.4 }, 2: { d: 3, r: 0.2 }, 3: { d: 3.65, r: 5.2 }, 4: { d: 3.55, r: -5.2 }, 5: { d: 4.5, r: -2.45 }, 6: { d: 0.65, r: 1.3 } }
|
|
64
65
|
},
|
|
65
66
|
ATK_L: {
|
|
66
|
-
1: { 1: { d: 0.75, r: 0
|
|
67
|
-
2: { 1: { d:
|
|
68
|
-
3: { 1: { d:
|
|
69
|
-
4: { 1: { d: 3.
|
|
70
|
-
5: { 1: { d:
|
|
71
|
-
6: { 1: { d:
|
|
67
|
+
1: { 1: { d: 0.75, r: 0 }, 2: { d: 0.5, r: -4 }, 3: { d: 1, r: -2.5 }, 4: { d: 3.5, r: 0.75 }, 5: { d: 6.25, r: -0.75 }, 6: { d: 3.5, r: -4 } },
|
|
68
|
+
2: { 1: { d: 3.4, r: -4.05 }, 2: { d: 0.75, r: 0 }, 3: { d: 0.9, r: -4.15 }, 4: { d: 1.8, r: -2.5 }, 5: { d: 3.4, r: 0.5 }, 6: { d: 6.5, r: -1.15 } },
|
|
69
|
+
3: { 1: { d: 6.35, r: -0.1 }, 2: { d: 2.1, r: -2.45 }, 3: { d: 0.9, r: 0 }, 4: { d: 0.8, r: -3.95 }, 5: { d: 4.6, r: -3.75 }, 6: { d: 3.6, r: 1.45 } },
|
|
70
|
+
4: { 1: { d: 3.5, r: 0.75 }, 2: { d: 0.5, r: -4 }, 3: { d: 1, r: -2.5 }, 4: { d: 0.75, r: 0 }, 5: { d: 6.25, r: -0.75 }, 6: { d: 3.5, r: -4 } },
|
|
71
|
+
5: { 1: { d: 4.25, r: -3.85 }, 2: { d: 3.55, r: 0.75 }, 3: { d: 1, r: -4.1 }, 4: { d: 2.05, r: -2.65 }, 5: { d: 0.85, r: -0.15 }, 6: { d: 6, r: -0.8 } },
|
|
72
|
+
6: { 1: { d: 5.9, r: -1 }, 2: { d: 1.05, r: -2.5 }, 3: { d: 3.45, r: 0.9 }, 4: { d: 0.7, r: -3.9 }, 5: { d: 3.4, r: -4.05 }, 6: { d: 0.75, r: -0.2 } }
|
|
72
73
|
},
|
|
73
74
|
ATK_M: {
|
|
74
|
-
1: { 1: { d: 0.75, r: 1.25 }, 2: { d: 1.25, r: -2
|
|
75
|
-
2: { 1: { d:
|
|
76
|
-
3: { 1: { d:
|
|
77
|
-
4: { 1: { d: 2.25, r: 2.
|
|
78
|
-
5: { 1: { d:
|
|
79
|
-
6: { 1: { d:
|
|
75
|
+
1: { 1: { d: 0.75, r: 1.25 }, 2: { d: 1.25, r: -2 }, 3: { d: 0.75, r: 0.5 }, 4: { d: 2.25, r: 2.6 }, 5: { d: 6.5, r: 1.5 }, 6: { d: 4, r: -1.5 } },
|
|
76
|
+
2: { 1: { d: 4.5, r: -2.2 }, 2: { d: 0.7, r: 1.25 }, 3: { d: 1.8, r: -2.45 }, 4: { d: 0.9, r: 0.05 }, 5: { d: 2.75, r: 3.05 }, 6: { d: 5.75, r: 0 } },
|
|
77
|
+
3: { 1: { d: 6.55, r: 1.15 }, 2: { d: 0.9, r: 0.3 }, 3: { d: 0.85, r: 1.45 }, 4: { d: 1.7, r: -2.7 }, 5: { d: 3.95, r: -1.75 }, 6: { d: 2.25, r: 3.2 } },
|
|
78
|
+
4: { 1: { d: 2.25, r: 2.6 }, 2: { d: 1.25, r: -2 }, 3: { d: 0.75, r: 0.5 }, 4: { d: 0.75, r: 1.25 }, 5: { d: 6.5, r: 1.5 }, 6: { d: 4, r: -1.5 } },
|
|
79
|
+
5: { 1: { d: 4.35, r: -1.5 }, 2: { d: 2.25, r: 2.85 }, 3: { d: 1.9, r: -2.55 }, 4: { d: 0.8, r: 0.35 }, 5: { d: 0.6, r: 1.45 }, 6: { d: 5.55, r: 1.45 } },
|
|
80
|
+
6: { 1: { d: 5.2, r: 1.1 }, 2: { d: 0.8, r: 0.35 }, 3: { d: 2.4, r: 3 }, 4: { d: 1.8, r: -2.15 }, 5: { d: 4.5, r: -1.7 }, 6: { d: 0.8, r: 1.35 } }
|
|
80
81
|
},
|
|
81
82
|
ATK_R: {
|
|
82
|
-
1: { 1: { d: 1.75, r: 2.
|
|
83
|
-
2: { 1: { d:
|
|
84
|
-
3: { 1: { d: 5.
|
|
85
|
-
4: { 1: { d: 2.25, r: 4
|
|
86
|
-
5: { 1: { d:
|
|
87
|
-
6: { 1: { d: 5.
|
|
83
|
+
1: { 1: { d: 1.75, r: 2.5 }, 2: { d: 1.5, r: -1.75 }, 3: { d: 0.75, r: 1.75 }, 4: { d: 0.5, r: 4 }, 5: { d: 5, r: 3.25 }, 6: { d: 5.75, r: -2 } },
|
|
84
|
+
2: { 1: { d: 4.65, r: -0.8 }, 2: { d: 0.75, r: 1.75 }, 3: { d: 1.85, r: -1.75 }, 4: { d: 1.7, r: 2.2 }, 5: { d: 2.15, r: 4.25 }, 6: { d: 6.25, r: 2 } },
|
|
85
|
+
3: { 1: { d: 5.1, r: 3.15 }, 2: { d: 1.85, r: 2.6 }, 3: { d: 0.8, r: 1.75 }, 4: { d: 2.15, r: -1.7 }, 5: { d: 4.9, r: -1.25 }, 6: { d: 1.9, r: 4.15 } },
|
|
86
|
+
4: { 1: { d: 2.25, r: 4 }, 2: { d: 2.25, r: -1.75 }, 3: { d: 0.75, r: 1.5 }, 4: { d: 1.5, r: 2.25 }, 5: { d: 6, r: 2.25 }, 6: { d: 5, r: -0.75 } },
|
|
87
|
+
5: { 1: { d: 5.95, r: -2 }, 2: { d: 0.9, r: 3.7 }, 3: { d: 2.2, r: -1.6 }, 4: { d: 2, r: 2.35 }, 5: { d: 0.9, r: 1.15 }, 6: { d: 6, r: 1.9 } },
|
|
88
|
+
6: { 1: { d: 5.35, r: 2.35 }, 2: { d: 2.05, r: 2.1 }, 3: { d: 0.8, r: 4 }, 4: { d: 2.1, r: -1.95 }, 5: { d: 4.9, r: -1.4 }, 6: { d: 0.4, r: 1.3 } }
|
|
88
89
|
}
|
|
89
90
|
};
|
|
90
91
|
// The default coordinate table as a BaseConfig.coords (jsonb string keys). Shared, readonly; materialized (and so
|
|
@@ -101,36 +102,47 @@ const DEFAULT_COORDS = (() => {
|
|
|
101
102
|
}
|
|
102
103
|
return out;
|
|
103
104
|
})();
|
|
104
|
-
// The owner's
|
|
105
|
+
// The owner's corrected per-point-of-attack block map for the 5-1 (exported 2026-08-09), keyed
|
|
105
106
|
// [DEF_L|DEF_M|DEF_R][rotation][zone] -> canBlock. `false` = that front-row zone sits OUT of the block for an attack
|
|
106
|
-
// from that side; `true` = reads/joins the wall. Only front-row zones
|
|
107
|
-
// as DEFAULT_COORDS.
|
|
107
|
+
// from that side; `true` = reads/joins the wall. Only the front-row zones in play for the rotation are tagged. Same
|
|
108
|
+
// rotation convention as DEFAULT_COORDS.
|
|
108
109
|
const DEFAULT_BLOCKING = {
|
|
109
110
|
DEF_L: {
|
|
110
111
|
1: { 2: true, 3: true, 4: false },
|
|
111
|
-
2: { 2:
|
|
112
|
-
3: {
|
|
112
|
+
2: { 2: false, 4: true },
|
|
113
|
+
3: { 3: false, 4: true },
|
|
113
114
|
4: { 2: true, 3: true, 4: false },
|
|
114
|
-
5: { 2:
|
|
115
|
-
6: {
|
|
115
|
+
5: { 2: false, 4: true },
|
|
116
|
+
6: { 3: false, 4: true }
|
|
116
117
|
},
|
|
117
118
|
DEF_M: {
|
|
118
119
|
1: { 2: false, 3: true, 4: false },
|
|
119
|
-
2: { 2:
|
|
120
|
-
3: {
|
|
120
|
+
2: { 2: false, 3: false },
|
|
121
|
+
3: { 3: false, 4: false },
|
|
121
122
|
4: { 2: false, 3: true, 4: false },
|
|
122
|
-
5: { 2:
|
|
123
|
-
6: {
|
|
123
|
+
5: { 2: false, 3: false },
|
|
124
|
+
6: { 3: false, 4: false }
|
|
124
125
|
},
|
|
125
126
|
DEF_R: {
|
|
126
127
|
1: { 2: false, 3: true, 4: true },
|
|
127
|
-
2: { 2: true, 3:
|
|
128
|
-
3: { 2: true,
|
|
128
|
+
2: { 2: true, 3: false },
|
|
129
|
+
3: { 2: true, 4: false },
|
|
129
130
|
4: { 2: false, 3: true, 4: true },
|
|
130
|
-
5: { 2: true, 3:
|
|
131
|
-
6: { 2: true,
|
|
131
|
+
5: { 2: true, 3: false },
|
|
132
|
+
6: { 2: true, 4: false }
|
|
132
133
|
}
|
|
133
134
|
};
|
|
135
|
+
// The owner's corrected 5-1 serve-receive participation map (exported 2026-08-09). The 5-1 uses this exact map; the
|
|
136
|
+
// other systems derive their 3-passer map from slot functions (defaultReceiveMap) since their receiving personnel
|
|
137
|
+
// differ. Keyed [rotation][zone] -> passes.
|
|
138
|
+
const DEFAULT_5_1_RECEIVE = {
|
|
139
|
+
1: { 1: false, 2: true, 3: false, 4: false, 5: true, 6: true },
|
|
140
|
+
2: { 1: true, 2: false, 3: true, 4: false, 5: false, 6: true },
|
|
141
|
+
3: { 1: true, 2: false, 3: false, 4: true, 5: true, 6: false },
|
|
142
|
+
4: { 1: false, 2: true, 3: false, 4: false, 5: true, 6: true },
|
|
143
|
+
5: { 1: true, 2: false, 3: true, 4: false, 5: false, 6: true },
|
|
144
|
+
6: { 1: true, 2: false, 3: false, 4: true, 5: true, 6: false }
|
|
145
|
+
};
|
|
134
146
|
// Rotation index -> the setter's rotational zone (inverse of SETTER_ZONE_TO_ROTATION {1:1,6:2,5:3,4:4,3:5,2:6}).
|
|
135
147
|
const ROTATION_TO_SETTER_ZONE = { 1: 1, 2: 6, 3: 5, 4: 4, 5: 3, 6: 2 };
|
|
136
148
|
// The default serve-receive participation map: the standard 3-passer formation. A rotational slot passes iff its
|
|
@@ -151,8 +163,9 @@ function defaultReceiveMap(system) {
|
|
|
151
163
|
return receive;
|
|
152
164
|
}
|
|
153
165
|
// The default base config a team of the given system starts with. Every team always has one (materialized on team
|
|
154
|
-
// creation and by the backfill migration)
|
|
155
|
-
// receive map
|
|
166
|
+
// creation and by the backfill migration). Every system reuses the corrected 5-1 coordinate table and block map; the
|
|
167
|
+
// 5-1 uses the owner's exported receive map, the other systems derive their receive map per system.
|
|
156
168
|
function defaultBaseConfig(system) {
|
|
157
|
-
|
|
169
|
+
const receive = system === rotation_system_1.RotationSystemEnum.FIVE_ONE ? DEFAULT_5_1_RECEIVE : defaultReceiveMap(system);
|
|
170
|
+
return { coords: DEFAULT_COORDS, receive, blocking: DEFAULT_BLOCKING };
|
|
158
171
|
}
|
|
@@ -4,6 +4,7 @@ export * from './formation';
|
|
|
4
4
|
export * from './tactics';
|
|
5
5
|
export * from './base-config';
|
|
6
6
|
export * from './default-base-config';
|
|
7
|
+
export * from './receive-overlap';
|
|
7
8
|
export * from './team-name';
|
|
8
9
|
export * from './energy-band';
|
|
9
10
|
export * from './pinch-condition';
|
|
@@ -20,6 +20,7 @@ __exportStar(require("./formation"), exports);
|
|
|
20
20
|
__exportStar(require("./tactics"), exports);
|
|
21
21
|
__exportStar(require("./base-config"), exports);
|
|
22
22
|
__exportStar(require("./default-base-config"), exports);
|
|
23
|
+
__exportStar(require("./receive-overlap"), exports);
|
|
23
24
|
__exportStar(require("./team-name"), exports);
|
|
24
25
|
__exportStar(require("./energy-band"), exports);
|
|
25
26
|
__exportStar(require("./pinch-condition"), exports);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { BaseConfig } from './base-config';
|
|
2
|
+
export interface ReceiveOverlapViolation {
|
|
3
|
+
/** Rotation (1..6) that has at least one violation. */
|
|
4
|
+
readonly rotation: number;
|
|
5
|
+
/** The rotational zones (1..6) involved in a violation, to flag in the editor. */
|
|
6
|
+
readonly zones: number[];
|
|
7
|
+
/** Human-readable violation messages for that rotation. */
|
|
8
|
+
readonly messages: string[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Returns every RECEIVE rotation that breaks the overlap rule (empty if the whole receive formation is legal).
|
|
12
|
+
* A missing RECEIVE map or a missing zone is skipped rather than flagged, so partial/legacy configs never throw.
|
|
13
|
+
*/
|
|
14
|
+
export declare function receiveOverlapViolations(config: BaseConfig): ReceiveOverlapViolation[];
|
|
15
|
+
/** True when the RECEIVE formation of `config` respects the overlap rule in every rotation. */
|
|
16
|
+
export declare function isReceiveOverlapLegal(config: BaseConfig): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Returns every SERVE rotation whose server (zone 1) is NOT behind the end line (owner 2026-08-10: on Serve, only
|
|
19
|
+
* the server is constrained; the rest of the serving formation is free). A missing SERVE map or zone-1 coord is
|
|
20
|
+
* skipped rather than flagged, so partial/legacy configs never throw.
|
|
21
|
+
*/
|
|
22
|
+
export declare function serveLineViolations(config: BaseConfig): ReceiveOverlapViolation[];
|
|
23
|
+
/** A base-config rule violation, tagged with the formation it belongs to so the editor/API can point at it. */
|
|
24
|
+
export interface FormationViolation extends ReceiveOverlapViolation {
|
|
25
|
+
readonly formation: 'RECEIVE' | 'SERVE';
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Every base-config rule violation across the constrained formations: the RECEIVE overlap rule and the SERVE
|
|
29
|
+
* server-behind-the-line rule. This is the single check the tactics save (UI + API) and the editor flagging share.
|
|
30
|
+
*/
|
|
31
|
+
export declare function baseConfigViolations(config: BaseConfig): FormationViolation[];
|
|
32
|
+
/** True when `config` breaks no RECEIVE overlap rule and no SERVE server-line rule. */
|
|
33
|
+
export declare function isBaseConfigLegal(config: BaseConfig): boolean;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.receiveOverlapViolations = receiveOverlapViolations;
|
|
4
|
+
exports.isReceiveOverlapLegal = isReceiveOverlapLegal;
|
|
5
|
+
exports.serveLineViolations = serveLineViolations;
|
|
6
|
+
exports.baseConfigViolations = baseConfigViolations;
|
|
7
|
+
exports.isBaseConfigLegal = isBaseConfigLegal;
|
|
8
|
+
/**
|
|
9
|
+
* Returns every RECEIVE rotation that breaks the overlap rule (empty if the whole receive formation is legal).
|
|
10
|
+
* A missing RECEIVE map or a missing zone is skipped rather than flagged, so partial/legacy configs never throw.
|
|
11
|
+
*/
|
|
12
|
+
function receiveOverlapViolations(config) {
|
|
13
|
+
const rc = config.coords?.RECEIVE;
|
|
14
|
+
if (rc == null)
|
|
15
|
+
return [];
|
|
16
|
+
const out = [];
|
|
17
|
+
for (let rot = 1; rot <= 6; rot++) {
|
|
18
|
+
const row = rc[String(rot)];
|
|
19
|
+
if (row == null)
|
|
20
|
+
continue;
|
|
21
|
+
const at = (zone) => row[String(zone)];
|
|
22
|
+
const bad = new Set();
|
|
23
|
+
const messages = [];
|
|
24
|
+
const lateral = (left, right, ln, rn) => {
|
|
25
|
+
const a = at(left);
|
|
26
|
+
const b = at(right);
|
|
27
|
+
if (a == null || b == null)
|
|
28
|
+
return;
|
|
29
|
+
if (a.r >= b.r) {
|
|
30
|
+
bad.add(left);
|
|
31
|
+
bad.add(right);
|
|
32
|
+
messages.push(`${ln} must be left of ${rn}`);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const depth = (front, back, fn, bn) => {
|
|
36
|
+
const a = at(front);
|
|
37
|
+
const b = at(back);
|
|
38
|
+
if (a == null || b == null)
|
|
39
|
+
return;
|
|
40
|
+
if (a.d >= b.d) {
|
|
41
|
+
bad.add(front);
|
|
42
|
+
bad.add(back);
|
|
43
|
+
messages.push(`${fn} must be in front of ${bn}`);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
lateral(4, 3, 'left-front', 'middle-front');
|
|
47
|
+
lateral(3, 2, 'middle-front', 'right-front');
|
|
48
|
+
lateral(5, 6, 'left-back', 'middle-back');
|
|
49
|
+
lateral(6, 1, 'middle-back', 'right-back');
|
|
50
|
+
depth(2, 1, 'right-front', 'right-back');
|
|
51
|
+
depth(3, 6, 'middle-front', 'middle-back');
|
|
52
|
+
depth(4, 5, 'left-front', 'left-back');
|
|
53
|
+
if (bad.size > 0)
|
|
54
|
+
out.push({ rotation: rot, zones: [...bad].sort((a, b) => a - b), messages });
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
/** True when the RECEIVE formation of `config` respects the overlap rule in every rotation. */
|
|
59
|
+
function isReceiveOverlapLegal(config) {
|
|
60
|
+
return receiveOverlapViolations(config).length === 0;
|
|
61
|
+
}
|
|
62
|
+
// The end line sits 9 m off the net (the FIVB court depth; matches the court editor's END_LINE). A server must
|
|
63
|
+
// contact the ball from BEHIND it, so on the SERVE formation the server (rotational zone 1) must have d >= this.
|
|
64
|
+
const END_LINE_DEPTH = 9;
|
|
65
|
+
/**
|
|
66
|
+
* Returns every SERVE rotation whose server (zone 1) is NOT behind the end line (owner 2026-08-10: on Serve, only
|
|
67
|
+
* the server is constrained; the rest of the serving formation is free). A missing SERVE map or zone-1 coord is
|
|
68
|
+
* skipped rather than flagged, so partial/legacy configs never throw.
|
|
69
|
+
*/
|
|
70
|
+
function serveLineViolations(config) {
|
|
71
|
+
const sc = config.coords?.SERVE;
|
|
72
|
+
if (sc == null)
|
|
73
|
+
return [];
|
|
74
|
+
const out = [];
|
|
75
|
+
for (let rot = 1; rot <= 6; rot++) {
|
|
76
|
+
const server = sc[String(rot)]?.['1'];
|
|
77
|
+
if (server == null)
|
|
78
|
+
continue;
|
|
79
|
+
if (server.d < END_LINE_DEPTH)
|
|
80
|
+
out.push({ rotation: rot, zones: [1], messages: ['server must be behind the end line'] });
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Every base-config rule violation across the constrained formations: the RECEIVE overlap rule and the SERVE
|
|
86
|
+
* server-behind-the-line rule. This is the single check the tactics save (UI + API) and the editor flagging share.
|
|
87
|
+
*/
|
|
88
|
+
function baseConfigViolations(config) {
|
|
89
|
+
return [
|
|
90
|
+
...receiveOverlapViolations(config).map(v => ({ ...v, formation: 'RECEIVE' })),
|
|
91
|
+
...serveLineViolations(config).map(v => ({ ...v, formation: 'SERVE' }))
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
/** True when `config` breaks no RECEIVE overlap rule and no SERVE server-line rule. */
|
|
95
|
+
function isBaseConfigLegal(config) {
|
|
96
|
+
return baseConfigViolations(config).length === 0;
|
|
97
|
+
}
|
|
@@ -1,86 +1,87 @@
|
|
|
1
|
+
import { RotationSystemEnum } from './rotation-system';
|
|
1
2
|
import { slotFunctionAt } from './lineup-function';
|
|
2
3
|
import { RoleEnum } from '../player';
|
|
3
4
|
import { isBackRow } from '../match';
|
|
4
5
|
const COORDS = {
|
|
5
6
|
SERVE: {
|
|
6
|
-
1: { 1: { d: 10
|
|
7
|
-
2: { 1: { d:
|
|
8
|
-
3: { 1: { d:
|
|
9
|
-
4: { 1: { d: 10
|
|
10
|
-
5: { 1: { d:
|
|
11
|
-
6: { 1: { d:
|
|
7
|
+
1: { 1: { d: 10, r: 3.5 }, 2: { d: 0.5, r: -2.5 }, 3: { d: 0.5, r: 0 }, 4: { d: 0.5, r: 2.5 }, 5: { d: 6.5, r: 0 }, 6: { d: 5, r: -2.5 } },
|
|
8
|
+
2: { 1: { d: 9.8, r: -2.7 }, 2: { d: 0.6, r: 2.35 }, 3: { d: 0.6, r: -2.55 }, 4: { d: 0.5, r: -0.2 }, 5: { d: 5, r: 3.25 }, 6: { d: 7.4, r: 0.15 } },
|
|
9
|
+
3: { 1: { d: 9.85, r: 3.3 }, 2: { d: 0.55, r: -0.05 }, 3: { d: 0.6, r: 2.45 }, 4: { d: 0.6, r: -2.7 }, 5: { d: 5.3, r: -2.75 }, 6: { d: 5.3, r: 2.7 } },
|
|
10
|
+
4: { 1: { d: 10, r: 3.5 }, 2: { d: 0.5, r: -2.5 }, 3: { d: 0.5, r: 0 }, 4: { d: 0.5, r: 2.4 }, 5: { d: 6.5, r: 0 }, 6: { d: 5, r: -2.5 } },
|
|
11
|
+
5: { 1: { d: 9.75, r: 3.25 }, 2: { d: 0.65, r: 2.8 }, 3: { d: 0.8, r: -2.85 }, 4: { d: 0.6, r: 0.05 }, 5: { d: 4.75, r: 2.85 }, 6: { d: 6.95, r: 0 } },
|
|
12
|
+
6: { 1: { d: 9.8, r: 3.05 }, 2: { d: 0.45, r: 0.05 }, 3: { d: 0.5, r: 2.45 }, 4: { d: 0.45, r: -2.8 }, 5: { d: 4.6, r: -2.65 }, 6: { d: 4.7, r: 3 } }
|
|
12
13
|
},
|
|
13
14
|
RECEIVE: {
|
|
14
|
-
1: { 1: { d: 6.
|
|
15
|
-
2: { 1: { d:
|
|
16
|
-
3: { 1: { d: 6
|
|
17
|
-
4: { 1: { d: 8.
|
|
18
|
-
5: { 1: { d: 6.
|
|
19
|
-
6: { 1: { d: 6
|
|
15
|
+
1: { 1: { d: 6.5, r: 3.5 }, 2: { d: 6, r: 3 }, 3: { d: 3, r: -3.5 }, 4: { d: 3.5, r: -4 }, 5: { d: 6, r: -3 }, 6: { d: 6.5, r: 0 } },
|
|
16
|
+
2: { 1: { d: 5.65, r: 2.3 }, 2: { d: 0.65, r: 2.1 }, 3: { d: 6, r: -2.3 }, 4: { d: 2.75, r: -3.9 }, 5: { d: 7.85, r: -1.7 }, 6: { d: 6.75, r: 0.1 } },
|
|
17
|
+
3: { 1: { d: 6, r: 3 }, 2: { d: 2.5, r: 3.95 }, 3: { d: 0.75, r: 1 }, 4: { d: 5.55, r: -2.75 }, 5: { d: 6.1, r: 0.1 }, 6: { d: 7.8, r: 1.65 } },
|
|
18
|
+
4: { 1: { d: 8.5, r: 4 }, 2: { d: 6, r: -3 }, 3: { d: 1.25, r: -4 }, 4: { d: 0.75, r: -4.05 }, 5: { d: 6.5, r: 0 }, 6: { d: 6, r: 3 } },
|
|
19
|
+
5: { 1: { d: 6.1, r: 2.6 }, 2: { d: 3.25, r: 3.9 }, 3: { d: 5.8, r: -2.75 }, 4: { d: 0.75, r: -3.85 }, 5: { d: 1.9, r: -1.7 }, 6: { d: 6.75, r: -0.1 } },
|
|
20
|
+
6: { 1: { d: 6, r: 3 }, 2: { d: 2.6, r: 3.85 }, 3: { d: 0.5, r: 0.4 }, 4: { d: 5.9, r: -2.9 }, 5: { d: 6.55, r: 0 }, 6: { d: 1.6, r: 0.9 } }
|
|
20
21
|
},
|
|
21
22
|
DEFENCE: {
|
|
22
|
-
1: { 1: { d: 5
|
|
23
|
-
2: { 1: { d:
|
|
24
|
-
3: { 1: { d:
|
|
25
|
-
4: { 1: { d: 5
|
|
26
|
-
5: { 1: { d:
|
|
27
|
-
6: { 1: { d:
|
|
23
|
+
1: { 1: { d: 5, r: 3 }, 2: { d: 0.5, r: -2.5 }, 3: { d: 0.5, r: 0 }, 4: { d: 0.5, r: 2.5 }, 5: { d: 7, r: 0 }, 6: { d: 5, r: -3 } },
|
|
24
|
+
2: { 1: { d: 4.9, r: -3 }, 2: { d: 0.6, r: 2.65 }, 3: { d: 0.65, r: -3 }, 4: { d: 0.65, r: -0.1 }, 5: { d: 5, r: 3.05 }, 6: { d: 6.75, r: 0.2 } },
|
|
25
|
+
3: { 1: { d: 7, r: 0.05 }, 2: { d: 0.5, r: 0.2 }, 3: { d: 0.6, r: 2.65 }, 4: { d: 0.5, r: -2.7 }, 5: { d: 4.7, r: -2.3 }, 6: { d: 4.85, r: 2.6 } },
|
|
26
|
+
4: { 1: { d: 5, r: 3 }, 2: { d: 0.5, r: -2.5 }, 3: { d: 0.5, r: 0 }, 4: { d: 0.5, r: 2.5 }, 5: { d: 7, r: 0 }, 6: { d: 5, r: -3 } },
|
|
27
|
+
5: { 1: { d: 4.8, r: -3.15 }, 2: { d: 0.6, r: 2.5 }, 3: { d: 0.65, r: -2.85 }, 4: { d: 0.65, r: -0.15 }, 5: { d: 5, r: 2.75 }, 6: { d: 6.75, r: 0.05 } },
|
|
28
|
+
6: { 1: { d: 7.2, r: -0.05 }, 2: { d: 0.45, r: -0.4 }, 3: { d: 0.55, r: 2.45 }, 4: { d: 0.55, r: -3 }, 5: { d: 4.85, r: -2.85 }, 6: { d: 4.8, r: 2.25 } }
|
|
28
29
|
},
|
|
29
30
|
DEF_L: {
|
|
30
|
-
1: { 1: { d: 5
|
|
31
|
-
2: { 1: { d:
|
|
32
|
-
3: { 1: { d:
|
|
33
|
-
4: { 1: { d: 5
|
|
34
|
-
5: { 1: { d:
|
|
35
|
-
6: { 1: { d:
|
|
31
|
+
1: { 1: { d: 5, r: 1.5 }, 2: { d: 0.25, r: -4 }, 3: { d: 0.25, r: -3.25 }, 4: { d: 1.75, r: 1.25 }, 5: { d: 8, r: -0.5 }, 6: { d: 5, r: -4.2 } },
|
|
32
|
+
2: { 1: { d: 4.45, r: -3.95 }, 2: { d: 1.9, r: 1.3 }, 3: { d: 0.4, r: -3.8 }, 4: { d: 0.4, r: -2.9 }, 5: { d: 5.05, r: 2.45 }, 6: { d: 7.6, r: -0.05 } },
|
|
33
|
+
3: { 1: { d: 8.2, r: -0.7 }, 2: { d: 0.4, r: -2.65 }, 3: { d: 2.1, r: 0.8 }, 4: { d: 0.45, r: -3.8 }, 5: { d: 5.1, r: -3.85 }, 6: { d: 5.2, r: 1.8 } },
|
|
34
|
+
4: { 1: { d: 5, r: 1.5 }, 2: { d: 0.25, r: -4 }, 3: { d: 0.25, r: -3.25 }, 4: { d: 1.75, r: 1.25 }, 5: { d: 8, r: -0.5 }, 6: { d: 5, r: -4.2 } },
|
|
35
|
+
5: { 1: { d: 5.05, r: -3.9 }, 2: { d: 2.2, r: 0.65 }, 3: { d: 0.65, r: -3.8 }, 4: { d: 0.65, r: -2.75 }, 5: { d: 4.65, r: 1.1 }, 6: { d: 7.7, r: -0.75 } },
|
|
36
|
+
6: { 1: { d: 7.15, r: 0.25 }, 2: { d: 0.5, r: -2.7 }, 3: { d: 1.8, r: 1.1 }, 4: { d: 0.5, r: -3.8 }, 5: { d: 4.75, r: -3.85 }, 6: { d: 4.95, r: 1.6 } }
|
|
36
37
|
},
|
|
37
38
|
DEF_M: {
|
|
38
|
-
1: { 1: { d: 5
|
|
39
|
-
2: { 1: { d:
|
|
40
|
-
3: { 1: { d:
|
|
41
|
-
4: { 1: { d: 5
|
|
42
|
-
5: { 1: { d:
|
|
43
|
-
6: { 1: { d:
|
|
39
|
+
1: { 1: { d: 5, r: 2.5 }, 2: { d: 1.75, r: -2.5 }, 3: { d: 0.25, r: 0 }, 4: { d: 1.75, r: 2.5 }, 5: { d: 7, r: 0 }, 6: { d: 5, r: -2.5 } },
|
|
40
|
+
2: { 1: { d: 5, r: -2.8 }, 2: { d: 1.85, r: 2.5 }, 3: { d: 1.85, r: -2.4 }, 4: { d: 0.4, r: 0.15 }, 5: { d: 5, r: 2.65 }, 6: { d: 7, r: 0.05 } },
|
|
41
|
+
3: { 1: { d: 7.15, r: 0.1 }, 2: { d: 0.5, r: 0.1 }, 3: { d: 1.95, r: 2.45 }, 4: { d: 1.8, r: -2.55 }, 5: { d: 5.25, r: -2.45 }, 6: { d: 5.2, r: 2.8 } },
|
|
42
|
+
4: { 1: { d: 5, r: 2.5 }, 2: { d: 1.75, r: -2.5 }, 3: { d: 0.25, r: 0 }, 4: { d: 1.75, r: 2.5 }, 5: { d: 7, r: 0 }, 6: { d: 5, r: -2.5 } },
|
|
43
|
+
5: { 1: { d: 4.9, r: -2.35 }, 2: { d: 1.95, r: 2.4 }, 3: { d: 1.85, r: -2.6 }, 4: { d: 0.55, r: -0.2 }, 5: { d: 4.9, r: 2.45 }, 6: { d: 6.7, r: -0.1 } },
|
|
44
|
+
6: { 1: { d: 7.35, r: 0.05 }, 2: { d: 0.6, r: 0.1 }, 3: { d: 2, r: 2.45 }, 4: { d: 2.25, r: -1.95 }, 5: { d: 5.2, r: -2.05 }, 6: { d: 5.3, r: 2.5 } }
|
|
44
45
|
},
|
|
45
46
|
DEF_R: {
|
|
46
|
-
1: { 1: { d: 5
|
|
47
|
-
2: { 1: { d:
|
|
48
|
-
3: { 1: { d:
|
|
49
|
-
4: { 1: { d: 5
|
|
50
|
-
5: { 1: { d:
|
|
51
|
-
6: { 1: { d:
|
|
47
|
+
1: { 1: { d: 5, r: 4.2 }, 2: { d: 1.75, r: -1.25 }, 3: { d: 0.25, r: 3.25 }, 4: { d: 0.25, r: 4 }, 5: { d: 8, r: 0.5 }, 6: { d: 5, r: -1.5 } },
|
|
48
|
+
2: { 1: { d: 4.65, r: -1 }, 2: { d: 0.25, r: 3.85 }, 3: { d: 1.75, r: -1.4 }, 4: { d: 0.3, r: 2.95 }, 5: { d: 4.3, r: 3.95 }, 6: { d: 8.15, r: 0.5 } },
|
|
49
|
+
3: { 1: { d: 8.05, r: 0.4 }, 2: { d: 0.4, r: 2.95 }, 3: { d: 0.4, r: 3.85 }, 4: { d: 2, r: -2 }, 5: { d: 4.65, r: -1.15 }, 6: { d: 4.75, r: 4 } },
|
|
50
|
+
4: { 1: { d: 5, r: 4.2 }, 2: { d: 1.75, r: -1.25 }, 3: { d: 0.25, r: 3.25 }, 4: { d: 0.25, r: 4 }, 5: { d: 8, r: 0.5 }, 6: { d: 5, r: -1.5 } },
|
|
51
|
+
5: { 1: { d: 5.35, r: -2 }, 2: { d: 0.5, r: 3.65 }, 3: { d: 2.1, r: -1.25 }, 4: { d: 0.5, r: 2.6 }, 5: { d: 5.4, r: 3.85 }, 6: { d: 7.75, r: -0.15 } },
|
|
52
|
+
6: { 1: { d: 7.8, r: 0.75 }, 2: { d: 0.45, r: 2.9 }, 3: { d: 0.45, r: 3.95 }, 4: { d: 1.75, r: -0.25 }, 5: { d: 5.15, r: -1.4 }, 6: { d: 4.9, r: 4 } }
|
|
52
53
|
},
|
|
53
54
|
ATTACK: {
|
|
54
|
-
1: { 1: { d: 0.
|
|
55
|
-
2: { 1: { d:
|
|
56
|
-
3: { 1: { d:
|
|
57
|
-
4: { 1: { d: 6.
|
|
58
|
-
5: { 1: { d:
|
|
59
|
-
6: { 1: { d:
|
|
55
|
+
1: { 1: { d: 0.5, r: 1.5 }, 2: { d: 3.75, r: -5 }, 3: { d: 3, r: 0.25 }, 4: { d: 3.75, r: 5 }, 5: { d: 6.5, r: 0 }, 6: { d: 4.5, r: -2.5 } },
|
|
56
|
+
2: { 1: { d: 5.1, r: -2 }, 2: { d: 0.45, r: 1.55 }, 3: { d: 3.6, r: -5.2 }, 4: { d: 2.8, r: 0.2 }, 5: { d: 6.4, r: 5.05 }, 6: { d: 6.55, r: -0.6 } },
|
|
57
|
+
3: { 1: { d: 6.5, r: -0.15 }, 2: { d: 3, r: 0.35 }, 3: { d: 0.5, r: 1.6 }, 4: { d: 2.4, r: -5.15 }, 5: { d: 4.6, r: -2.55 }, 6: { d: 5.4, r: 5.2 } },
|
|
58
|
+
4: { 1: { d: 6.5, r: 4.9 }, 2: { d: 3.75, r: -5 }, 3: { d: 3, r: 0.25 }, 4: { d: 0.5, r: 1.5 }, 5: { d: 6.5, r: 0 }, 6: { d: 4.5, r: -2.5 } },
|
|
59
|
+
5: { 1: { d: 4.65, r: -2.35 }, 2: { d: 3.65, r: 4.8 }, 3: { d: 2.9, r: -5.15 }, 4: { d: 3.05, r: 0.4 }, 5: { d: 0.75, r: 1.7 }, 6: { d: 6.4, r: -0.05 } },
|
|
60
|
+
6: { 1: { d: 6.2, r: -0.4 }, 2: { d: 3, r: 0.2 }, 3: { d: 3.65, r: 5.2 }, 4: { d: 3.55, r: -5.2 }, 5: { d: 4.5, r: -2.45 }, 6: { d: 0.65, r: 1.3 } }
|
|
60
61
|
},
|
|
61
62
|
ATK_L: {
|
|
62
|
-
1: { 1: { d: 0.75, r: 0
|
|
63
|
-
2: { 1: { d:
|
|
64
|
-
3: { 1: { d:
|
|
65
|
-
4: { 1: { d: 3.
|
|
66
|
-
5: { 1: { d:
|
|
67
|
-
6: { 1: { d:
|
|
63
|
+
1: { 1: { d: 0.75, r: 0 }, 2: { d: 0.5, r: -4 }, 3: { d: 1, r: -2.5 }, 4: { d: 3.5, r: 0.75 }, 5: { d: 6.25, r: -0.75 }, 6: { d: 3.5, r: -4 } },
|
|
64
|
+
2: { 1: { d: 3.4, r: -4.05 }, 2: { d: 0.75, r: 0 }, 3: { d: 0.9, r: -4.15 }, 4: { d: 1.8, r: -2.5 }, 5: { d: 3.4, r: 0.5 }, 6: { d: 6.5, r: -1.15 } },
|
|
65
|
+
3: { 1: { d: 6.35, r: -0.1 }, 2: { d: 2.1, r: -2.45 }, 3: { d: 0.9, r: 0 }, 4: { d: 0.8, r: -3.95 }, 5: { d: 4.6, r: -3.75 }, 6: { d: 3.6, r: 1.45 } },
|
|
66
|
+
4: { 1: { d: 3.5, r: 0.75 }, 2: { d: 0.5, r: -4 }, 3: { d: 1, r: -2.5 }, 4: { d: 0.75, r: 0 }, 5: { d: 6.25, r: -0.75 }, 6: { d: 3.5, r: -4 } },
|
|
67
|
+
5: { 1: { d: 4.25, r: -3.85 }, 2: { d: 3.55, r: 0.75 }, 3: { d: 1, r: -4.1 }, 4: { d: 2.05, r: -2.65 }, 5: { d: 0.85, r: -0.15 }, 6: { d: 6, r: -0.8 } },
|
|
68
|
+
6: { 1: { d: 5.9, r: -1 }, 2: { d: 1.05, r: -2.5 }, 3: { d: 3.45, r: 0.9 }, 4: { d: 0.7, r: -3.9 }, 5: { d: 3.4, r: -4.05 }, 6: { d: 0.75, r: -0.2 } }
|
|
68
69
|
},
|
|
69
70
|
ATK_M: {
|
|
70
|
-
1: { 1: { d: 0.75, r: 1.25 }, 2: { d: 1.25, r: -2
|
|
71
|
-
2: { 1: { d:
|
|
72
|
-
3: { 1: { d:
|
|
73
|
-
4: { 1: { d: 2.25, r: 2.
|
|
74
|
-
5: { 1: { d:
|
|
75
|
-
6: { 1: { d:
|
|
71
|
+
1: { 1: { d: 0.75, r: 1.25 }, 2: { d: 1.25, r: -2 }, 3: { d: 0.75, r: 0.5 }, 4: { d: 2.25, r: 2.6 }, 5: { d: 6.5, r: 1.5 }, 6: { d: 4, r: -1.5 } },
|
|
72
|
+
2: { 1: { d: 4.5, r: -2.2 }, 2: { d: 0.7, r: 1.25 }, 3: { d: 1.8, r: -2.45 }, 4: { d: 0.9, r: 0.05 }, 5: { d: 2.75, r: 3.05 }, 6: { d: 5.75, r: 0 } },
|
|
73
|
+
3: { 1: { d: 6.55, r: 1.15 }, 2: { d: 0.9, r: 0.3 }, 3: { d: 0.85, r: 1.45 }, 4: { d: 1.7, r: -2.7 }, 5: { d: 3.95, r: -1.75 }, 6: { d: 2.25, r: 3.2 } },
|
|
74
|
+
4: { 1: { d: 2.25, r: 2.6 }, 2: { d: 1.25, r: -2 }, 3: { d: 0.75, r: 0.5 }, 4: { d: 0.75, r: 1.25 }, 5: { d: 6.5, r: 1.5 }, 6: { d: 4, r: -1.5 } },
|
|
75
|
+
5: { 1: { d: 4.35, r: -1.5 }, 2: { d: 2.25, r: 2.85 }, 3: { d: 1.9, r: -2.55 }, 4: { d: 0.8, r: 0.35 }, 5: { d: 0.6, r: 1.45 }, 6: { d: 5.55, r: 1.45 } },
|
|
76
|
+
6: { 1: { d: 5.2, r: 1.1 }, 2: { d: 0.8, r: 0.35 }, 3: { d: 2.4, r: 3 }, 4: { d: 1.8, r: -2.15 }, 5: { d: 4.5, r: -1.7 }, 6: { d: 0.8, r: 1.35 } }
|
|
76
77
|
},
|
|
77
78
|
ATK_R: {
|
|
78
|
-
1: { 1: { d: 1.75, r: 2.
|
|
79
|
-
2: { 1: { d:
|
|
80
|
-
3: { 1: { d: 5.
|
|
81
|
-
4: { 1: { d: 2.25, r: 4
|
|
82
|
-
5: { 1: { d:
|
|
83
|
-
6: { 1: { d: 5.
|
|
79
|
+
1: { 1: { d: 1.75, r: 2.5 }, 2: { d: 1.5, r: -1.75 }, 3: { d: 0.75, r: 1.75 }, 4: { d: 0.5, r: 4 }, 5: { d: 5, r: 3.25 }, 6: { d: 5.75, r: -2 } },
|
|
80
|
+
2: { 1: { d: 4.65, r: -0.8 }, 2: { d: 0.75, r: 1.75 }, 3: { d: 1.85, r: -1.75 }, 4: { d: 1.7, r: 2.2 }, 5: { d: 2.15, r: 4.25 }, 6: { d: 6.25, r: 2 } },
|
|
81
|
+
3: { 1: { d: 5.1, r: 3.15 }, 2: { d: 1.85, r: 2.6 }, 3: { d: 0.8, r: 1.75 }, 4: { d: 2.15, r: -1.7 }, 5: { d: 4.9, r: -1.25 }, 6: { d: 1.9, r: 4.15 } },
|
|
82
|
+
4: { 1: { d: 2.25, r: 4 }, 2: { d: 2.25, r: -1.75 }, 3: { d: 0.75, r: 1.5 }, 4: { d: 1.5, r: 2.25 }, 5: { d: 6, r: 2.25 }, 6: { d: 5, r: -0.75 } },
|
|
83
|
+
5: { 1: { d: 5.95, r: -2 }, 2: { d: 0.9, r: 3.7 }, 3: { d: 2.2, r: -1.6 }, 4: { d: 2, r: 2.35 }, 5: { d: 0.9, r: 1.15 }, 6: { d: 6, r: 1.9 } },
|
|
84
|
+
6: { 1: { d: 5.35, r: 2.35 }, 2: { d: 2.05, r: 2.1 }, 3: { d: 0.8, r: 4 }, 4: { d: 2.1, r: -1.95 }, 5: { d: 4.9, r: -1.4 }, 6: { d: 0.4, r: 1.3 } }
|
|
84
85
|
}
|
|
85
86
|
};
|
|
86
87
|
// The default coordinate table as a BaseConfig.coords (jsonb string keys). Shared, readonly; materialized (and so
|
|
@@ -97,36 +98,47 @@ const DEFAULT_COORDS = (() => {
|
|
|
97
98
|
}
|
|
98
99
|
return out;
|
|
99
100
|
})();
|
|
100
|
-
// The owner's
|
|
101
|
+
// The owner's corrected per-point-of-attack block map for the 5-1 (exported 2026-08-09), keyed
|
|
101
102
|
// [DEF_L|DEF_M|DEF_R][rotation][zone] -> canBlock. `false` = that front-row zone sits OUT of the block for an attack
|
|
102
|
-
// from that side; `true` = reads/joins the wall. Only front-row zones
|
|
103
|
-
// as DEFAULT_COORDS.
|
|
103
|
+
// from that side; `true` = reads/joins the wall. Only the front-row zones in play for the rotation are tagged. Same
|
|
104
|
+
// rotation convention as DEFAULT_COORDS.
|
|
104
105
|
const DEFAULT_BLOCKING = {
|
|
105
106
|
DEF_L: {
|
|
106
107
|
1: { 2: true, 3: true, 4: false },
|
|
107
|
-
2: { 2:
|
|
108
|
-
3: {
|
|
108
|
+
2: { 2: false, 4: true },
|
|
109
|
+
3: { 3: false, 4: true },
|
|
109
110
|
4: { 2: true, 3: true, 4: false },
|
|
110
|
-
5: { 2:
|
|
111
|
-
6: {
|
|
111
|
+
5: { 2: false, 4: true },
|
|
112
|
+
6: { 3: false, 4: true }
|
|
112
113
|
},
|
|
113
114
|
DEF_M: {
|
|
114
115
|
1: { 2: false, 3: true, 4: false },
|
|
115
|
-
2: { 2:
|
|
116
|
-
3: {
|
|
116
|
+
2: { 2: false, 3: false },
|
|
117
|
+
3: { 3: false, 4: false },
|
|
117
118
|
4: { 2: false, 3: true, 4: false },
|
|
118
|
-
5: { 2:
|
|
119
|
-
6: {
|
|
119
|
+
5: { 2: false, 3: false },
|
|
120
|
+
6: { 3: false, 4: false }
|
|
120
121
|
},
|
|
121
122
|
DEF_R: {
|
|
122
123
|
1: { 2: false, 3: true, 4: true },
|
|
123
|
-
2: { 2: true, 3:
|
|
124
|
-
3: { 2: true,
|
|
124
|
+
2: { 2: true, 3: false },
|
|
125
|
+
3: { 2: true, 4: false },
|
|
125
126
|
4: { 2: false, 3: true, 4: true },
|
|
126
|
-
5: { 2: true, 3:
|
|
127
|
-
6: { 2: true,
|
|
127
|
+
5: { 2: true, 3: false },
|
|
128
|
+
6: { 2: true, 4: false }
|
|
128
129
|
}
|
|
129
130
|
};
|
|
131
|
+
// The owner's corrected 5-1 serve-receive participation map (exported 2026-08-09). The 5-1 uses this exact map; the
|
|
132
|
+
// other systems derive their 3-passer map from slot functions (defaultReceiveMap) since their receiving personnel
|
|
133
|
+
// differ. Keyed [rotation][zone] -> passes.
|
|
134
|
+
const DEFAULT_5_1_RECEIVE = {
|
|
135
|
+
1: { 1: false, 2: true, 3: false, 4: false, 5: true, 6: true },
|
|
136
|
+
2: { 1: true, 2: false, 3: true, 4: false, 5: false, 6: true },
|
|
137
|
+
3: { 1: true, 2: false, 3: false, 4: true, 5: true, 6: false },
|
|
138
|
+
4: { 1: false, 2: true, 3: false, 4: false, 5: true, 6: true },
|
|
139
|
+
5: { 1: true, 2: false, 3: true, 4: false, 5: false, 6: true },
|
|
140
|
+
6: { 1: true, 2: false, 3: false, 4: true, 5: true, 6: false }
|
|
141
|
+
};
|
|
130
142
|
// Rotation index -> the setter's rotational zone (inverse of SETTER_ZONE_TO_ROTATION {1:1,6:2,5:3,4:4,3:5,2:6}).
|
|
131
143
|
const ROTATION_TO_SETTER_ZONE = { 1: 1, 2: 6, 3: 5, 4: 4, 5: 3, 6: 2 };
|
|
132
144
|
// The default serve-receive participation map: the standard 3-passer formation. A rotational slot passes iff its
|
|
@@ -147,8 +159,9 @@ export function defaultReceiveMap(system) {
|
|
|
147
159
|
return receive;
|
|
148
160
|
}
|
|
149
161
|
// The default base config a team of the given system starts with. Every team always has one (materialized on team
|
|
150
|
-
// creation and by the backfill migration)
|
|
151
|
-
// receive map
|
|
162
|
+
// creation and by the backfill migration). Every system reuses the corrected 5-1 coordinate table and block map; the
|
|
163
|
+
// 5-1 uses the owner's exported receive map, the other systems derive their receive map per system.
|
|
152
164
|
export function defaultBaseConfig(system) {
|
|
153
|
-
|
|
165
|
+
const receive = system === RotationSystemEnum.FIVE_ONE ? DEFAULT_5_1_RECEIVE : defaultReceiveMap(system);
|
|
166
|
+
return { coords: DEFAULT_COORDS, receive, blocking: DEFAULT_BLOCKING };
|
|
154
167
|
}
|
|
@@ -4,6 +4,7 @@ export * from './formation';
|
|
|
4
4
|
export * from './tactics';
|
|
5
5
|
export * from './base-config';
|
|
6
6
|
export * from './default-base-config';
|
|
7
|
+
export * from './receive-overlap';
|
|
7
8
|
export * from './team-name';
|
|
8
9
|
export * from './energy-band';
|
|
9
10
|
export * from './pinch-condition';
|
|
@@ -4,6 +4,7 @@ export * from './formation';
|
|
|
4
4
|
export * from './tactics';
|
|
5
5
|
export * from './base-config';
|
|
6
6
|
export * from './default-base-config';
|
|
7
|
+
export * from './receive-overlap';
|
|
7
8
|
export * from './team-name';
|
|
8
9
|
export * from './energy-band';
|
|
9
10
|
export * from './pinch-condition';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { BaseConfig } from './base-config';
|
|
2
|
+
export interface ReceiveOverlapViolation {
|
|
3
|
+
/** Rotation (1..6) that has at least one violation. */
|
|
4
|
+
readonly rotation: number;
|
|
5
|
+
/** The rotational zones (1..6) involved in a violation, to flag in the editor. */
|
|
6
|
+
readonly zones: number[];
|
|
7
|
+
/** Human-readable violation messages for that rotation. */
|
|
8
|
+
readonly messages: string[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Returns every RECEIVE rotation that breaks the overlap rule (empty if the whole receive formation is legal).
|
|
12
|
+
* A missing RECEIVE map or a missing zone is skipped rather than flagged, so partial/legacy configs never throw.
|
|
13
|
+
*/
|
|
14
|
+
export declare function receiveOverlapViolations(config: BaseConfig): ReceiveOverlapViolation[];
|
|
15
|
+
/** True when the RECEIVE formation of `config` respects the overlap rule in every rotation. */
|
|
16
|
+
export declare function isReceiveOverlapLegal(config: BaseConfig): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Returns every SERVE rotation whose server (zone 1) is NOT behind the end line (owner 2026-08-10: on Serve, only
|
|
19
|
+
* the server is constrained; the rest of the serving formation is free). A missing SERVE map or zone-1 coord is
|
|
20
|
+
* skipped rather than flagged, so partial/legacy configs never throw.
|
|
21
|
+
*/
|
|
22
|
+
export declare function serveLineViolations(config: BaseConfig): ReceiveOverlapViolation[];
|
|
23
|
+
/** A base-config rule violation, tagged with the formation it belongs to so the editor/API can point at it. */
|
|
24
|
+
export interface FormationViolation extends ReceiveOverlapViolation {
|
|
25
|
+
readonly formation: 'RECEIVE' | 'SERVE';
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Every base-config rule violation across the constrained formations: the RECEIVE overlap rule and the SERVE
|
|
29
|
+
* server-behind-the-line rule. This is the single check the tactics save (UI + API) and the editor flagging share.
|
|
30
|
+
*/
|
|
31
|
+
export declare function baseConfigViolations(config: BaseConfig): FormationViolation[];
|
|
32
|
+
/** True when `config` breaks no RECEIVE overlap rule and no SERVE server-line rule. */
|
|
33
|
+
export declare function isBaseConfigLegal(config: BaseConfig): boolean;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns every RECEIVE rotation that breaks the overlap rule (empty if the whole receive formation is legal).
|
|
3
|
+
* A missing RECEIVE map or a missing zone is skipped rather than flagged, so partial/legacy configs never throw.
|
|
4
|
+
*/
|
|
5
|
+
export function receiveOverlapViolations(config) {
|
|
6
|
+
const rc = config.coords?.RECEIVE;
|
|
7
|
+
if (rc == null)
|
|
8
|
+
return [];
|
|
9
|
+
const out = [];
|
|
10
|
+
for (let rot = 1; rot <= 6; rot++) {
|
|
11
|
+
const row = rc[String(rot)];
|
|
12
|
+
if (row == null)
|
|
13
|
+
continue;
|
|
14
|
+
const at = (zone) => row[String(zone)];
|
|
15
|
+
const bad = new Set();
|
|
16
|
+
const messages = [];
|
|
17
|
+
const lateral = (left, right, ln, rn) => {
|
|
18
|
+
const a = at(left);
|
|
19
|
+
const b = at(right);
|
|
20
|
+
if (a == null || b == null)
|
|
21
|
+
return;
|
|
22
|
+
if (a.r >= b.r) {
|
|
23
|
+
bad.add(left);
|
|
24
|
+
bad.add(right);
|
|
25
|
+
messages.push(`${ln} must be left of ${rn}`);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const depth = (front, back, fn, bn) => {
|
|
29
|
+
const a = at(front);
|
|
30
|
+
const b = at(back);
|
|
31
|
+
if (a == null || b == null)
|
|
32
|
+
return;
|
|
33
|
+
if (a.d >= b.d) {
|
|
34
|
+
bad.add(front);
|
|
35
|
+
bad.add(back);
|
|
36
|
+
messages.push(`${fn} must be in front of ${bn}`);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
lateral(4, 3, 'left-front', 'middle-front');
|
|
40
|
+
lateral(3, 2, 'middle-front', 'right-front');
|
|
41
|
+
lateral(5, 6, 'left-back', 'middle-back');
|
|
42
|
+
lateral(6, 1, 'middle-back', 'right-back');
|
|
43
|
+
depth(2, 1, 'right-front', 'right-back');
|
|
44
|
+
depth(3, 6, 'middle-front', 'middle-back');
|
|
45
|
+
depth(4, 5, 'left-front', 'left-back');
|
|
46
|
+
if (bad.size > 0)
|
|
47
|
+
out.push({ rotation: rot, zones: [...bad].sort((a, b) => a - b), messages });
|
|
48
|
+
}
|
|
49
|
+
return out;
|
|
50
|
+
}
|
|
51
|
+
/** True when the RECEIVE formation of `config` respects the overlap rule in every rotation. */
|
|
52
|
+
export function isReceiveOverlapLegal(config) {
|
|
53
|
+
return receiveOverlapViolations(config).length === 0;
|
|
54
|
+
}
|
|
55
|
+
// The end line sits 9 m off the net (the FIVB court depth; matches the court editor's END_LINE). A server must
|
|
56
|
+
// contact the ball from BEHIND it, so on the SERVE formation the server (rotational zone 1) must have d >= this.
|
|
57
|
+
const END_LINE_DEPTH = 9;
|
|
58
|
+
/**
|
|
59
|
+
* Returns every SERVE rotation whose server (zone 1) is NOT behind the end line (owner 2026-08-10: on Serve, only
|
|
60
|
+
* the server is constrained; the rest of the serving formation is free). A missing SERVE map or zone-1 coord is
|
|
61
|
+
* skipped rather than flagged, so partial/legacy configs never throw.
|
|
62
|
+
*/
|
|
63
|
+
export function serveLineViolations(config) {
|
|
64
|
+
const sc = config.coords?.SERVE;
|
|
65
|
+
if (sc == null)
|
|
66
|
+
return [];
|
|
67
|
+
const out = [];
|
|
68
|
+
for (let rot = 1; rot <= 6; rot++) {
|
|
69
|
+
const server = sc[String(rot)]?.['1'];
|
|
70
|
+
if (server == null)
|
|
71
|
+
continue;
|
|
72
|
+
if (server.d < END_LINE_DEPTH)
|
|
73
|
+
out.push({ rotation: rot, zones: [1], messages: ['server must be behind the end line'] });
|
|
74
|
+
}
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Every base-config rule violation across the constrained formations: the RECEIVE overlap rule and the SERVE
|
|
79
|
+
* server-behind-the-line rule. This is the single check the tactics save (UI + API) and the editor flagging share.
|
|
80
|
+
*/
|
|
81
|
+
export function baseConfigViolations(config) {
|
|
82
|
+
return [
|
|
83
|
+
...receiveOverlapViolations(config).map(v => ({ ...v, formation: 'RECEIVE' })),
|
|
84
|
+
...serveLineViolations(config).map(v => ({ ...v, formation: 'SERVE' }))
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
/** True when `config` breaks no RECEIVE overlap rule and no SERVE server-line rule. */
|
|
88
|
+
export function isBaseConfigLegal(config) {
|
|
89
|
+
return baseConfigViolations(config).length === 0;
|
|
90
|
+
}
|