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.
Files changed (82) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +18 -2
  3. package/dist/src/__tests__/array-dynamic.test.d.ts +12 -0
  4. package/dist/src/__tests__/array-dynamic.test.js +131 -0
  5. package/dist/src/__tests__/array-write.test.d.ts +11 -0
  6. package/dist/src/__tests__/array-write.test.js +149 -0
  7. package/dist/src/__tests__/tuner/engine.test.d.ts +4 -0
  8. package/dist/src/__tests__/tuner/engine.test.js +232 -0
  9. package/dist/src/ast/types.d.ts +7 -0
  10. package/dist/src/emit/modules.js +5 -0
  11. package/dist/src/hir/lower.js +29 -0
  12. package/dist/src/hir/monomorphize.js +2 -0
  13. package/dist/src/hir/types.d.ts +9 -2
  14. package/dist/src/lir/lower.js +131 -0
  15. package/dist/src/mir/lower.js +73 -3
  16. package/dist/src/mir/macro.js +5 -0
  17. package/dist/src/mir/types.d.ts +12 -0
  18. package/dist/src/mir/verify.js +7 -0
  19. package/dist/src/optimizer/copy_prop.js +5 -0
  20. package/dist/src/optimizer/coroutine.js +12 -0
  21. package/dist/src/optimizer/dce.js +9 -0
  22. package/dist/src/optimizer/unroll.js +3 -0
  23. package/dist/src/parser/index.js +5 -0
  24. package/dist/src/tuner/adapters/ln-polynomial.d.ts +23 -0
  25. package/dist/src/tuner/adapters/ln-polynomial.js +142 -0
  26. package/dist/src/tuner/adapters/sqrt-newton.d.ts +28 -0
  27. package/dist/src/tuner/adapters/sqrt-newton.js +125 -0
  28. package/dist/src/tuner/cli.d.ts +5 -0
  29. package/dist/src/tuner/cli.js +168 -0
  30. package/dist/src/tuner/engine.d.ts +17 -0
  31. package/dist/src/tuner/engine.js +215 -0
  32. package/dist/src/tuner/metrics.d.ts +15 -0
  33. package/dist/src/tuner/metrics.js +51 -0
  34. package/dist/src/tuner/simulator.d.ts +35 -0
  35. package/dist/src/tuner/simulator.js +78 -0
  36. package/dist/src/tuner/types.d.ts +32 -0
  37. package/dist/src/tuner/types.js +6 -0
  38. package/dist/src/typechecker/index.js +5 -0
  39. package/docs/STDLIB_ROADMAP.md +142 -0
  40. package/editors/vscode/package-lock.json +3 -3
  41. package/editors/vscode/package.json +1 -1
  42. package/package.json +1 -1
  43. package/src/__tests__/array-dynamic.test.ts +147 -0
  44. package/src/__tests__/array-write.test.ts +169 -0
  45. package/src/__tests__/tuner/engine.test.ts +260 -0
  46. package/src/ast/types.ts +1 -0
  47. package/src/emit/modules.ts +5 -0
  48. package/src/hir/lower.ts +30 -0
  49. package/src/hir/monomorphize.ts +2 -0
  50. package/src/hir/types.ts +3 -1
  51. package/src/lir/lower.ts +151 -0
  52. package/src/mir/lower.ts +75 -3
  53. package/src/mir/macro.ts +5 -0
  54. package/src/mir/types.ts +2 -0
  55. package/src/mir/verify.ts +7 -0
  56. package/src/optimizer/copy_prop.ts +5 -0
  57. package/src/optimizer/coroutine.ts +9 -0
  58. package/src/optimizer/dce.ts +6 -0
  59. package/src/optimizer/unroll.ts +3 -0
  60. package/src/parser/index.ts +9 -0
  61. package/src/stdlib/bigint.mcrs +155 -192
  62. package/src/stdlib/bits.mcrs +158 -0
  63. package/src/stdlib/color.mcrs +160 -0
  64. package/src/stdlib/geometry.mcrs +124 -0
  65. package/src/stdlib/list.mcrs +96 -0
  66. package/src/stdlib/math.mcrs +227 -0
  67. package/src/stdlib/math_hp.mcrs +65 -0
  68. package/src/stdlib/random.mcrs +67 -0
  69. package/src/stdlib/signal.mcrs +112 -0
  70. package/src/stdlib/timer.mcrs +32 -0
  71. package/src/stdlib/vec.mcrs +27 -0
  72. package/src/tuner/adapters/ln-polynomial.ts +147 -0
  73. package/src/tuner/adapters/sqrt-newton.ts +135 -0
  74. package/src/tuner/cli.ts +158 -0
  75. package/src/tuner/engine.ts +272 -0
  76. package/src/tuner/metrics.ts +66 -0
  77. package/src/tuner/simulator.ts +69 -0
  78. package/src/tuner/types.ts +44 -0
  79. package/src/typechecker/index.ts +6 -0
  80. package/docs/ARCHITECTURE.zh.md +0 -1088
  81. package/docs/COMPILATION_STATS.md +0 -142
  82. 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
+ }
@@ -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
+ }