Skip to content

Commit c5b3e0f

Browse files
committed
Add toss, dice functions
1 parent 2e509b2 commit c5b3e0f

File tree

3 files changed

+159
-39
lines changed

3 files changed

+159
-39
lines changed

example/example.script

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,45 @@
1-
local TINT_GREEN = vmath.vector4(0.3, 0.9, 0.3, 1)
2-
local TINT_RED = vmath.vector4(0.9, 0.3, 0.3, 1)
3-
local EPSILON = 0.00001
4-
5-
function init(self)
6-
msg.post("@render:", "use_fixed_fit_projection", { near = -1, far = 1 })
7-
end
8-
9-
local function equal_rng(actual, expected, label_url)
10-
if actual == expected then
11-
label.set_text(label_url, tostring(actual) .. " == " .. tostring(expected))
12-
go.set(label_url, "color", TINT_GREEN)
13-
else
14-
label.set_text(label_url, tostring(actual) .. " ~= " .. tostring(expected))
15-
go.set(label_url, "color", TINT_RED)
16-
end
17-
end
18-
19-
local function almost_equal_rng(actual, expected, label_url)
20-
if math.abs(actual - expected) < EPSILON then
21-
label.set_text(label_url, tostring(actual) .. " == " .. tostring(expected))
22-
go.set(label_url, "color", TINT_GREEN)
23-
else
24-
label.set_text(label_url, tostring(actual) .. " ~= " .. tostring(expected))
25-
go.set(label_url, "color", TINT_RED)
26-
end
27-
end
28-
29-
function update(self, dt)
30-
splitmix64.randomseed(1)
31-
32-
equal_rng(splitmix64.random(1000), 466, "/tests#test1")
33-
equal_rng(splitmix64.random(5, 10000), 4884, "/tests#test2")
34-
almost_equal_rng(splitmix64.random(), 0.9710027535868, "/tests#test3")
35-
equal_rng(splitmix64.random(-1000000, -5000), -952085, "/tests#test4")
36-
equal_rng(splitmix64.random(1), 1, "/tests#test5")
37-
almost_equal_rng(splitmix64.random(), 0.76289439191176, "/tests#test6")
38-
end
1+
local TINT_GREEN = vmath.vector4(0.3, 0.9, 0.3, 1)
2+
local TINT_RED = vmath.vector4(0.9, 0.3, 0.3, 1)
3+
local EPSILON = 0.00001
4+
local html5 = sys.get_sys_info().system_name == "HTML5"
5+
6+
function init(self)
7+
msg.post("@render:", "use_fixed_fit_projection", { near = -1, far = 1 })
8+
end
9+
10+
local function equal_rng(actual, expected, label_url)
11+
if actual == expected then
12+
label.set_text(label_url, tostring(actual) .. " == " .. tostring(expected))
13+
go.set(label_url, "color", TINT_GREEN)
14+
else
15+
label.set_text(label_url, tostring(actual) .. " ~= " .. tostring(expected))
16+
go.set(label_url, "color", TINT_RED)
17+
end
18+
if not html5 then
19+
assert(actual == expected, tostring(actual) .. " ~= " .. tostring(expected))
20+
end
21+
end
22+
23+
local function almost_equal_rng(actual, expected, label_url)
24+
if math.abs(actual - expected) < EPSILON then
25+
label.set_text(label_url, tostring(actual) .. " == " .. tostring(expected))
26+
go.set(label_url, "color", TINT_GREEN)
27+
else
28+
label.set_text(label_url, tostring(actual) .. " ~= " .. tostring(expected))
29+
go.set(label_url, "color", TINT_RED)
30+
end
31+
if not html5 then
32+
assert(math.abs(actual - expected) < EPSILON, tostring(actual) .. " ~= " .. tostring(expected))
33+
end
34+
end
35+
36+
function update(self, dt)
37+
splitmix64.randomseed(1)
38+
39+
equal_rng(splitmix64.random(1000), 466, "/tests#test1")
40+
equal_rng(splitmix64.random(5, 10000), 4884, "/tests#test2")
41+
almost_equal_rng(splitmix64.random(), 0.9710027535868, "/tests#test3")
42+
equal_rng(splitmix64.random(-1000000, -5000), -952085, "/tests#test4")
43+
equal_rng(splitmix64.random(1), 1, "/tests#test5")
44+
almost_equal_rng(splitmix64.random(), 0.76289439191176, "/tests#test6")
45+
end

splitmix64/api/splitmix64.script_api

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,48 @@
2121
parameters:
2222
- name: x
2323
type: number
24+
- name: toss
25+
type: function
26+
desc: Toss a coin. Returns 0 or 1.
27+
returns:
28+
- name: value
29+
type: number
30+
desc: Returns 0 or 1.
31+
- name: dice
32+
type: function
33+
desc: Roll one or more dice of the given type. Returns a table of individual rolls and the total sum.
34+
parameters:
35+
- name: roll
36+
type: number
37+
desc: Number of dice to roll (must be > 0).
38+
- name: type
39+
type: number
40+
desc: Dice type (splitmix64.D4, splitmix64.D6, splitmix64.D8, splitmix64.D10, splitmix64.D12, splitmix64.D20, or splitmix64.D100).
41+
returns:
42+
- name: rolls
43+
type: table
44+
desc: Table of individual roll results.
45+
- name: total
46+
type: number
47+
desc: Sum of all rolls.
48+
- name: D4
49+
type: number
50+
desc: Dice type constant for 4-sided die.
51+
- name: D6
52+
type: number
53+
desc: Dice type constant for 6-sided die.
54+
- name: D8
55+
type: number
56+
desc: Dice type constant for 8-sided die.
57+
- name: D10
58+
type: number
59+
desc: Dice type constant for 10-sided die (0-9).
60+
- name: D12
61+
type: number
62+
desc: Dice type constant for 12-sided die.
63+
- name: D20
64+
type: number
65+
desc: Dice type constant for 20-sided die.
66+
- name: D100
67+
type: number
68+
desc: Dice type constant for percentile die (0, 10, 20, ..., 90).

splitmix64/src/main.cpp

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ static uint64_t next() {
3333

3434
#define MT64_MUL (1.0 / 9007199254740992.0)
3535

36+
static uint64_t bounded_rand(uint64_t n) {
37+
uint64_t r = next();
38+
return r % n;
39+
}
40+
3641
static int Random(lua_State *L) {
3742
lua_Integer low, up;
3843
switch (lua_gettop(L)) { /* check number of arguments */
@@ -61,7 +66,8 @@ static int Random(lua_State *L) {
6166
#else
6267
luaL_argcheck(L, low >= 0 || up <= INT_MAX + low, 1, "interval too large");
6368
#endif
64-
uint64_t i = next() % ((uint64_t)abs(up - low) + 1);
69+
uint64_t n = (uint64_t)abs(up - low) + 1;
70+
uint64_t i = bounded_rand(n);
6571
lua_pushinteger(L, (lua_Integer)i + low);
6672
return 1;
6773
}
@@ -72,9 +78,59 @@ static int RandomSeed(lua_State *L) {
7278
return 0;
7379
}
7480

81+
enum DiceType {
82+
D4 = 4,
83+
D6 = 6,
84+
D8 = 8,
85+
D10 = 10,
86+
D12 = 12,
87+
D20 = 20,
88+
D100 = 100
89+
};
90+
91+
static int Toss(lua_State *L) {
92+
uint64_t r = bounded_rand(2);
93+
lua_pushinteger(L, (lua_Integer)r);
94+
return 1;
95+
}
96+
97+
static int Dice(lua_State *L) {
98+
lua_Integer roll_count = luaL_checkinteger(L, 1);
99+
if (roll_count <= 0) {
100+
return luaL_error(L, "roll must be bigger than 0");
101+
}
102+
lua_Integer type_val = luaL_checkinteger(L, 2);
103+
int type = (int)type_val;
104+
105+
lua_createtable(L, (int)roll_count, (int)roll_count);
106+
int table_idx = lua_gettop(L);
107+
lua_Integer total = 0;
108+
109+
for (lua_Integer i = 0; i < roll_count; ++i) {
110+
lua_Integer num;
111+
if (type == D100) {
112+
num = (lua_Integer)bounded_rand(10) * 10;
113+
} else if (type == D10) {
114+
num = (lua_Integer)bounded_rand(10);
115+
} else if (type == D4 || type == D6 || type == D8 || type == D12 || type == D20) {
116+
num = (lua_Integer)bounded_rand((uint64_t)type) + 1;
117+
} else {
118+
return luaL_error(L, "invalid dice type: %d (use D4, D6, D8, D10, D12, D20, D100)", type);
119+
}
120+
total += num;
121+
lua_pushinteger(L, num);
122+
lua_rawseti(L, table_idx, (int)(i + 1));
123+
}
124+
125+
lua_pushinteger(L, total);
126+
return 2;
127+
}
128+
75129
// Functions exposed to Lua
76130
static const luaL_reg Module_methods[] = {{"random", Random},
77131
{"randomseed", RandomSeed},
132+
{"toss", Toss},
133+
{"dice", Dice},
78134
/* Sentinel: */
79135
{NULL, NULL}};
80136

@@ -84,6 +140,18 @@ static void LuaInit(lua_State *L) {
84140
// Register lua names
85141
luaL_register(L, MODULE_NAME, Module_methods);
86142

143+
#define SETCONSTANT(name) \
144+
lua_pushinteger(L, (lua_Integer)name); \
145+
lua_setfield(L, -2, #name);
146+
SETCONSTANT(D4);
147+
SETCONSTANT(D6);
148+
SETCONSTANT(D8);
149+
SETCONSTANT(D10);
150+
SETCONSTANT(D12);
151+
SETCONSTANT(D20);
152+
SETCONSTANT(D100);
153+
#undef SETCONSTANT
154+
87155
lua_pop(L, 1);
88156
assert(top == lua_gettop(L));
89157
}

0 commit comments

Comments
 (0)