@quenty/randomutils 6.9.0 → 6.9.1
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 +8 -0
- package/package.json +3 -3
- package/src/Shared/RandomSampler.lua +20 -2
- package/src/Shared/RandomUtils.lua +19 -13
- package/src/Shared/WeightedRandomChooser.lua +10 -10
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [6.9.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/randomutils@6.9.0...@quenty/randomutils@6.9.1) (2025-03-21)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @quenty/randomutils
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
6
14
|
# [6.9.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/randomutils@6.8.0...@quenty/randomutils@6.9.0) (2025-02-18)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @quenty/randomutils
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/randomutils",
|
|
3
|
-
"version": "6.9.
|
|
3
|
+
"version": "6.9.1",
|
|
4
4
|
"description": "Quenty's RandomUtils, utility functions for Roblox",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@quenty/loader": "^10.8.0",
|
|
33
|
-
"@quenty/table": "^3.7.
|
|
33
|
+
"@quenty/table": "^3.7.1"
|
|
34
34
|
},
|
|
35
|
-
"gitHead": "
|
|
35
|
+
"gitHead": "6b7c3e15e60cdb185986207b574e2b5591261e7a"
|
|
36
36
|
}
|
|
@@ -10,6 +10,12 @@ local RandomSampler = {}
|
|
|
10
10
|
RandomSampler.ClassName = "RandomSampler"
|
|
11
11
|
RandomSampler.__index = RandomSampler
|
|
12
12
|
|
|
13
|
+
--[=[
|
|
14
|
+
Constructs a new RandomSampler
|
|
15
|
+
|
|
16
|
+
@param samples { T } -- The list of samples to sample from
|
|
17
|
+
@return RandomSampler<T>
|
|
18
|
+
]=]
|
|
13
19
|
function RandomSampler.new(samples)
|
|
14
20
|
local self = setmetatable({}, RandomSampler)
|
|
15
21
|
|
|
@@ -23,6 +29,11 @@ function RandomSampler.new(samples)
|
|
|
23
29
|
return self
|
|
24
30
|
end
|
|
25
31
|
|
|
32
|
+
--[=[
|
|
33
|
+
Sets the samples to sample from
|
|
34
|
+
|
|
35
|
+
@param samples { T } -- The list of samples to sample from
|
|
36
|
+
]=]
|
|
26
37
|
function RandomSampler:SetSamples(samples)
|
|
27
38
|
assert(type(samples) == "table", "Bad samples")
|
|
28
39
|
|
|
@@ -34,6 +45,11 @@ function RandomSampler:SetSamples(samples)
|
|
|
34
45
|
end
|
|
35
46
|
end
|
|
36
47
|
|
|
48
|
+
--[=[
|
|
49
|
+
Samples from the list
|
|
50
|
+
|
|
51
|
+
@return T -- The sample
|
|
52
|
+
]=]
|
|
37
53
|
function RandomSampler:Sample()
|
|
38
54
|
if #self._shuffledAvailableList == 0 then
|
|
39
55
|
self:Refill()
|
|
@@ -45,6 +61,9 @@ function RandomSampler:Sample()
|
|
|
45
61
|
return selection
|
|
46
62
|
end
|
|
47
63
|
|
|
64
|
+
--[=[
|
|
65
|
+
Refills the list
|
|
66
|
+
]=]
|
|
48
67
|
function RandomSampler:Refill()
|
|
49
68
|
local newList = RandomUtils.shuffledCopy(self._optionsList)
|
|
50
69
|
|
|
@@ -58,5 +77,4 @@ function RandomSampler:Refill()
|
|
|
58
77
|
self._shuffledAvailableList = newList
|
|
59
78
|
end
|
|
60
79
|
|
|
61
|
-
|
|
62
|
-
return RandomSampler
|
|
80
|
+
return RandomSampler
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
Utility functions involving random variables. This is quite useful
|
|
3
4
|
for a variety of game mechanics.
|
|
@@ -34,7 +35,7 @@ local RandomUtils = {}
|
|
|
34
35
|
@param random Random? -- Optional
|
|
35
36
|
@return T?
|
|
36
37
|
]=]
|
|
37
|
-
function RandomUtils.choice(list, random)
|
|
38
|
+
function RandomUtils.choice<T>(list: { T }, random: Random?): T?
|
|
38
39
|
if #list == 0 then
|
|
39
40
|
return nil
|
|
40
41
|
elseif #list == 1 then
|
|
@@ -63,7 +64,7 @@ end
|
|
|
63
64
|
@param random Random? -- Optional random to use when shuffling
|
|
64
65
|
@return { T }
|
|
65
66
|
]=]
|
|
66
|
-
function RandomUtils.shuffledCopy(list, random)
|
|
67
|
+
function RandomUtils.shuffledCopy<T>(list: { T }, random: Random?): { T }
|
|
67
68
|
local copy = table.clone(list)
|
|
68
69
|
|
|
69
70
|
RandomUtils.shuffle(copy, random)
|
|
@@ -88,7 +89,7 @@ end
|
|
|
88
89
|
@param list {T}
|
|
89
90
|
@param random Random? -- Optional random to use when shuffling
|
|
90
91
|
]=]
|
|
91
|
-
function RandomUtils.shuffle(list, random)
|
|
92
|
+
function RandomUtils.shuffle<T>(list: { T }, random: Random?)
|
|
92
93
|
if random then
|
|
93
94
|
for i = #list, 2, -1 do
|
|
94
95
|
local j = random:NextInteger(1, i)
|
|
@@ -111,6 +112,10 @@ end
|
|
|
111
112
|
undefined behavior.
|
|
112
113
|
:::
|
|
113
114
|
|
|
115
|
+
:::tip
|
|
116
|
+
See [RandomSampler] for a stateful approach where we remove items from the bag.
|
|
117
|
+
:::
|
|
118
|
+
|
|
114
119
|
```lua
|
|
115
120
|
local weights = { 1, 3, 10 }
|
|
116
121
|
local options = { "a", "b", "c" }
|
|
@@ -123,14 +128,14 @@ end
|
|
|
123
128
|
@param random Random? -- Optional random
|
|
124
129
|
@return T? -- May return nil if the list is empty
|
|
125
130
|
]=]
|
|
126
|
-
function RandomUtils.weightedChoice(list, weights, random)
|
|
131
|
+
function RandomUtils.weightedChoice<T>(list: { T }, weights: { number }, random: Random): T?
|
|
127
132
|
if #list == 0 then
|
|
128
133
|
return nil
|
|
129
134
|
elseif #list == 1 then
|
|
130
135
|
return list[1]
|
|
131
136
|
else
|
|
132
137
|
local total = 0
|
|
133
|
-
for i=1, #list do
|
|
138
|
+
for i = 1, #list do
|
|
134
139
|
assert(type(weights[i]) == "number", "Bad weights")
|
|
135
140
|
total = total + weights[i]
|
|
136
141
|
end
|
|
@@ -144,12 +149,12 @@ function RandomUtils.weightedChoice(list, weights, random)
|
|
|
144
149
|
|
|
145
150
|
local totalSum = 0
|
|
146
151
|
|
|
147
|
-
for i=1, #list do
|
|
152
|
+
for i = 1, #list do
|
|
148
153
|
if weights[i] == 0 then
|
|
149
154
|
continue
|
|
150
155
|
end
|
|
151
156
|
totalSum = totalSum + weights[i]
|
|
152
|
-
local threshold = totalSum/total
|
|
157
|
+
local threshold = totalSum / total
|
|
153
158
|
if randomNum <= threshold then
|
|
154
159
|
return list[i]
|
|
155
160
|
end
|
|
@@ -167,28 +172,29 @@ end
|
|
|
167
172
|
@param random Random? -- Optional random to use
|
|
168
173
|
@return number
|
|
169
174
|
]=]
|
|
170
|
-
function RandomUtils.gaussianRandom(random)
|
|
175
|
+
function RandomUtils.gaussianRandom(random: Random?): number
|
|
171
176
|
local a, t
|
|
172
177
|
if random then
|
|
173
|
-
a = 2*math.pi*random:NextNumber()
|
|
178
|
+
a = 2 * math.pi * random:NextNumber()
|
|
174
179
|
t = random:NextNumber()
|
|
175
180
|
else
|
|
176
|
-
a = 2*math.pi*math.random()
|
|
181
|
+
a = 2 * math.pi * math.random()
|
|
177
182
|
t = math.random()
|
|
178
183
|
end
|
|
179
184
|
|
|
180
|
-
return math.sqrt(-2*math.log(1 - t))*math.cos(a)
|
|
185
|
+
return math.sqrt(-2 * math.log(1 - t)) * math.cos(a)
|
|
181
186
|
end
|
|
182
187
|
|
|
183
188
|
--[=[
|
|
184
189
|
@param random? Random? -- Optional random to use
|
|
185
190
|
@return Vector3
|
|
186
191
|
]=]
|
|
187
|
-
function RandomUtils.randomUnitVector3(random)
|
|
192
|
+
function RandomUtils.randomUnitVector3(random: Random?): Vector3
|
|
188
193
|
return Vector3.new(
|
|
189
194
|
RandomUtils.gaussianRandom(random),
|
|
190
195
|
RandomUtils.gaussianRandom(random),
|
|
191
|
-
RandomUtils.gaussianRandom(random)
|
|
196
|
+
RandomUtils.gaussianRandom(random)
|
|
197
|
+
)
|
|
192
198
|
end
|
|
193
199
|
|
|
194
200
|
return RandomUtils
|
|
@@ -57,7 +57,7 @@ end
|
|
|
57
57
|
@param option T
|
|
58
58
|
@return number | nil
|
|
59
59
|
]=]
|
|
60
|
-
function WeightedRandomChooser:GetWeight(option)
|
|
60
|
+
function WeightedRandomChooser:GetWeight(option): number?
|
|
61
61
|
return self._optionToWeight[option]
|
|
62
62
|
end
|
|
63
63
|
|
|
@@ -67,14 +67,14 @@ end
|
|
|
67
67
|
@param option T
|
|
68
68
|
@return number | nil
|
|
69
69
|
]=]
|
|
70
|
-
function WeightedRandomChooser:GetProbability(option)
|
|
70
|
+
function WeightedRandomChooser:GetProbability(option): number?
|
|
71
71
|
local weight = self._optionToWeight[option]
|
|
72
72
|
if weight then
|
|
73
73
|
return nil
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
local cache = self:_getOrCreateDataCache()
|
|
77
|
-
return weight/cache.total
|
|
77
|
+
return weight / cache.total
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
--[=[
|
|
@@ -83,7 +83,7 @@ end
|
|
|
83
83
|
@param random Random
|
|
84
84
|
@return T
|
|
85
85
|
]=]
|
|
86
|
-
function WeightedRandomChooser:Choose(random)
|
|
86
|
+
function WeightedRandomChooser:Choose(random: Random?)
|
|
87
87
|
local data = self:_getOrCreateDataCache()
|
|
88
88
|
|
|
89
89
|
local randomNum
|
|
@@ -96,11 +96,11 @@ function WeightedRandomChooser:Choose(random)
|
|
|
96
96
|
local totalSum = 0
|
|
97
97
|
|
|
98
98
|
-- TODO: Binary search
|
|
99
|
-
for i=1, #data.options do
|
|
99
|
+
for i = 1, #data.options do
|
|
100
100
|
totalSum = totalSum + data.weights[i]
|
|
101
101
|
|
|
102
102
|
-- TODO: cache threshold?
|
|
103
|
-
local threshold = totalSum/data.total
|
|
103
|
+
local threshold = totalSum / data.total
|
|
104
104
|
if randomNum <= threshold then
|
|
105
105
|
return data.options[i]
|
|
106
106
|
end
|
|
@@ -126,11 +126,11 @@ function WeightedRandomChooser:_getOrCreateDataCache()
|
|
|
126
126
|
end
|
|
127
127
|
|
|
128
128
|
self._cache = {
|
|
129
|
-
options = options
|
|
130
|
-
weights = weights
|
|
131
|
-
total = total
|
|
129
|
+
options = options,
|
|
130
|
+
weights = weights,
|
|
131
|
+
total = total,
|
|
132
132
|
}
|
|
133
133
|
return self._cache
|
|
134
134
|
end
|
|
135
135
|
|
|
136
|
-
return WeightedRandomChooser
|
|
136
|
+
return WeightedRandomChooser
|