redscript-mc 2.2.1 → 2.4.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/CHANGELOG.md +31 -0
- package/README.md +18 -2
- package/dist/src/__tests__/array-dynamic.test.d.ts +12 -0
- package/dist/src/__tests__/array-dynamic.test.js +131 -0
- package/dist/src/__tests__/array-write.test.d.ts +11 -0
- package/dist/src/__tests__/array-write.test.js +149 -0
- package/dist/src/__tests__/tuner/engine.test.d.ts +4 -0
- package/dist/src/__tests__/tuner/engine.test.js +232 -0
- package/dist/src/ast/types.d.ts +7 -0
- package/dist/src/emit/modules.js +5 -0
- package/dist/src/hir/lower.js +29 -0
- package/dist/src/hir/monomorphize.js +2 -0
- package/dist/src/hir/types.d.ts +9 -2
- package/dist/src/lir/lower.js +131 -0
- package/dist/src/mir/lower.js +73 -3
- package/dist/src/mir/macro.js +5 -0
- package/dist/src/mir/types.d.ts +12 -0
- package/dist/src/mir/verify.js +7 -0
- package/dist/src/optimizer/copy_prop.js +5 -0
- package/dist/src/optimizer/coroutine.js +12 -0
- package/dist/src/optimizer/dce.js +9 -0
- package/dist/src/optimizer/unroll.js +3 -0
- package/dist/src/parser/index.js +5 -0
- package/dist/src/tuner/adapters/ln-polynomial.d.ts +23 -0
- package/dist/src/tuner/adapters/ln-polynomial.js +142 -0
- package/dist/src/tuner/adapters/sqrt-newton.d.ts +28 -0
- package/dist/src/tuner/adapters/sqrt-newton.js +125 -0
- package/dist/src/tuner/cli.d.ts +5 -0
- package/dist/src/tuner/cli.js +168 -0
- package/dist/src/tuner/engine.d.ts +17 -0
- package/dist/src/tuner/engine.js +215 -0
- package/dist/src/tuner/metrics.d.ts +15 -0
- package/dist/src/tuner/metrics.js +51 -0
- package/dist/src/tuner/simulator.d.ts +35 -0
- package/dist/src/tuner/simulator.js +78 -0
- package/dist/src/tuner/types.d.ts +32 -0
- package/dist/src/tuner/types.js +6 -0
- package/dist/src/typechecker/index.js +5 -0
- package/docs/STDLIB_ROADMAP.md +142 -0
- package/editors/vscode/package-lock.json +3 -3
- package/editors/vscode/package.json +1 -1
- package/package.json +1 -1
- package/src/__tests__/array-dynamic.test.ts +147 -0
- package/src/__tests__/array-write.test.ts +169 -0
- package/src/__tests__/tuner/engine.test.ts +260 -0
- package/src/ast/types.ts +1 -0
- package/src/emit/modules.ts +5 -0
- package/src/hir/lower.ts +30 -0
- package/src/hir/monomorphize.ts +2 -0
- package/src/hir/types.ts +3 -1
- package/src/lir/lower.ts +151 -0
- package/src/mir/lower.ts +75 -3
- package/src/mir/macro.ts +5 -0
- package/src/mir/types.ts +2 -0
- package/src/mir/verify.ts +7 -0
- package/src/optimizer/copy_prop.ts +5 -0
- package/src/optimizer/coroutine.ts +9 -0
- package/src/optimizer/dce.ts +6 -0
- package/src/optimizer/unroll.ts +3 -0
- package/src/parser/index.ts +9 -0
- package/src/stdlib/bigint.mcrs +155 -192
- package/src/stdlib/bits.mcrs +158 -0
- package/src/stdlib/color.mcrs +160 -0
- package/src/stdlib/geometry.mcrs +124 -0
- package/src/stdlib/list.mcrs +96 -0
- package/src/stdlib/math.mcrs +227 -0
- package/src/stdlib/math_hp.mcrs +65 -0
- package/src/stdlib/random.mcrs +67 -0
- package/src/stdlib/signal.mcrs +112 -0
- package/src/stdlib/timer.mcrs +32 -0
- package/src/stdlib/vec.mcrs +27 -0
- package/src/tuner/adapters/ln-polynomial.ts +147 -0
- package/src/tuner/adapters/sqrt-newton.ts +135 -0
- package/src/tuner/cli.ts +158 -0
- package/src/tuner/engine.ts +272 -0
- package/src/tuner/metrics.ts +66 -0
- package/src/tuner/simulator.ts +69 -0
- package/src/tuner/types.ts +44 -0
- package/src/typechecker/index.ts +6 -0
- package/docs/ARCHITECTURE.zh.md +0 -1088
- package/docs/COMPILATION_STATS.md +0 -142
- package/docs/IMPLEMENTATION_GUIDE.md +0 -512
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// color.mcrs — Color utilities for RedScript datapacks.
|
|
2
|
+
//
|
|
3
|
+
// All RGB values: 0-255
|
|
4
|
+
// All HSL values: H 0-360, S 0-100, L 0-100
|
|
5
|
+
// Packed int format: 0xRRGGBB (R in bits 16-23, G in bits 8-15, B in bits 0-7)
|
|
6
|
+
// packed = R*65536 + G*256 + B
|
|
7
|
+
//
|
|
8
|
+
// Note: No native bitwise ops in MC scoreboard — packing/unpacking uses multiply/divide.
|
|
9
|
+
|
|
10
|
+
module library;
|
|
11
|
+
|
|
12
|
+
// ─── Pack / Unpack ────────────────────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
// rgb_pack(r, g, b): pack RGB into a single int (0xRRGGBB)
|
|
15
|
+
fn rgb_pack(r: int, g: int, b: int): int {
|
|
16
|
+
return r * 65536 + g * 256 + b;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// rgb_r(packed): extract red component
|
|
20
|
+
fn rgb_r(packed: int): int {
|
|
21
|
+
return packed / 65536 % 256;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// rgb_g(packed): extract green component
|
|
25
|
+
fn rgb_g(packed: int): int {
|
|
26
|
+
return packed / 256 % 256;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// rgb_b(packed): extract blue component
|
|
30
|
+
fn rgb_b(packed: int): int {
|
|
31
|
+
return packed % 256;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ─── Blending ─────────────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
// rgb_lerp(a, b, t): linear blend between two packed colors, t ∈ [0, 1000]
|
|
37
|
+
// t=0 → a, t=1000 → b
|
|
38
|
+
fn rgb_lerp(a: int, b: int, t: int): int {
|
|
39
|
+
let ra: int = a / 65536 % 256;
|
|
40
|
+
let ga: int = a / 256 % 256;
|
|
41
|
+
let ba_: int = a % 256;
|
|
42
|
+
let rb: int = b / 65536 % 256;
|
|
43
|
+
let gb: int = b / 256 % 256;
|
|
44
|
+
let bb_: int = b % 256;
|
|
45
|
+
let r: int = ra + (rb - ra) * t / 1000;
|
|
46
|
+
let g: int = ga + (gb - ga) * t / 1000;
|
|
47
|
+
let bv: int = ba_ + (bb_ - ba_) * t / 1000;
|
|
48
|
+
return r * 65536 + g * 256 + bv;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ─── HSL ↔ RGB ────────────────────────────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
// hsl_to_rgb_r/g/b: convert HSL to individual RGB components
|
|
54
|
+
// H: 0-360, S: 0-100, L: 0-100, returns 0-255
|
|
55
|
+
fn _hsl_chroma_x(h: int, c: int): int {
|
|
56
|
+
// X = C * (1 - |H/60 mod 2 - 1|)
|
|
57
|
+
let sector: int = h / 60;
|
|
58
|
+
let rem: int = h % 120;
|
|
59
|
+
if (rem > 60) { rem = 120 - rem; }
|
|
60
|
+
return c * rem / 60;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
fn hsl_to_r(h: int, s: int, l: int): int {
|
|
64
|
+
let c: int = s * (1000 - (2 * l * 10 - 1000)) / 1000;
|
|
65
|
+
if (c < 0) { c = 0 - c; }
|
|
66
|
+
c = c / 10;
|
|
67
|
+
let x: int = _hsl_chroma_x(h, c);
|
|
68
|
+
let m: int = l * 255 / 100 - c / 2;
|
|
69
|
+
let sector: int = h / 60;
|
|
70
|
+
if (sector == 0) { return (c + m); }
|
|
71
|
+
if (sector == 1) { return (x + m); }
|
|
72
|
+
if (sector == 2) { return m; }
|
|
73
|
+
if (sector == 3) { return m; }
|
|
74
|
+
if (sector == 4) { return (x + m); }
|
|
75
|
+
return (c + m);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
fn hsl_to_g(h: int, s: int, l: int): int {
|
|
79
|
+
let c: int = s * (1000 - (2 * l * 10 - 1000)) / 1000;
|
|
80
|
+
if (c < 0) { c = 0 - c; }
|
|
81
|
+
c = c / 10;
|
|
82
|
+
let x: int = _hsl_chroma_x(h, c);
|
|
83
|
+
let m: int = l * 255 / 100 - c / 2;
|
|
84
|
+
let sector: int = h / 60;
|
|
85
|
+
if (sector == 0) { return (x + m); }
|
|
86
|
+
if (sector == 1) { return (c + m); }
|
|
87
|
+
if (sector == 2) { return (c + m); }
|
|
88
|
+
if (sector == 3) { return (x + m); }
|
|
89
|
+
if (sector == 4) { return m; }
|
|
90
|
+
return m;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
fn hsl_to_b(h: int, s: int, l: int): int {
|
|
94
|
+
let c: int = s * (1000 - (2 * l * 10 - 1000)) / 1000;
|
|
95
|
+
if (c < 0) { c = 0 - c; }
|
|
96
|
+
c = c / 10;
|
|
97
|
+
let x: int = _hsl_chroma_x(h, c);
|
|
98
|
+
let m: int = l * 255 / 100 - c / 2;
|
|
99
|
+
let sector: int = h / 60;
|
|
100
|
+
if (sector == 0) { return m; }
|
|
101
|
+
if (sector == 1) { return m; }
|
|
102
|
+
if (sector == 2) { return (x + m); }
|
|
103
|
+
if (sector == 3) { return (c + m); }
|
|
104
|
+
if (sector == 4) { return (c + m); }
|
|
105
|
+
return (x + m);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// hsl_to_packed(h, s, l): HSL → packed RGB int
|
|
109
|
+
fn hsl_to_packed(h: int, s: int, l: int): int {
|
|
110
|
+
return rgb_pack(hsl_to_r(h, s, l), hsl_to_g(h, s, l), hsl_to_b(h, s, l));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ─── RGB → HSL ────────────────────────────────────────────────────────────────
|
|
114
|
+
|
|
115
|
+
// rgb_to_l(r, g, b): lightness 0-100
|
|
116
|
+
fn rgb_to_l(r: int, g: int, b: int): int {
|
|
117
|
+
let mx: int = r;
|
|
118
|
+
if (g > mx) { mx = g; }
|
|
119
|
+
if (b > mx) { mx = b; }
|
|
120
|
+
let mn: int = r;
|
|
121
|
+
if (g < mn) { mn = g; }
|
|
122
|
+
if (b < mn) { mn = b; }
|
|
123
|
+
return (mx + mn) * 100 / 510;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// rgb_to_s(r, g, b): saturation 0-100
|
|
127
|
+
fn rgb_to_s(r: int, g: int, b: int): int {
|
|
128
|
+
let mx: int = r;
|
|
129
|
+
if (g > mx) { mx = g; }
|
|
130
|
+
if (b > mx) { mx = b; }
|
|
131
|
+
let mn: int = r;
|
|
132
|
+
if (g < mn) { mn = g; }
|
|
133
|
+
if (b < mn) { mn = b; }
|
|
134
|
+
let c: int = mx - mn;
|
|
135
|
+
if (c == 0) { return 0; }
|
|
136
|
+
let l: int = (mx + mn) * 100 / 510;
|
|
137
|
+
if (l <= 50) { return c * 100 / (mx + mn); }
|
|
138
|
+
return c * 100 / (510 - mx - mn);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// rgb_to_h(r, g, b): hue 0-360
|
|
142
|
+
fn rgb_to_h(r: int, g: int, b: int): int {
|
|
143
|
+
let mx: int = r;
|
|
144
|
+
if (g > mx) { mx = g; }
|
|
145
|
+
if (b > mx) { mx = b; }
|
|
146
|
+
let mn: int = r;
|
|
147
|
+
if (g < mn) { mn = g; }
|
|
148
|
+
if (b < mn) { mn = b; }
|
|
149
|
+
let c: int = mx - mn;
|
|
150
|
+
if (c == 0) { return 0; }
|
|
151
|
+
if (mx == r) {
|
|
152
|
+
let h: int = 60 * (g - b) / c;
|
|
153
|
+
if (h < 0) { h = h + 360; }
|
|
154
|
+
return h;
|
|
155
|
+
}
|
|
156
|
+
if (mx == g) {
|
|
157
|
+
return 60 * (b - r) / c + 120;
|
|
158
|
+
}
|
|
159
|
+
return 60 * (r - g) / c + 240;
|
|
160
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
// geometry.mcrs — 3D geometry helpers for Minecraft datapacks.
|
|
2
|
+
//
|
|
3
|
+
// Fixed-point convention: coordinates × 100 (so 1.0 block = 100 units)
|
|
4
|
+
// Angles in degrees × 10000
|
|
5
|
+
//
|
|
6
|
+
// Requires: import "stdlib/math" (for sqrt_fx, sin_fixed, cos_fixed, abs)
|
|
7
|
+
|
|
8
|
+
module library;
|
|
9
|
+
|
|
10
|
+
// ─── Midpoint ─────────────────────────────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
// midpoint_x/y/z(a, b): integer midpoint of two coordinates
|
|
13
|
+
fn midpoint(a: int, b: int): int {
|
|
14
|
+
return (a + b) / 2;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// ─── Bounding box ─────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
// aabb_contains(px, py, pz, minx, miny, minz, maxx, maxy, maxz):
|
|
20
|
+
// Returns 1 if point (px,py,pz) is inside axis-aligned bounding box, 0 otherwise.
|
|
21
|
+
fn aabb_contains(px: int, py: int, pz: int,
|
|
22
|
+
minx: int, miny: int, minz: int,
|
|
23
|
+
maxx: int, maxy: int, maxz: int): int {
|
|
24
|
+
if (px < minx) { return 0; }
|
|
25
|
+
if (px > maxx) { return 0; }
|
|
26
|
+
if (py < miny) { return 0; }
|
|
27
|
+
if (py > maxy) { return 0; }
|
|
28
|
+
if (pz < minz) { return 0; }
|
|
29
|
+
if (pz > maxz) { return 0; }
|
|
30
|
+
return 1;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// sphere_contains(px, py, pz, cx, cy, cz, r):
|
|
34
|
+
// Returns 1 if point is inside sphere (all coords in same unit, r is radius).
|
|
35
|
+
// Avoids sqrt by comparing squared distances.
|
|
36
|
+
fn sphere_contains(px: int, py: int, pz: int,
|
|
37
|
+
cx: int, cy: int, cz: int,
|
|
38
|
+
r: int): int {
|
|
39
|
+
let dx: int = px - cx;
|
|
40
|
+
let dy: int = py - cy;
|
|
41
|
+
let dz: int = pz - cz;
|
|
42
|
+
let dist_sq: int = dx * dx + dy * dy + dz * dz;
|
|
43
|
+
if (dist_sq <= r * r) { return 1; }
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// cylinder_contains(px, pz, cx, cz, r):
|
|
48
|
+
// Returns 1 if point is inside vertical cylinder (ignores Y). 2D circle check.
|
|
49
|
+
fn cylinder_contains(px: int, pz: int, cx: int, cz: int, r: int): int {
|
|
50
|
+
let dx: int = px - cx;
|
|
51
|
+
let dz: int = pz - cz;
|
|
52
|
+
if (dx * dx + dz * dz <= r * r) { return 1; }
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ─── Parabola (projectile) ───────────────────────────────────────────────────
|
|
57
|
+
//
|
|
58
|
+
// MC projectile physics: velocity in blocks/tick, gravity ≈ 0.05 blocks/tick²
|
|
59
|
+
// For a simplified fixed-point model:
|
|
60
|
+
// pos(t) = init_pos + init_vel * t - gravity_half * t²
|
|
61
|
+
//
|
|
62
|
+
// All values × 100 (1 block = 100 units), time in ticks.
|
|
63
|
+
|
|
64
|
+
// parabola_y(y0, vy0, t): Y position at tick t.
|
|
65
|
+
// y0: initial Y × 100, vy0: initial Y velocity × 100 (blocks/tick × 100)
|
|
66
|
+
// gravity: 5 units/tick² (= 0.05 blocks/tick² × 100)
|
|
67
|
+
fn parabola_y(y0: int, vy0: int, t: int): int {
|
|
68
|
+
return y0 + vy0 * t - 5 * t * t / 2;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// parabola_x(x0, vx0, t): horizontal X position at tick t (no drag, constant).
|
|
72
|
+
fn parabola_x(x0: int, vx0: int, t: int): int {
|
|
73
|
+
return x0 + vx0 * t;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// parabola_land_t(vy0): approximate tick when projectile returns to Y=0.
|
|
77
|
+
// t_land ≈ 2 * vy0 / gravity = 2 * vy0 / 5 (in fixed-point units)
|
|
78
|
+
fn parabola_land_t(vy0: int): int {
|
|
79
|
+
return 2 * vy0 / 5;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ─── Grid / tile math ────────────────────────────────────────────────────────
|
|
83
|
+
|
|
84
|
+
// tile_of(coord): which tile a coordinate belongs to (floor division).
|
|
85
|
+
// tile_of(250, 100) = 2 (block 2 when tile size = 100)
|
|
86
|
+
fn tile_of(coord: int, tile_size: int): int {
|
|
87
|
+
if (coord >= 0) {
|
|
88
|
+
return coord / tile_size;
|
|
89
|
+
}
|
|
90
|
+
return (coord - tile_size + 1) / tile_size;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// tile_center(tile, tile_size): center coordinate of a tile
|
|
94
|
+
fn tile_center(tile: int, tile_size: int): int {
|
|
95
|
+
return tile * tile_size + tile_size / 2;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ─── Angle helpers ────────────────────────────────────────────────────────────
|
|
99
|
+
|
|
100
|
+
// angle_normalize(deg): normalize angle to [0, 3600000) (degrees × 10000)
|
|
101
|
+
fn angle_normalize(deg: int): int {
|
|
102
|
+
let a: int = deg;
|
|
103
|
+
while (a < 0) { a = a + 3600000; }
|
|
104
|
+
while (a >= 3600000) { a = a - 3600000; }
|
|
105
|
+
return a;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// angle_diff(a, b): signed shortest angular difference (degrees × 10000)
|
|
109
|
+
// Result in (-1800000, 1800000]
|
|
110
|
+
fn angle_diff(a: int, b: int): int {
|
|
111
|
+
let d: int = angle_normalize(b - a);
|
|
112
|
+
if (d > 1800000) { d = d - 3600000; }
|
|
113
|
+
return d;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ─── Sun angle helper ────────────────────────────────────────────────────────
|
|
117
|
+
|
|
118
|
+
// mc_day_angle(daytime): MC sun angle × 10000 from /time query daytime
|
|
119
|
+
// Daytime 0 = dawn (sun at east = 90°), 6000 = noon (sun at south = 180°)
|
|
120
|
+
fn mc_day_angle(daytime: int): int {
|
|
121
|
+
// MC daytime: 0-24000 ticks per day
|
|
122
|
+
// Sun angle = (daytime * 360 / 24000 + 90) mod 360
|
|
123
|
+
return ((daytime * 360 / 24000 + 90) % 360) * 10000;
|
|
124
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// list.mcrs — List and array utilities for RedScript datapacks.
|
|
2
|
+
//
|
|
3
|
+
// NOTE: Array parameters cannot be passed to functions by reference in
|
|
4
|
+
// the current RedScript implementation. Functions that operate on arrays
|
|
5
|
+
// must be inlined by the user, OR use fixed-size static helpers below.
|
|
6
|
+
//
|
|
7
|
+
// For dynamic array operations (sort, search, sum over variable-length arrays),
|
|
8
|
+
// write the loop directly in your code:
|
|
9
|
+
//
|
|
10
|
+
// let nums: int[] = [30, 10, 20];
|
|
11
|
+
// // Manual bubble sort (2 elements):
|
|
12
|
+
// if (nums[0] > nums[1]) {
|
|
13
|
+
// let tmp: int = nums[0];
|
|
14
|
+
// nums[0] = nums[1];
|
|
15
|
+
// nums[1] = tmp;
|
|
16
|
+
// }
|
|
17
|
+
//
|
|
18
|
+
// The static helpers below work on up to 5 discrete values passed as arguments.
|
|
19
|
+
|
|
20
|
+
module library;
|
|
21
|
+
|
|
22
|
+
// ─── Static min/max/avg ──────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
fn sort2_min(a: int, b: int): int { if (a <= b) { return a; } return b; }
|
|
25
|
+
fn sort2_max(a: int, b: int): int { if (a >= b) { return a; } return b; }
|
|
26
|
+
|
|
27
|
+
fn list_min3(a: int, b: int, c: int): int {
|
|
28
|
+
let m: int = a;
|
|
29
|
+
if (b < m) { m = b; }
|
|
30
|
+
if (c < m) { m = c; }
|
|
31
|
+
return m;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
fn list_max3(a: int, b: int, c: int): int {
|
|
35
|
+
let m: int = a;
|
|
36
|
+
if (b > m) { m = b; }
|
|
37
|
+
if (c > m) { m = c; }
|
|
38
|
+
return m;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
fn list_min5(a: int, b: int, c: int, d: int, e: int): int {
|
|
42
|
+
let m: int = a;
|
|
43
|
+
if (b < m) { m = b; }
|
|
44
|
+
if (c < m) { m = c; }
|
|
45
|
+
if (d < m) { m = d; }
|
|
46
|
+
if (e < m) { m = e; }
|
|
47
|
+
return m;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
fn list_max5(a: int, b: int, c: int, d: int, e: int): int {
|
|
51
|
+
let m: int = a;
|
|
52
|
+
if (b > m) { m = b; }
|
|
53
|
+
if (c > m) { m = c; }
|
|
54
|
+
if (d > m) { m = d; }
|
|
55
|
+
if (e > m) { m = e; }
|
|
56
|
+
return m;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
fn list_sum5(a: int, b: int, c: int, d: int, e: int): int { return a + b + c + d + e; }
|
|
60
|
+
fn list_sum4(a: int, b: int, c: int, d: int): int { return a + b + c + d; }
|
|
61
|
+
fn list_sum3(a: int, b: int, c: int): int { return a + b + c; }
|
|
62
|
+
fn avg3(a: int, b: int, c: int): int { return (a + b + c) / 3; }
|
|
63
|
+
fn avg5(a: int, b: int, c: int, d: int, e: int): int { return (a + b + c + d + e) / 5; }
|
|
64
|
+
|
|
65
|
+
// ─── Static sort (sorting network) ───────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
// sort3(a, b, c, pos): return sorted value at position pos (0=min, 1=mid, 2=max)
|
|
68
|
+
fn sort3(a: int, b: int, c: int, pos: int): int {
|
|
69
|
+
let x: int = a; let y: int = b; let z: int = c;
|
|
70
|
+
if (x > y) { let t: int = x; x = y; y = t; }
|
|
71
|
+
if (y > z) { let t: int = y; y = z; z = t; }
|
|
72
|
+
if (x > y) { let t: int = x; x = y; y = t; }
|
|
73
|
+
if (pos == 0) { return x; }
|
|
74
|
+
if (pos == 1) { return y; }
|
|
75
|
+
return z;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ─── Weighted random choice ───────────────────────────────────────────────────
|
|
79
|
+
|
|
80
|
+
fn weighted2(seed: int, w0: int, w1: int): int {
|
|
81
|
+
let total: int = w0 + w1;
|
|
82
|
+
let r: int = seed * 1664525 + 1013904223;
|
|
83
|
+
if (r < 0) { r = 0 - r; }
|
|
84
|
+
if (r % total < w0) { return 0; }
|
|
85
|
+
return 1;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
fn weighted3(seed: int, w0: int, w1: int, w2: int): int {
|
|
89
|
+
let total: int = w0 + w1 + w2;
|
|
90
|
+
let r: int = seed * 1664525 + 1013904223;
|
|
91
|
+
if (r < 0) { r = 0 - r; }
|
|
92
|
+
let v: int = r % total;
|
|
93
|
+
if (v < w0) { return 0; }
|
|
94
|
+
if (v < w0 + w1) { return 1; }
|
|
95
|
+
return 2;
|
|
96
|
+
}
|
package/src/stdlib/math.mcrs
CHANGED
|
@@ -300,3 +300,230 @@ fn smootherstep(lo: int, hi: int, x: int) -> int {
|
|
|
300
300
|
let inner: int = 10000 - 15 * t10 + 6 * t2 / 100;
|
|
301
301
|
return t3 * inner / 100000;
|
|
302
302
|
}
|
|
303
|
+
|
|
304
|
+
// AUTO-GENERATED by redscript tune — DO NOT EDIT
|
|
305
|
+
// Adapter: ln-polynomial | Date: 2026-03-17
|
|
306
|
+
// max_error: 0.000557 | mae: 0.000186 | estimated_cmds: 27
|
|
307
|
+
// Run `redscript tune --adapter ln-polynomial` to regenerate
|
|
308
|
+
//
|
|
309
|
+
// atanh series coefficients (×10000 scale):
|
|
310
|
+
// A1 = 20010 (theoretical 2×10000 = 20000)
|
|
311
|
+
// A3 = 6856 (theoretical 2/3×10000 = 6667)
|
|
312
|
+
// A5 = 2539 (theoretical 2/5×10000 = 4000)
|
|
313
|
+
|
|
314
|
+
fn ln(x: int): int {
|
|
315
|
+
// Input x: fixed-point ×10000; returns ln(x/10000)×10000
|
|
316
|
+
// Valid range: x ∈ [100, 1000000] (0.01 ~ 100.0)
|
|
317
|
+
// max_error: 0.000557 (in ×10000 units, i.e. 0.00000006 in real units)
|
|
318
|
+
|
|
319
|
+
let scale: int = 10000;
|
|
320
|
+
let ln2: int = 6931;
|
|
321
|
+
let A1: int = 20010;
|
|
322
|
+
let A3: int = 6856;
|
|
323
|
+
let A5: int = 2539;
|
|
324
|
+
|
|
325
|
+
// Step 1: range reduction — bring x into [scale, 2*scale)
|
|
326
|
+
let xr: int = x;
|
|
327
|
+
let k: int = 0;
|
|
328
|
+
while (xr < scale) {
|
|
329
|
+
xr = xr * 2;
|
|
330
|
+
k = k - 1;
|
|
331
|
+
}
|
|
332
|
+
while (xr >= scale * 2) {
|
|
333
|
+
xr = xr / 2;
|
|
334
|
+
k = k + 1;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Step 2: s = (xr - scale) * scale / (xr + scale)
|
|
338
|
+
let s: int = (xr - scale) * scale / (xr + scale);
|
|
339
|
+
|
|
340
|
+
// Step 3: atanh series ln(xr/scale) ≈ A1*s + A3*s³ + A5*s⁵ (all /scale)
|
|
341
|
+
let s2: int = s * s / scale;
|
|
342
|
+
let s3: int = s * s2;
|
|
343
|
+
let s5: int = s3 * s2;
|
|
344
|
+
let lnxr: int = A1 * s / scale + A3 * s3 / scale + A5 * s5 / scale;
|
|
345
|
+
|
|
346
|
+
// Step 4: ln(x) = k*ln(2) + ln(xr/scale)
|
|
347
|
+
return k * ln2 + lnxr;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// sqrt_fx(x): fixed-point sqrt, scale ×10000
|
|
351
|
+
// sqrt_fx(10000) == 10000 (√1.0 = 1.0)
|
|
352
|
+
// sqrt_fx(20000) ≈ 14142 (√2.0 ≈ 1.4142)
|
|
353
|
+
// sqrt_fx(40000) == 20000 (√4.0 = 2.0)
|
|
354
|
+
fn sqrt_fx(x: int) -> int {
|
|
355
|
+
return isqrt(x * 100) * 100;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// exp_fx(x): e^(x/10000) × 10000, fixed-point ×10000
|
|
359
|
+
// exp_fx(0) == 10000 (e^0 = 1.0)
|
|
360
|
+
// exp_fx(10000) ≈ 27183 (e^1 ≈ 2.7183)
|
|
361
|
+
// exp_fx(6931) ≈ 20000 (e^ln2 = 2.0)
|
|
362
|
+
// exp_fx(-10000) ≈ 3679 (e^-1 ≈ 0.3679)
|
|
363
|
+
// Valid range: x ∈ [-100000, 100000] (real: -10.0 to 10.0)
|
|
364
|
+
fn exp_fx(x: int): int {
|
|
365
|
+
// Range reduction: x = k*ln2 + r, r in [0, 6931]
|
|
366
|
+
let ln2: int = 6931;
|
|
367
|
+
let k: int = x / ln2;
|
|
368
|
+
let r: int = x - k * ln2;
|
|
369
|
+
if (r < 0) { r = r + ln2; k = k - 1; }
|
|
370
|
+
|
|
371
|
+
// 6-term Horner-form Taylor: e^r ≈ 1 + r + r²/2! + r³/3! + ...
|
|
372
|
+
// Coefficients scaled ×10000, nested for numerical stability
|
|
373
|
+
let t: int = 14;
|
|
374
|
+
t = 83 + t * r / 10000;
|
|
375
|
+
t = 417 + t * r / 10000;
|
|
376
|
+
t = 1667 + t * r / 10000;
|
|
377
|
+
t = 5000 + t * r / 10000;
|
|
378
|
+
t = 10000 + t * r / 10000;
|
|
379
|
+
let er: int = 10000 + t * r / 10000;
|
|
380
|
+
|
|
381
|
+
// Scale by 2^k
|
|
382
|
+
if (k >= 0) {
|
|
383
|
+
let i: int = 0;
|
|
384
|
+
while (i < k) { er = er * 2; i = i + 1; }
|
|
385
|
+
}
|
|
386
|
+
if (k < 0) {
|
|
387
|
+
let i: int = 0;
|
|
388
|
+
let nk: int = 0 - k;
|
|
389
|
+
while (i < nk) { er = er / 2; i = i + 1; }
|
|
390
|
+
}
|
|
391
|
+
return er;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// ─── Cubic root ──────────────────────────────────────────────────────────────
|
|
395
|
+
|
|
396
|
+
// cbrt_fx(x): integer cube root, returns floor(cbrt(x)).
|
|
397
|
+
// Uses Newton's method: g_next = (2*g + x/g²) / 3
|
|
398
|
+
// cbrt_fx(1000) = 10 (∛1000=10), cbrt_fx(27) = 3, cbrt_fx(8) = 2
|
|
399
|
+
fn cbrt_fx(x: int): int {
|
|
400
|
+
if (x <= 0) { return 0; }
|
|
401
|
+
let g: int = x / 3;
|
|
402
|
+
if (g <= 0) { g = 1; }
|
|
403
|
+
let i: int = 0;
|
|
404
|
+
while (i < 20) {
|
|
405
|
+
let g2: int = g * g;
|
|
406
|
+
if (g2 <= 0) { g2 = 1; }
|
|
407
|
+
let next: int = (2 * g + x / g2) / 3;
|
|
408
|
+
if (next == g) { i = 20; }
|
|
409
|
+
g = next;
|
|
410
|
+
if (g <= 0) { g = 1; }
|
|
411
|
+
i = i + 1;
|
|
412
|
+
}
|
|
413
|
+
return g;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// ─── Combinatorics ───────────────────────────────────────────────────────────
|
|
417
|
+
|
|
418
|
+
// factorial(n): n! for n ∈ [0, 12] (13! exceeds int32)
|
|
419
|
+
fn factorial(n: int): int {
|
|
420
|
+
if (n <= 1) { return 1; }
|
|
421
|
+
let r: int = 1;
|
|
422
|
+
let i: int = 2;
|
|
423
|
+
while (i <= n) { r = r * i; i = i + 1; }
|
|
424
|
+
return r;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// combinations(n, k): C(n,k) = n! / (k! * (n-k)!) for n ≤ 20, k ≤ n
|
|
428
|
+
// Uses multiplicative formula to avoid overflow: C(n,k) = ∏ (n-i)/(i+1) for i=0..k-1
|
|
429
|
+
fn combinations(n: int, k: int): int {
|
|
430
|
+
if (k <= 0) { return 1; }
|
|
431
|
+
if (k > n) { return 0; }
|
|
432
|
+
// Use smaller k for efficiency: C(n,k) == C(n, n-k)
|
|
433
|
+
let kk: int = k;
|
|
434
|
+
if (n - k < kk) { kk = n - k; }
|
|
435
|
+
let r: int = 1;
|
|
436
|
+
let i: int = 0;
|
|
437
|
+
while (i < kk) {
|
|
438
|
+
r = r * (n - i) / (i + 1);
|
|
439
|
+
i = i + 1;
|
|
440
|
+
}
|
|
441
|
+
return r;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// ─── Logarithm ───────────────────────────────────────────────────────────────
|
|
445
|
+
|
|
446
|
+
// log10_fx(x): log base 10, fixed-point ×10000
|
|
447
|
+
// log10(x) = ln(x) / ln(10) ≈ ln(x) / 23026
|
|
448
|
+
fn log10_fx(x: int): int {
|
|
449
|
+
return ln(x) * 10000 / 23026;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// log2_fx(x): log base 2, fixed-point ×10000
|
|
453
|
+
// log2(x) = ln(x) / ln(2) ≈ ln(x) / 6931
|
|
454
|
+
fn log2_fx(x: int): int {
|
|
455
|
+
return ln(x) * 10000 / 6931;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// loga_fx(base_fx, x): log_base(x), fixed-point ×10000
|
|
459
|
+
// base_fx and x are both ×10000
|
|
460
|
+
// loga_fx(20000, 40000) ≈ 10000 (log_2(4) = 2, but ×10000 → 20000... wait)
|
|
461
|
+
// Actually: log_b(x) = ln(x) / ln(b), both ×10000, so result = ln(x)/ln(b) × 10000
|
|
462
|
+
fn loga_fx(base_fx: int, x: int): int {
|
|
463
|
+
let lb: int = ln(base_fx);
|
|
464
|
+
if (lb == 0) { return 0; }
|
|
465
|
+
return ln(x) * 10000 / lb;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// ─── Gamma function approximation ────────────────────────────────────────────
|
|
469
|
+
|
|
470
|
+
// gamma_int(n): Gamma(n) = (n-1)! for positive integers
|
|
471
|
+
fn gamma_int(n: int): int {
|
|
472
|
+
if (n <= 1) { return 1; }
|
|
473
|
+
return factorial(n - 1);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// ─── Linear equation solvers ─────────────────────────────────────────────────
|
|
477
|
+
|
|
478
|
+
// solve2x2_x(a, b, e, c, d, f): solve ax + by = e, cx + dy = f → return x × 10000
|
|
479
|
+
// Uses Cramer's rule. Returns 0 if determinant = 0 (singular system).
|
|
480
|
+
// a, b, c, d, e, f are integers (not fixed-point); result is fixed-point ×10000.
|
|
481
|
+
fn solve2x2_x(a: int, b: int, e: int, c: int, d: int, f: int): int {
|
|
482
|
+
let det: int = a * d - b * c;
|
|
483
|
+
if (det == 0) { return 0; }
|
|
484
|
+
return (e * d - b * f) * 10000 / det;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// solve2x2_y(a, b, e, c, d, f): same system, return y × 10000
|
|
488
|
+
fn solve2x2_y(a: int, b: int, e: int, c: int, d: int, f: int): int {
|
|
489
|
+
let det: int = a * d - b * c;
|
|
490
|
+
if (det == 0) { return 0; }
|
|
491
|
+
return (a * f - e * c) * 10000 / det;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// ─── Quadratic equation ───────────────────────────────────────────────────────
|
|
495
|
+
|
|
496
|
+
// quadratic_disc(a, b, c): discriminant b² - 4ac
|
|
497
|
+
// Returns > 0 (two real roots), 0 (one root), < 0 (no real roots)
|
|
498
|
+
fn quadratic_disc(a: int, b: int, c: int): int {
|
|
499
|
+
return b * b - 4 * a * c;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// quadratic_x1(a, b, c): larger root × 10000 using integer sqrt
|
|
503
|
+
// Only valid when discriminant >= 0
|
|
504
|
+
fn quadratic_x1(a: int, b: int, c: int): int {
|
|
505
|
+
if (a == 0) { return 0; }
|
|
506
|
+
let disc: int = b * b - 4 * a * c;
|
|
507
|
+
if (disc < 0) { return 0; }
|
|
508
|
+
let sq: int = isqrt(disc);
|
|
509
|
+
return (0 - b + sq) * 10000 / (2 * a);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// quadratic_x2(a, b, c): smaller root × 10000
|
|
513
|
+
fn quadratic_x2(a: int, b: int, c: int): int {
|
|
514
|
+
if (a == 0) { return 0; }
|
|
515
|
+
let disc: int = b * b - 4 * a * c;
|
|
516
|
+
if (disc < 0) { return 0; }
|
|
517
|
+
let sq: int = isqrt(disc);
|
|
518
|
+
return (0 - b - sq) * 10000 / (2 * a);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// ─── Fixed-point comparison helpers ──────────────────────────────────────────
|
|
522
|
+
|
|
523
|
+
// approx_eq(a, b, eps): 1 if |a - b| <= eps
|
|
524
|
+
fn approx_eq(a: int, b: int, eps: int): int {
|
|
525
|
+
let d: int = a - b;
|
|
526
|
+
if (d < 0) { d = 0 - d; }
|
|
527
|
+
if (d <= eps) { return 1; }
|
|
528
|
+
return 0;
|
|
529
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// math_hp.mcrs — High-precision trig using MC entity rotation trick.
|
|
2
|
+
//
|
|
3
|
+
// MC internally uses Java Math.sin/cos (double precision).
|
|
4
|
+
// By teleporting a Marker entity one block in its local forward direction,
|
|
5
|
+
// Pos[0] = cos(θ) and Pos[2] = sin(θ) with ~15 significant figures.
|
|
6
|
+
//
|
|
7
|
+
// SCALE: angles in degrees × 10000 (e.g. 900000 = 90°)
|
|
8
|
+
// outputs × 10000 (e.g. 10000 = 1.0, -7071 ≈ sin 45°)
|
|
9
|
+
//
|
|
10
|
+
// ⚠ SETUP REQUIRED: Call init_trig() in your @load function:
|
|
11
|
+
// @load fn setup() { init_trig(); }
|
|
12
|
+
//
|
|
13
|
+
// Usage:
|
|
14
|
+
// import "stdlib/math_hp"
|
|
15
|
+
// @load fn setup() { init_trig(); }
|
|
16
|
+
// fn my_fn() {
|
|
17
|
+
// let s: int = sin_hp(450000); // sin(45°) ≈ 7071
|
|
18
|
+
// let c: int = cos_hp(450000); // cos(45°) ≈ 7071
|
|
19
|
+
// }
|
|
20
|
+
|
|
21
|
+
module library;
|
|
22
|
+
|
|
23
|
+
// Internal tag for the helper Marker entity.
|
|
24
|
+
// Do NOT kill or modify entities with this tag.
|
|
25
|
+
let _TRIG_TAG: string = "rs_trig";
|
|
26
|
+
|
|
27
|
+
// init_trig(): create the Marker entity used by sin_hp/cos_hp.
|
|
28
|
+
// Safe to call multiple times (uses execute unless entity).
|
|
29
|
+
// Must be called from your @load function.
|
|
30
|
+
@require_on_load(init_trig)
|
|
31
|
+
fn init_trig() {
|
|
32
|
+
raw("execute unless entity @e[tag=rs_trig,limit=1] run summon minecraft:marker ~ 0 ~ {Tags:[\"rs_trig\"]}");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// sin_hp(angle): high-precision sine.
|
|
36
|
+
// angle: degrees × 10000 (e.g. 450000 = 45°, 900000 = 90°)
|
|
37
|
+
// returns: sin(angle/10000°) × 10000
|
|
38
|
+
// Example: sin_hp(900000) == 10000, sin_hp(0) == 0, sin_hp(450000) ≈ 7071
|
|
39
|
+
@require_on_load(init_trig)
|
|
40
|
+
fn sin_hp(angle: int): int {
|
|
41
|
+
// Step 1: store angle into scoreboard, then use execute store to set Rotation[0]
|
|
42
|
+
scoreboard_set("$sin_hp_in", "__rs_math_hp", angle);
|
|
43
|
+
raw("execute store result entity @e[tag=rs_trig,limit=1] Rotation[0] float 0.0001 run scoreboard players get $sin_hp_in __rs_math_hp");
|
|
44
|
+
// Step 2: teleport Marker 1 block forward along its facing direction
|
|
45
|
+
raw("execute as @e[tag=rs_trig,limit=1] rotated as @s positioned 0.0 0.0 0.0 run tp @s ^ ^ ^1 ~ ~");
|
|
46
|
+
// Step 3: read Pos[2] (= sin θ), scale ×10000
|
|
47
|
+
raw("execute store result score $sin_hp_out __rs_math_hp run data get entity @e[tag=rs_trig,limit=1] Pos[2] 10000.0");
|
|
48
|
+
// Step 4: reset Marker position
|
|
49
|
+
raw("tp @e[tag=rs_trig,limit=1] 0 0 0");
|
|
50
|
+
return scoreboard_get("$sin_hp_out", "__rs_math_hp");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// cos_hp(angle): high-precision cosine.
|
|
54
|
+
// angle: degrees × 10000 (e.g. 450000 = 45°)
|
|
55
|
+
// returns: cos(angle/10000°) × 10000
|
|
56
|
+
@require_on_load(init_trig)
|
|
57
|
+
fn cos_hp(angle: int): int {
|
|
58
|
+
scoreboard_set("$cos_hp_in", "__rs_math_hp", angle);
|
|
59
|
+
raw("execute store result entity @e[tag=rs_trig,limit=1] Rotation[0] float 0.0001 run scoreboard players get $cos_hp_in __rs_math_hp");
|
|
60
|
+
raw("execute as @e[tag=rs_trig,limit=1] rotated as @s positioned 0.0 0.0 0.0 run tp @s ^ ^ ^1 ~ ~");
|
|
61
|
+
// Pos[0] = cos θ
|
|
62
|
+
raw("execute store result score $cos_hp_out __rs_math_hp run data get entity @e[tag=rs_trig,limit=1] Pos[0] 10000.0");
|
|
63
|
+
raw("tp @e[tag=rs_trig,limit=1] 0 0 0");
|
|
64
|
+
return scoreboard_get("$cos_hp_out", "__rs_math_hp");
|
|
65
|
+
}
|