redscript-mc 1.2.25 → 1.2.27
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/README.md +67 -9
- package/README.zh.md +61 -4
- package/dist/__tests__/cli.test.js +1 -1
- package/dist/__tests__/codegen.test.js +12 -6
- package/dist/__tests__/e2e.test.js +6 -6
- package/dist/__tests__/lowering.test.js +8 -8
- package/dist/__tests__/optimizer.test.js +31 -0
- package/dist/__tests__/stdlib-advanced.test.d.ts +4 -0
- package/dist/__tests__/stdlib-advanced.test.js +378 -0
- package/dist/__tests__/stdlib-bigint.test.d.ts +7 -0
- package/dist/__tests__/stdlib-bigint.test.js +428 -0
- package/dist/__tests__/stdlib-math.test.d.ts +7 -0
- package/dist/__tests__/stdlib-math.test.js +352 -0
- package/dist/__tests__/stdlib-vec.test.d.ts +4 -0
- package/dist/__tests__/stdlib-vec.test.js +264 -0
- package/dist/ast/types.d.ts +17 -1
- package/dist/codegen/mcfunction/index.js +154 -18
- package/dist/codegen/var-allocator.d.ts +17 -0
- package/dist/codegen/var-allocator.js +26 -0
- package/dist/compile.d.ts +14 -0
- package/dist/compile.js +62 -5
- package/dist/data/arena/function/__load.mcfunction +6 -0
- package/dist/data/arena/function/__tick.mcfunction +2 -0
- package/dist/data/arena/function/announce_leaders/else_1.mcfunction +3 -0
- package/dist/data/arena/function/announce_leaders/foreach_0/merge_2.mcfunction +1 -0
- package/dist/data/arena/function/announce_leaders/foreach_0/then_0.mcfunction +3 -0
- package/dist/data/arena/function/announce_leaders/foreach_0.mcfunction +7 -0
- package/dist/data/arena/function/announce_leaders/foreach_1/merge_2.mcfunction +1 -0
- package/dist/data/arena/function/announce_leaders/foreach_1/then_0.mcfunction +4 -0
- package/dist/data/arena/function/announce_leaders/foreach_1.mcfunction +6 -0
- package/dist/data/arena/function/announce_leaders/merge_2.mcfunction +1 -0
- package/dist/data/arena/function/announce_leaders/then_0.mcfunction +4 -0
- package/dist/data/arena/function/announce_leaders.mcfunction +6 -0
- package/dist/data/arena/function/arena_tick/merge_2.mcfunction +1 -0
- package/dist/data/arena/function/arena_tick/then_0.mcfunction +4 -0
- package/dist/data/arena/function/arena_tick.mcfunction +11 -0
- package/dist/data/counter/function/__load.mcfunction +5 -0
- package/dist/data/counter/function/__tick.mcfunction +2 -0
- package/dist/data/counter/function/counter_tick/merge_2.mcfunction +1 -0
- package/dist/data/counter/function/counter_tick/then_0.mcfunction +3 -0
- package/dist/data/counter/function/counter_tick.mcfunction +11 -0
- package/dist/data/gcd2/function/__load.mcfunction +3 -0
- package/dist/data/gcd2/function/abs/merge_2.mcfunction +3 -0
- package/dist/data/gcd2/function/abs/then_0.mcfunction +5 -0
- package/dist/data/gcd2/function/abs.mcfunction +7 -0
- package/dist/data/gcd2/function/gcd/loop_body_1.mcfunction +7 -0
- package/dist/data/gcd2/function/gcd/loop_check_0.mcfunction +5 -0
- package/dist/data/gcd2/function/gcd/loop_exit_2.mcfunction +3 -0
- package/dist/data/gcd2/function/gcd.mcfunction +14 -0
- package/dist/data/gcd3/function/__load.mcfunction +3 -0
- package/dist/data/gcd3/function/abs/merge_2.mcfunction +3 -0
- package/dist/data/gcd3/function/abs/then_0.mcfunction +5 -0
- package/dist/data/gcd3/function/abs.mcfunction +7 -0
- package/dist/data/gcd3/function/gcd/loop_body_1.mcfunction +7 -0
- package/dist/data/gcd3/function/gcd/loop_check_0.mcfunction +5 -0
- package/dist/data/gcd3/function/gcd/loop_exit_2.mcfunction +3 -0
- package/dist/data/gcd3/function/gcd.mcfunction +14 -0
- package/dist/data/gcd3/function/test.mcfunction +7 -0
- package/dist/data/gcd3nm/function/__load.mcfunction +3 -0
- package/dist/data/gcd3nm/function/abs/merge_2.mcfunction +3 -0
- package/dist/data/gcd3nm/function/abs/then_0.mcfunction +5 -0
- package/dist/data/gcd3nm/function/abs.mcfunction +7 -0
- package/dist/data/gcd3nm/function/gcd/loop_body_1.mcfunction +7 -0
- package/dist/data/gcd3nm/function/gcd/loop_check_0.mcfunction +5 -0
- package/dist/data/gcd3nm/function/gcd/loop_exit_2.mcfunction +3 -0
- package/dist/data/gcd3nm/function/gcd.mcfunction +14 -0
- package/dist/data/gcd3nm/function/test.mcfunction +7 -0
- package/dist/data/gcd_test/function/__load.mcfunction +3 -0
- package/dist/data/gcd_test/function/abs/merge_2.mcfunction +3 -0
- package/dist/data/gcd_test/function/abs/then_0.mcfunction +5 -0
- package/dist/data/gcd_test/function/abs.mcfunction +7 -0
- package/dist/data/gcd_test/function/gcd/loop_body_1.mcfunction +7 -0
- package/dist/data/gcd_test/function/gcd/loop_check_0.mcfunction +5 -0
- package/dist/data/gcd_test/function/gcd/loop_exit_2.mcfunction +3 -0
- package/dist/data/gcd_test/function/gcd.mcfunction +14 -0
- package/dist/data/isqrttest/function/__load.mcfunction +6 -0
- package/dist/data/isqrttest/function/isqrt/loop_body_4.mcfunction +12 -0
- package/dist/data/isqrttest/function/isqrt/loop_check_3.mcfunction +5 -0
- package/dist/data/isqrttest/function/isqrt/loop_exit_5.mcfunction +3 -0
- package/dist/data/isqrttest/function/isqrt/merge_2.mcfunction +4 -0
- package/dist/data/isqrttest/function/isqrt/merge_8.mcfunction +6 -0
- package/dist/data/isqrttest/function/isqrt/then_0.mcfunction +3 -0
- package/dist/data/isqrttest/function/isqrt/then_6.mcfunction +3 -0
- package/dist/data/isqrttest/function/isqrt.mcfunction +7 -0
- package/dist/data/isqrttest/function/test.mcfunction +6 -0
- package/dist/data/mathtest/function/__load.mcfunction +3 -0
- package/dist/data/mathtest/function/abs/merge_2.mcfunction +3 -0
- package/dist/data/mathtest/function/abs/then_0.mcfunction +5 -0
- package/dist/data/mathtest/function/abs.mcfunction +6 -0
- package/dist/data/mathtest/function/test.mcfunction +5 -0
- package/dist/data/minecraft/tags/function/load.json +5 -0
- package/dist/data/minecraft/tags/function/tick.json +5 -0
- package/dist/data/mypack/function/__load.mcfunction +13 -0
- package/dist/data/mypack/function/_atan_init.mcfunction +2 -0
- package/dist/data/mypack/function/abs/merge_2.mcfunction +3 -0
- package/dist/data/mypack/function/abs/then_0.mcfunction +5 -0
- package/dist/data/mypack/function/abs.mcfunction +6 -0
- package/dist/data/mypack/function/atan2_fixed/__sgi_1.mcfunction +2 -0
- package/dist/data/mypack/function/atan2_fixed/else_34.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/loop_body_31.mcfunction +19 -0
- package/dist/data/mypack/function/atan2_fixed/loop_check_30.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/loop_exit_32.mcfunction +6 -0
- package/dist/data/mypack/function/atan2_fixed/merge_11.mcfunction +6 -0
- package/dist/data/mypack/function/atan2_fixed/merge_14.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/merge_17.mcfunction +6 -0
- package/dist/data/mypack/function/atan2_fixed/merge_2.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_20.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_23.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_26.mcfunction +6 -0
- package/dist/data/mypack/function/atan2_fixed/merge_29.mcfunction +4 -0
- package/dist/data/mypack/function/atan2_fixed/merge_38.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_41.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_44.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_47.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_5.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/merge_8.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_0.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_12.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_15.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_18.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_21.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_24.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_27.mcfunction +6 -0
- package/dist/data/mypack/function/atan2_fixed/then_3.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_33.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_36.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_39.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_42.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_45.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed/then_6.mcfunction +3 -0
- package/dist/data/mypack/function/atan2_fixed/then_9.mcfunction +5 -0
- package/dist/data/mypack/function/atan2_fixed.mcfunction +7 -0
- package/dist/data/mypack/function/my_game.mcfunction +10 -0
- package/dist/data/quiz/function/__load.mcfunction +16 -0
- package/dist/data/quiz/function/__tick.mcfunction +6 -0
- package/dist/data/quiz/function/__trigger_quiz_a_dispatch.mcfunction +4 -0
- package/dist/data/quiz/function/__trigger_quiz_b_dispatch.mcfunction +4 -0
- package/dist/data/quiz/function/__trigger_quiz_c_dispatch.mcfunction +4 -0
- package/dist/data/quiz/function/__trigger_quiz_start_dispatch.mcfunction +4 -0
- package/dist/data/quiz/function/answer_a.mcfunction +4 -0
- package/dist/data/quiz/function/answer_b.mcfunction +4 -0
- package/dist/data/quiz/function/answer_c.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question/else_1.mcfunction +5 -0
- package/dist/data/quiz/function/ask_question/else_4.mcfunction +5 -0
- package/dist/data/quiz/function/ask_question/else_7.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question/merge_2.mcfunction +1 -0
- package/dist/data/quiz/function/ask_question/merge_5.mcfunction +2 -0
- package/dist/data/quiz/function/ask_question/merge_8.mcfunction +2 -0
- package/dist/data/quiz/function/ask_question/then_0.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question/then_3.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question/then_6.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question.mcfunction +7 -0
- package/dist/data/quiz/function/finish_quiz.mcfunction +6 -0
- package/dist/data/quiz/function/handle_answer/else_1.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/else_10.mcfunction +3 -0
- package/dist/data/quiz/function/handle_answer/else_16.mcfunction +3 -0
- package/dist/data/quiz/function/handle_answer/else_4.mcfunction +3 -0
- package/dist/data/quiz/function/handle_answer/else_7.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/merge_11.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/merge_14.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/merge_17.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/merge_2.mcfunction +8 -0
- package/dist/data/quiz/function/handle_answer/merge_5.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/merge_8.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/then_0.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/then_12.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/then_15.mcfunction +6 -0
- package/dist/data/quiz/function/handle_answer/then_3.mcfunction +6 -0
- package/dist/data/quiz/function/handle_answer/then_6.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/then_9.mcfunction +6 -0
- package/dist/data/quiz/function/handle_answer.mcfunction +11 -0
- package/dist/data/quiz/function/start_quiz.mcfunction +5 -0
- package/dist/data/reqtest/function/__load.mcfunction +4 -0
- package/dist/data/reqtest/function/_table_init.mcfunction +2 -0
- package/dist/data/reqtest/function/no_trig.mcfunction +3 -0
- package/dist/data/reqtest/function/use_table.mcfunction +4 -0
- package/dist/data/reqtest2/function/__load.mcfunction +3 -0
- package/dist/data/reqtest2/function/no_trig.mcfunction +3 -0
- package/dist/data/runtime/function/__load.mcfunction +5 -0
- package/dist/data/runtime/function/__tick.mcfunction +2 -0
- package/dist/data/runtime/function/counter_tick/then_0.mcfunction +3 -0
- package/dist/data/runtime/function/counter_tick.mcfunction +13 -0
- package/dist/data/shop/function/__load.mcfunction +7 -0
- package/dist/data/shop/function/__tick.mcfunction +3 -0
- package/dist/data/shop/function/__trigger_shop_buy_dispatch.mcfunction +4 -0
- package/dist/data/shop/function/complete_purchase/else_1.mcfunction +5 -0
- package/dist/data/shop/function/complete_purchase/else_4.mcfunction +5 -0
- package/dist/data/shop/function/complete_purchase/else_7.mcfunction +3 -0
- package/dist/data/shop/function/complete_purchase/merge_2.mcfunction +2 -0
- package/dist/data/shop/function/complete_purchase/merge_5.mcfunction +2 -0
- package/dist/data/shop/function/complete_purchase/merge_8.mcfunction +2 -0
- package/dist/data/shop/function/complete_purchase/then_0.mcfunction +4 -0
- package/dist/data/shop/function/complete_purchase/then_3.mcfunction +4 -0
- package/dist/data/shop/function/complete_purchase/then_6.mcfunction +4 -0
- package/dist/data/shop/function/complete_purchase.mcfunction +7 -0
- package/dist/data/shop/function/handle_shop_trigger.mcfunction +3 -0
- package/dist/data/swap_test/function/__load.mcfunction +3 -0
- package/dist/data/swap_test/function/gcd_old/loop_body_1.mcfunction +7 -0
- package/dist/data/swap_test/function/gcd_old/loop_check_0.mcfunction +5 -0
- package/dist/data/swap_test/function/gcd_old/loop_exit_2.mcfunction +3 -0
- package/dist/data/swap_test/function/gcd_old.mcfunction +8 -0
- package/dist/data/turret/function/__load.mcfunction +5 -0
- package/dist/data/turret/function/__tick.mcfunction +4 -0
- package/dist/data/turret/function/__trigger_deploy_turret_dispatch.mcfunction +4 -0
- package/dist/data/turret/function/deploy_turret.mcfunction +8 -0
- package/dist/data/turret/function/turret_tick/at_1.mcfunction +2 -0
- package/dist/data/turret/function/turret_tick/foreach_0.mcfunction +2 -0
- package/dist/data/turret/function/turret_tick/foreach_2.mcfunction +2 -0
- package/dist/data/turret/function/turret_tick/tick_body.mcfunction +3 -0
- package/dist/data/turret/function/turret_tick/tick_skip.mcfunction +1 -0
- package/dist/data/turret/function/turret_tick.mcfunction +5 -0
- package/dist/gcd2.map.json +15 -0
- package/dist/gcd3.map.json +17 -0
- package/dist/gcd_test.map.json +15 -0
- package/dist/index.js +20 -1
- package/dist/ir/types.d.ts +4 -0
- package/dist/isqrttest.map.json +15 -0
- package/dist/lexer/index.d.ts +1 -1
- package/dist/lexer/index.js +1 -0
- package/dist/lowering/index.d.ts +5 -0
- package/dist/lowering/index.js +154 -14
- package/dist/mathtest.map.json +6 -0
- package/dist/mypack.map.json +27 -0
- package/dist/optimizer/dce.js +21 -5
- package/dist/optimizer/passes.js +18 -6
- package/dist/optimizer/structure.js +7 -0
- package/dist/pack.mcmeta +6 -0
- package/dist/parser/index.d.ts +5 -0
- package/dist/parser/index.js +43 -2
- package/dist/reqtest.map.json +4 -0
- package/dist/reqtest2.map.json +4 -0
- package/dist/runtime/index.d.ts +6 -0
- package/dist/runtime/index.js +130 -9
- package/dist/runtime.map.json +7 -0
- package/dist/swap_test.map.json +14 -0
- package/editors/vscode/package-lock.json +3 -3
- package/editors/vscode/package.json +1 -1
- package/examples/showcase.mcrs +505 -0
- package/package.json +1 -1
- package/src/__tests__/cli.test.ts +1 -1
- package/src/__tests__/codegen.test.ts +12 -6
- package/src/__tests__/e2e.test.ts +6 -6
- package/src/__tests__/lowering.test.ts +8 -8
- package/src/__tests__/optimizer.test.ts +33 -0
- package/src/__tests__/stdlib-advanced.test.ts +379 -0
- package/src/__tests__/stdlib-bigint.test.ts +427 -0
- package/src/__tests__/stdlib-math.test.ts +374 -0
- package/src/__tests__/stdlib-vec.test.ts +259 -0
- package/src/ast/types.ts +11 -1
- package/src/codegen/mcfunction/index.ts +143 -19
- package/src/codegen/var-allocator.ts +29 -0
- package/src/compile.ts +72 -5
- package/src/index.ts +21 -1
- package/src/ir/types.ts +2 -0
- package/src/lexer/index.ts +2 -1
- package/src/lowering/index.ts +171 -14
- package/src/optimizer/dce.ts +22 -5
- package/src/optimizer/passes.ts +18 -5
- package/src/optimizer/structure.ts +6 -1
- package/src/parser/index.ts +47 -2
- package/src/runtime/index.ts +130 -10
- package/src/stdlib/advanced.mcrs +330 -0
- package/src/stdlib/bigint.mcrs +205 -0
- package/src/stdlib/math.mcrs +274 -21
- package/src/stdlib/vec.mcrs +246 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
// bigint.mcrs — Arbitrary precision integer arithmetic for RedScript.
|
|
2
|
+
//
|
|
3
|
+
// Representation:
|
|
4
|
+
// 8 limbs, base B = 10000 (10^4) per limb.
|
|
5
|
+
// Limb[0] = least significant (ones place in base 10000).
|
|
6
|
+
// Maximum value: 10^32 - 1 (32 decimal digits).
|
|
7
|
+
// Stored in NBT int arrays inside data storage ("rs:bigint").
|
|
8
|
+
//
|
|
9
|
+
// Registers: "a", "b", "c" (three independent BigInt values).
|
|
10
|
+
//
|
|
11
|
+
// Usage example:
|
|
12
|
+
// bigint_init();
|
|
13
|
+
// bigint_from_int_a(12345678); // a = 12345678
|
|
14
|
+
// bigint_from_int_b(87654321); // b = 87654321
|
|
15
|
+
// bigint_add(); // c = a + b = 99999999
|
|
16
|
+
// let limb0: int = bigint_get_c(0); // → 9999 (c[0])
|
|
17
|
+
// let limb1: int = bigint_get_c(1); // → 9999 (c[1])
|
|
18
|
+
//
|
|
19
|
+
// Multiply overflow note:
|
|
20
|
+
// bigint_mul uses grade-school O(n^2) algorithm.
|
|
21
|
+
// Per-product max: 9999 * 9999 + 9999 + 9999 = 99,999,999 < INT32 ✓
|
|
22
|
+
|
|
23
|
+
module library;
|
|
24
|
+
|
|
25
|
+
// ── Initialization ────────────────────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
// Initialize (or reset) all BigInt registers to zero.
|
|
28
|
+
// Must be called once before using any bigint operation.
|
|
29
|
+
fn bigint_init() {
|
|
30
|
+
storage_set_array("rs:bigint", "a", "[0,0,0,0,0,0,0,0]");
|
|
31
|
+
storage_set_array("rs:bigint", "b", "[0,0,0,0,0,0,0,0]");
|
|
32
|
+
storage_set_array("rs:bigint", "c", "[0,0,0,0,0,0,0,0]");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ── Load from int32 ───────────────────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
// Set register a from a 32-bit integer (splits into up to 3 limbs).
|
|
38
|
+
// Supports any n in [0, 999999999999] (12-digit safe limit).
|
|
39
|
+
fn bigint_from_int_a(n: int) {
|
|
40
|
+
storage_set_array("rs:bigint", "a", "[0,0,0,0,0,0,0,0]");
|
|
41
|
+
storage_set_int("rs:bigint", "a", 0, n % 10000);
|
|
42
|
+
storage_set_int("rs:bigint", "a", 1, n / 10000 % 10000);
|
|
43
|
+
storage_set_int("rs:bigint", "a", 2, n / 10000 / 10000);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Set register b from a 32-bit integer.
|
|
47
|
+
fn bigint_from_int_b(n: int) {
|
|
48
|
+
storage_set_array("rs:bigint", "b", "[0,0,0,0,0,0,0,0]");
|
|
49
|
+
storage_set_int("rs:bigint", "b", 0, n % 10000);
|
|
50
|
+
storage_set_int("rs:bigint", "b", 1, n / 10000 % 10000);
|
|
51
|
+
storage_set_int("rs:bigint", "b", 2, n / 10000 / 10000);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ── Read limb ─────────────────────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
fn bigint_get_a(i: int) -> int { return storage_get_int("rs:bigint", "a", i); }
|
|
57
|
+
fn bigint_get_b(i: int) -> int { return storage_get_int("rs:bigint", "b", i); }
|
|
58
|
+
fn bigint_get_c(i: int) -> int { return storage_get_int("rs:bigint", "c", i); }
|
|
59
|
+
|
|
60
|
+
// ── Copy between registers ────────────────────────────────────────────────────
|
|
61
|
+
|
|
62
|
+
fn bigint_copy_a_to_b() {
|
|
63
|
+
let i: int = 0;
|
|
64
|
+
while (i < 8) {
|
|
65
|
+
storage_set_int("rs:bigint", "b", i, storage_get_int("rs:bigint", "a", i));
|
|
66
|
+
i = i + 1;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fn bigint_copy_b_to_a() {
|
|
71
|
+
let i: int = 0;
|
|
72
|
+
while (i < 8) {
|
|
73
|
+
storage_set_int("rs:bigint", "a", i, storage_get_int("rs:bigint", "b", i));
|
|
74
|
+
i = i + 1;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
fn bigint_copy_c_to_a() {
|
|
79
|
+
let i: int = 0;
|
|
80
|
+
while (i < 8) {
|
|
81
|
+
storage_set_int("rs:bigint", "a", i, storage_get_int("rs:bigint", "c", i));
|
|
82
|
+
i = i + 1;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
fn bigint_copy_c_to_b() {
|
|
87
|
+
let i: int = 0;
|
|
88
|
+
while (i < 8) {
|
|
89
|
+
storage_set_int("rs:bigint", "b", i, storage_get_int("rs:bigint", "c", i));
|
|
90
|
+
i = i + 1;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ── Addition: c = a + b ───────────────────────────────────────────────────────
|
|
95
|
+
|
|
96
|
+
// c = a + b (carry propagated across all 8 limbs)
|
|
97
|
+
fn bigint_add() {
|
|
98
|
+
let carry: int = 0;
|
|
99
|
+
let i: int = 0;
|
|
100
|
+
while (i < 8) {
|
|
101
|
+
let s: int = storage_get_int("rs:bigint", "a", i)
|
|
102
|
+
+ storage_get_int("rs:bigint", "b", i)
|
|
103
|
+
+ carry;
|
|
104
|
+
carry = s / 10000;
|
|
105
|
+
storage_set_int("rs:bigint", "c", i, s % 10000);
|
|
106
|
+
i = i + 1;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ── Subtraction: c = a - b (assumes a ≥ b) ──────────────────────────────────
|
|
111
|
+
|
|
112
|
+
fn bigint_sub() {
|
|
113
|
+
let borrow: int = 0;
|
|
114
|
+
let i: int = 0;
|
|
115
|
+
while (i < 8) {
|
|
116
|
+
let d: int = storage_get_int("rs:bigint", "a", i)
|
|
117
|
+
- storage_get_int("rs:bigint", "b", i)
|
|
118
|
+
- borrow;
|
|
119
|
+
if (d < 0) {
|
|
120
|
+
d = d + 10000;
|
|
121
|
+
borrow = 1;
|
|
122
|
+
} else {
|
|
123
|
+
borrow = 0;
|
|
124
|
+
}
|
|
125
|
+
storage_set_int("rs:bigint", "c", i, d);
|
|
126
|
+
i = i + 1;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ── Comparison: returns 1 (a>b), 0 (a==b), -1 (a<b) ─────────────────────────
|
|
131
|
+
|
|
132
|
+
fn bigint_compare() -> int {
|
|
133
|
+
let i: int = 7;
|
|
134
|
+
while (i >= 0) {
|
|
135
|
+
let ai: int = storage_get_int("rs:bigint", "a", i);
|
|
136
|
+
let bi: int = storage_get_int("rs:bigint", "b", i);
|
|
137
|
+
if (ai > bi) { return 1; }
|
|
138
|
+
if (ai < bi) { return -1; }
|
|
139
|
+
i = i - 1;
|
|
140
|
+
}
|
|
141
|
+
return 0;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ── Multiply by small constant: c = a × k (k < 10000) ───────────────────────
|
|
145
|
+
// Max per-limb: 9999 × 9999 + 9999 = 99,989,999 < INT32 ✓
|
|
146
|
+
|
|
147
|
+
fn bigint_mul_small(k: int) {
|
|
148
|
+
let carry: int = 0;
|
|
149
|
+
let i: int = 0;
|
|
150
|
+
while (i < 8) {
|
|
151
|
+
let p: int = storage_get_int("rs:bigint", "a", i) * k + carry;
|
|
152
|
+
carry = p / 10000;
|
|
153
|
+
storage_set_int("rs:bigint", "c", i, p % 10000);
|
|
154
|
+
i = i + 1;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ── Multiply: c = a × b (grade-school O(n²), n=8) ───────────────────────────
|
|
159
|
+
// Per-product max: 9999 × 9999 + 9999 (prev c) + 9999 (carry) = 99,999,999 < INT32 ✓
|
|
160
|
+
|
|
161
|
+
fn bigint_mul() {
|
|
162
|
+
storage_set_array("rs:bigint", "c", "[0,0,0,0,0,0,0,0]");
|
|
163
|
+
let i: int = 0;
|
|
164
|
+
while (i < 8) {
|
|
165
|
+
let ai: int = storage_get_int("rs:bigint", "a", i);
|
|
166
|
+
if (ai != 0) {
|
|
167
|
+
let j: int = 0;
|
|
168
|
+
let carry: int = 0;
|
|
169
|
+
while (j < 8) {
|
|
170
|
+
let k: int = i + j;
|
|
171
|
+
if (k < 8) {
|
|
172
|
+
let p: int = ai * storage_get_int("rs:bigint", "b", j)
|
|
173
|
+
+ storage_get_int("rs:bigint", "c", k)
|
|
174
|
+
+ carry;
|
|
175
|
+
carry = p / 10000;
|
|
176
|
+
storage_set_int("rs:bigint", "c", k, p % 10000);
|
|
177
|
+
}
|
|
178
|
+
j = j + 1;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
i = i + 1;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ── Fibonacci: F(n) → register a (n ≤ 150 before 32-digit overflow) ─────────
|
|
186
|
+
//
|
|
187
|
+
// Invariant: a=F(k), b=F(k+1). After n iterations: a=F(n).
|
|
188
|
+
//
|
|
189
|
+
// F(50) = 12,586,269,025 → a[0]=9025, a[1]=8626, a[2]=125
|
|
190
|
+
// F(100) = 354,224,848,179,261,915,075 → 21 digits, fits in 6 limbs
|
|
191
|
+
|
|
192
|
+
fn bigint_fib(n: int) {
|
|
193
|
+
bigint_init(); // a=0=F(0), b=0
|
|
194
|
+
bigint_from_int_b(1); // b=1=F(1)
|
|
195
|
+
let i: int = 0;
|
|
196
|
+
while (i < n) {
|
|
197
|
+
// Invariant entering iteration: a=F(i), b=F(i+1)
|
|
198
|
+
bigint_add(); // c = F(i) + F(i+1) = F(i+2)
|
|
199
|
+
bigint_copy_b_to_a(); // a = F(i+1)
|
|
200
|
+
bigint_copy_c_to_b(); // b = F(i+2)
|
|
201
|
+
// Invariant restored: a=F(i+1), b=F(i+2)
|
|
202
|
+
i = i + 1;
|
|
203
|
+
}
|
|
204
|
+
// result: a = F(n)
|
|
205
|
+
}
|
package/src/stdlib/math.mcrs
CHANGED
|
@@ -1,49 +1,302 @@
|
|
|
1
|
-
// Integer math helpers for RedScript datapacks.
|
|
1
|
+
// math.mcrs — Integer & fixed-point math helpers for RedScript datapacks.
|
|
2
|
+
//
|
|
3
|
+
// Fixed-point convention: scale = 1000
|
|
4
|
+
// 1.0 → 1000
|
|
5
|
+
// 3.14 → 3140
|
|
6
|
+
// Use `sqrt_fixed` / `lerp` for sub-integer precision.
|
|
7
|
+
//
|
|
8
|
+
// Phase 1: basic integer helpers (abs, sign, min, max, clamp, lerp)
|
|
9
|
+
// Phase 2: iterative algorithms (isqrt, sqrt_fixed, pow_int, gcd)
|
|
10
|
+
// Phase 3: trig (sin_fixed, cos_fixed) — lookup table in NBT storage
|
|
11
|
+
|
|
12
|
+
// All functions in this file are library-mode: only compiled into the
|
|
13
|
+
// datapack if actually called from user code. Use via `librarySources`
|
|
14
|
+
// compile option or concatenate with user code (module library; handles it).
|
|
15
|
+
module library;
|
|
16
|
+
// Phase 4: number theory & utilities (lcm, map, ceil_div, log2_int)
|
|
17
|
+
|
|
18
|
+
// ─── Phase 1: Basic integer helpers ──────────────────────────────────────────
|
|
2
19
|
|
|
3
20
|
fn abs(x: int) -> int {
|
|
4
21
|
if (x < 0) {
|
|
5
|
-
return -x;
|
|
6
|
-
} else {
|
|
7
|
-
return x;
|
|
22
|
+
return 0 - x;
|
|
8
23
|
}
|
|
24
|
+
return x;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
fn sign(x: int) -> int {
|
|
28
|
+
if (x > 0) {
|
|
29
|
+
return 1;
|
|
30
|
+
}
|
|
31
|
+
if (x < 0) {
|
|
32
|
+
return -1;
|
|
33
|
+
}
|
|
34
|
+
return 0;
|
|
9
35
|
}
|
|
10
36
|
|
|
11
37
|
fn min(a: int, b: int) -> int {
|
|
12
38
|
if (a < b) {
|
|
13
39
|
return a;
|
|
14
|
-
} else {
|
|
15
|
-
return b;
|
|
16
40
|
}
|
|
41
|
+
return b;
|
|
17
42
|
}
|
|
18
43
|
|
|
19
44
|
fn max(a: int, b: int) -> int {
|
|
20
45
|
if (a > b) {
|
|
21
46
|
return a;
|
|
22
|
-
} else {
|
|
23
|
-
return b;
|
|
24
47
|
}
|
|
48
|
+
return b;
|
|
25
49
|
}
|
|
26
50
|
|
|
27
51
|
fn clamp(x: int, lo: int, hi: int) -> int {
|
|
28
52
|
if (x < lo) {
|
|
29
53
|
return lo;
|
|
30
|
-
} else {
|
|
31
|
-
if (x > hi) {
|
|
32
|
-
return hi;
|
|
33
|
-
} else {
|
|
34
|
-
return x;
|
|
35
|
-
}
|
|
36
54
|
}
|
|
55
|
+
if (x > hi) {
|
|
56
|
+
return hi;
|
|
57
|
+
}
|
|
58
|
+
return x;
|
|
37
59
|
}
|
|
38
60
|
|
|
39
|
-
|
|
40
|
-
|
|
61
|
+
// Linear interpolation (fixed-point t, t in [0, 1000])
|
|
62
|
+
// lerp(0, 1000, 500) == 500
|
|
63
|
+
// lerp(100, 200, 750) == 175
|
|
64
|
+
fn lerp(a: int, b: int, t: int) -> int {
|
|
65
|
+
return a + (b - a) * t / 1000;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ─── Phase 2: Iterative algorithms ───────────────────────────────────────────
|
|
69
|
+
|
|
70
|
+
// Integer square root: floor(sqrt(n))
|
|
71
|
+
// Uses Newton's method, converges in ≤16 iterations for all int32.
|
|
72
|
+
// isqrt(9) == 3, isqrt(10) == 3, isqrt(0) == 0
|
|
73
|
+
fn isqrt(n: int) -> int {
|
|
74
|
+
if (n <= 0) { return 0; }
|
|
75
|
+
if (n == 1) { return 1; }
|
|
76
|
+
// Bit-length of n: how many bits needed to represent n.
|
|
77
|
+
let bits: int = 0;
|
|
78
|
+
let tmp: int = n;
|
|
79
|
+
while (tmp > 0) {
|
|
80
|
+
tmp = tmp / 2;
|
|
81
|
+
bits = bits + 1;
|
|
82
|
+
}
|
|
83
|
+
// Initial guess: 2^((bits+1)/2). Always ≥ sqrt(n), so Newton converges
|
|
84
|
+
// monotonically from above — the standard floor-sqrt Newton iteration.
|
|
85
|
+
let half: int = (bits + 1) / 2;
|
|
86
|
+
let x: int = 1;
|
|
87
|
+
let j: int = 0;
|
|
88
|
+
while (j < half) {
|
|
89
|
+
x = x * 2;
|
|
90
|
+
j = j + 1;
|
|
91
|
+
}
|
|
92
|
+
// Newton–Raphson floor-sqrt: converges in ≤ 8 iterations from a 2× overestimate.
|
|
93
|
+
let i: int = 0;
|
|
94
|
+
while (i < 16) {
|
|
95
|
+
let next: int = (x + n / x) / 2;
|
|
96
|
+
if (next >= x) { return x; }
|
|
97
|
+
x = next;
|
|
98
|
+
i = i + 1;
|
|
99
|
+
}
|
|
100
|
+
return x;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Fixed-point sqrt (scale = 1000)
|
|
104
|
+
// sqrt_fixed(2000) ≈ 1414 (√2 × 1000)
|
|
105
|
+
// sqrt_fixed(1000) == 1000 (√1 × 1000)
|
|
106
|
+
fn sqrt_fixed(x: int) -> int {
|
|
107
|
+
return isqrt(x * 1000);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Integer power: base^exp (exp ≥ 0)
|
|
111
|
+
// Fast exponentiation by squaring: O(log exp)
|
|
112
|
+
// pow_int(2, 10) == 1024, pow_int(3, 0) == 1
|
|
113
|
+
fn pow_int(base: int, exp: int) -> int {
|
|
114
|
+
if (exp <= 0) {
|
|
41
115
|
return 1;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
116
|
+
}
|
|
117
|
+
let result: int = 1;
|
|
118
|
+
let b: int = base;
|
|
119
|
+
let e: int = exp;
|
|
120
|
+
while (e > 0) {
|
|
121
|
+
if (e % 2 == 1) {
|
|
122
|
+
result = result * b;
|
|
47
123
|
}
|
|
124
|
+
b = b * b;
|
|
125
|
+
e = e / 2;
|
|
126
|
+
}
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Greatest common divisor (Euclidean algorithm)
|
|
131
|
+
// gcd(12, 8) == 4, gcd(0, 5) == 5
|
|
132
|
+
fn gcd(a: int, b: int) -> int {
|
|
133
|
+
// Inline abs to avoid cross-function scoreboard variable collision.
|
|
134
|
+
let x: int = a;
|
|
135
|
+
if (x < 0) { x = 0 - x; }
|
|
136
|
+
let y: int = b;
|
|
137
|
+
if (y < 0) { y = 0 - y; }
|
|
138
|
+
while (y > 0) {
|
|
139
|
+
let r: int = x % y;
|
|
140
|
+
x = y;
|
|
141
|
+
y = r;
|
|
142
|
+
}
|
|
143
|
+
return x;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ─── Phase 3: Trigonometry ────────────────────────────────────────────────────
|
|
147
|
+
//
|
|
148
|
+
// sin/cos lookup table stored in NBT storage (math:tables).
|
|
149
|
+
// 91 entries covering 0-90°; other quadrants derived by symmetry.
|
|
150
|
+
// All values are sin(i°) × 1000, rounded to nearest integer.
|
|
151
|
+
//
|
|
152
|
+
// Accuracy: ≤ 1 unit error (≤0.1% relative) for all integer degrees.
|
|
153
|
+
// Cost: ~4 MC commands per call + 1 NBT read per call (O(1)).
|
|
154
|
+
|
|
155
|
+
// Initialize the sin lookup table.
|
|
156
|
+
// This function has NO @load — it is called from __load only when sin_fixed
|
|
157
|
+
// or cos_fixed are compiled into the project (via @requires). If you only
|
|
158
|
+
// use Phase 1/2/4 functions, this never runs and adds zero overhead.
|
|
159
|
+
fn _math_init() {
|
|
160
|
+
storage_set_array("math:tables", "sin",
|
|
161
|
+
"[0, 17, 35, 52, 70, 87, 105, 122, 139, 156, 174, 191, 208, 225, 242, 259, 276, 292, 309, 326, 342, 358, 375, 391, 407, 423, 438, 454, 469, 485, 500, 515, 530, 545, 559, 574, 588, 602, 616, 629, 643, 656, 669, 682, 695, 707, 719, 731, 743, 755, 766, 777, 788, 799, 809, 819, 829, 839, 848, 857, 866, 875, 883, 891, 899, 906, 914, 921, 927, 934, 940, 946, 951, 956, 961, 966, 970, 974, 978, 982, 985, 988, 990, 993, 995, 996, 998, 999, 999, 1000, 1000]"
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// sin_fixed(deg) → sin(deg°) × 1000 (integer degrees, any value)
|
|
166
|
+
// sin_fixed(30) == 500
|
|
167
|
+
// sin_fixed(90) == 1000
|
|
168
|
+
// sin_fixed(180) == 0
|
|
169
|
+
// sin_fixed(270) == -1000
|
|
170
|
+
//
|
|
171
|
+
// @require_on_load(_math_init): the sin lookup table is written to NBT storage at
|
|
172
|
+
// world load automatically when this function is included in a project.
|
|
173
|
+
@require_on_load(_math_init)
|
|
174
|
+
fn sin_fixed(deg: int) -> int {
|
|
175
|
+
// Normalise to [0, 359]
|
|
176
|
+
let d: int = deg % 360;
|
|
177
|
+
if (d < 0) { d = d + 360; }
|
|
178
|
+
|
|
179
|
+
// Quadrant reduction to first quadrant index [0, 90]
|
|
180
|
+
if (d <= 90) {
|
|
181
|
+
return storage_get_int("math:tables", "sin", d);
|
|
182
|
+
}
|
|
183
|
+
if (d <= 180) {
|
|
184
|
+
return storage_get_int("math:tables", "sin", 180 - d);
|
|
185
|
+
}
|
|
186
|
+
if (d <= 270) {
|
|
187
|
+
let idx: int = d - 180;
|
|
188
|
+
return 0 - storage_get_int("math:tables", "sin", idx);
|
|
48
189
|
}
|
|
190
|
+
// d in (270, 360)
|
|
191
|
+
let idx: int = 360 - d;
|
|
192
|
+
return 0 - storage_get_int("math:tables", "sin", idx);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// cos_fixed(deg) → cos(deg°) × 1000 (integer degrees, any value)
|
|
196
|
+
// cos_fixed(0) == 1000
|
|
197
|
+
// cos_fixed(90) == 0
|
|
198
|
+
// cos_fixed(180) == -1000
|
|
199
|
+
@require_on_load(_math_init)
|
|
200
|
+
fn cos_fixed(deg: int) -> int {
|
|
201
|
+
return sin_fixed(deg + 90);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ─── Phase 4: Number theory & utilities ──────────────────────────────────────
|
|
205
|
+
|
|
206
|
+
// Least common multiple
|
|
207
|
+
// lcm(4, 6) == 12, lcm(0, 5) == 0
|
|
208
|
+
fn lcm(a: int, b: int) -> int {
|
|
209
|
+
let g: int = gcd(a, b);
|
|
210
|
+
if (g == 0) { return 0; }
|
|
211
|
+
return a / g * b;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Range map: scale x from [in_lo, in_hi] onto [out_lo, out_hi].
|
|
215
|
+
// Uses integer arithmetic — multiply before dividing to preserve precision.
|
|
216
|
+
// map(5, 0, 10, 0, 100) == 50
|
|
217
|
+
// map(1, 0, 10, 100, 200) == 110
|
|
218
|
+
fn map(x: int, in_lo: int, in_hi: int, out_lo: int, out_hi: int) -> int {
|
|
219
|
+
let in_range: int = in_hi - in_lo;
|
|
220
|
+
if (in_range == 0) { return out_lo; }
|
|
221
|
+
return out_lo + (x - in_lo) * (out_hi - out_lo) / in_range;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Ceiling division: ⌈a / b⌉ (b > 0 required)
|
|
225
|
+
// ceil_div(7, 3) == 3, ceil_div(6, 3) == 2
|
|
226
|
+
fn ceil_div(a: int, b: int) -> int {
|
|
227
|
+
return (a + b - 1) / b;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Integer log base 2: ⌊log₂(n)⌋
|
|
231
|
+
// log2_int(1) == 0, log2_int(8) == 3, log2_int(7) == 2
|
|
232
|
+
// Returns -1 for n ≤ 0 (error sentinel).
|
|
233
|
+
fn log2_int(n: int) -> int {
|
|
234
|
+
if (n <= 0) { return -1; }
|
|
235
|
+
let result: int = 0;
|
|
236
|
+
let v: int = n;
|
|
237
|
+
while (v > 1) {
|
|
238
|
+
v = v / 2;
|
|
239
|
+
result = result + 1;
|
|
240
|
+
}
|
|
241
|
+
return result;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// ─── Phase 5: Fixed-point arithmetic & easing ────────────────────────────────
|
|
245
|
+
// Vector functions (dot2d, cross2d, length2d_fixed, manhattan, chebyshev,
|
|
246
|
+
// atan2_fixed, rotate2d, normalize2d, etc.) have moved to vec.mcrs.
|
|
247
|
+
|
|
248
|
+
// Fixed-point multiply: (a × b) / 1000
|
|
249
|
+
// Use instead of a*b when both operands are fixed-point (scale=1000),
|
|
250
|
+
// e.g. mulfix(sin_fixed(30), cos_fixed(45)) instead of sin*cos which overflows.
|
|
251
|
+
// mulfix(500, 707) == 353 (≈ 0.5 × 0.707)
|
|
252
|
+
fn mulfix(a: int, b: int) -> int {
|
|
253
|
+
return a * b / 1000;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Fixed-point divide: (a × 1000) / b
|
|
257
|
+
// Inverse of mulfix; produces a fixed-point result from two integers.
|
|
258
|
+
// divfix(1, 3) == 333 (≈ 0.333)
|
|
259
|
+
fn divfix(a: int, b: int) -> int {
|
|
260
|
+
if (b == 0) { return 0; }
|
|
261
|
+
return a * 1000 / b;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Smooth Hermite interpolation (Ken Perlin's smoothstep).
|
|
265
|
+
// Returns a value in [0, 1000] (fixed-point scale = 1000).
|
|
266
|
+
// Eases in AND out — useful for animations and value transitions.
|
|
267
|
+
//
|
|
268
|
+
// smoothstep(0, 100, 0) == 0
|
|
269
|
+
// smoothstep(0, 100, 50) == 500
|
|
270
|
+
// smoothstep(0, 100, 100) == 1000
|
|
271
|
+
// smoothstep(0, 100, 25) == 156 (≈ 3×0.25² − 2×0.25³ = 0.15625)
|
|
272
|
+
fn smoothstep(lo: int, hi: int, x: int) -> int {
|
|
273
|
+
let range: int = hi - lo;
|
|
274
|
+
if (range == 0) { return 0; }
|
|
275
|
+
// t in [0, 1000]
|
|
276
|
+
let t: int = (x - lo) * 1000 / range;
|
|
277
|
+
if (t < 0) { t = 0; }
|
|
278
|
+
if (t > 1000) { t = 1000; }
|
|
279
|
+
// f(t) = t² × (3 − 2t) / 1000 (all in scale=1000)
|
|
280
|
+
// Rewrite to avoid int32 overflow: use t/10 as intermediate
|
|
281
|
+
let t10: int = t / 10; // [0, 100], avoids 1000² = 10⁶ overflow
|
|
282
|
+
return t10 * t10 * (3000 - 2 * t) / 10000;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Smoother step (Perlin's order-5): 6t⁵ − 15t⁴ + 10t³
|
|
286
|
+
// Higher-order derivative at edges → smoother acceleration curve.
|
|
287
|
+
// smootherstep(0, 100, 25) ≈ 103
|
|
288
|
+
fn smootherstep(lo: int, hi: int, x: int) -> int {
|
|
289
|
+
let range: int = hi - lo;
|
|
290
|
+
if (range == 0) { return 0; }
|
|
291
|
+
let t: int = (x - lo) * 1000 / range;
|
|
292
|
+
if (t < 0) { t = 0; }
|
|
293
|
+
if (t > 1000) { t = 1000; }
|
|
294
|
+
// f(t) = t³ × (10 − t × (15 − 6t) / 1000) / 1000000
|
|
295
|
+
// Compute in stages to stay within int32
|
|
296
|
+
let t10: int = t / 10; // [0, 100]
|
|
297
|
+
let t2: int = t10 * t10; // [0, 10000]
|
|
298
|
+
let t3: int = t2 * t10 / 100; // [0, 10000]
|
|
299
|
+
// 10t³ − 15t⁴ + 6t⁵ = t³(10 − 15t + 6t²) at scale=1000
|
|
300
|
+
let inner: int = 10000 - 15 * t10 + 6 * t2 / 100;
|
|
301
|
+
return t3 * inner / 100000;
|
|
49
302
|
}
|