@pkmn/engine 0.1.0-dev.c5fe6d07 → 0.1.0-dev.ce4c0b2a
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/LICENSE +1 -3
- package/README.md +46 -19
- package/build/pkg/addon/browser.d.ts +3 -0
- package/build/pkg/addon/browser.js +43 -0
- package/build/pkg/addon/browser.js.map +1 -0
- package/build/pkg/addon/node.d.ts +3 -0
- package/build/pkg/addon/node.js +96 -0
- package/build/pkg/addon/node.js.map +1 -0
- package/build/pkg/addon.d.ts +2 -0
- package/build/pkg/addon.js +35 -58
- package/build/pkg/addon.js.map +1 -1
- package/build/pkg/data/ids.json +12 -12
- package/build/pkg/data/layout.json +2 -2
- package/build/pkg/data/protocol.json +69 -12
- package/build/pkg/data.d.ts +27 -5
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.js +3 -3
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +24 -10
- package/build/pkg/index.js +15 -10
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.d.ts +20 -1
- package/build/pkg/protocol.js +123 -102
- package/build/pkg/protocol.js.map +1 -1
- package/build/tools/debug.js +36 -68
- package/build/tools/debug.js.map +1 -1
- package/build/tools/display/debug.jsx +128 -0
- package/build/tools/display/debug.jsx.map +1 -0
- package/build/tools/display/index.js +132 -0
- package/build/tools/display/index.js.map +1 -0
- package/build/tools/display/ui.jsx +349 -0
- package/build/tools/display/ui.jsx.map +1 -0
- package/build/tools/display/util.js +18 -0
- package/build/tools/display/util.js.map +1 -0
- package/build.zig +230 -99
- package/package.json +63 -30
- package/src/bin/install-pkmn-engine +29 -19
- package/src/bin/pkmn-debug +1 -1
- package/src/lib/common/array.zig +77 -0
- package/src/lib/common/data.zig +12 -24
- package/src/lib/common/debug.zig +11 -6
- package/src/lib/common/js.zig +4 -2
- package/src/lib/common/optional.zig +21 -10
- package/src/lib/common/options.zig +4 -0
- package/src/lib/common/protocol.zig +807 -327
- package/src/lib/common/rational.zig +125 -31
- package/src/lib/common/rng.zig +22 -13
- package/src/lib/common/util.zig +50 -1
- package/src/lib/gen1/calc.zig +660 -137
- package/src/lib/gen1/chance.zig +409 -284
- package/src/lib/gen1/data/moves.zig +192 -180
- package/src/lib/gen1/data/species.zig +3 -3
- package/src/lib/gen1/data/types.zig +7 -7
- package/src/lib/gen1/data.zig +48 -59
- package/src/lib/gen1/helpers.zig +94 -552
- package/src/lib/gen1/mechanics.zig +580 -518
- package/src/lib/gen2/calc.zig +161 -0
- package/src/lib/gen2/chance.zig +902 -0
- package/src/lib/gen2/data/items.zig +12 -18
- package/src/lib/gen2/data/moves.zig +663 -569
- package/src/lib/gen2/data/species.zig +1 -1
- package/src/lib/gen2/data/types.zig +134 -31
- package/src/lib/gen2/data.zig +107 -79
- package/src/lib/gen2/generated.zig +806 -0
- package/src/lib/gen2/helpers.zig +49 -25
- package/src/lib/gen2/mechanics.zig +3560 -12
- package/src/lib/{binding/node.zig → node.zig} +10 -13
- package/src/lib/pkmn.zig +32 -15
- package/src/lib/{binding/wasm.zig → wasm.zig} +2 -1
- package/src/tools/display/dom.ts +96 -0
- package/src/tools/display/ui.css +351 -0
- package/build/test/display.js +0 -400
- package/build/test/display.js.map +0 -1
- package/src/lib/gen1/README.md +0 -892
- package/src/lib/gen2/README.md +0 -308
- package/src/test/display/pkmn.html.tmpl +0 -368
|
@@ -6,6 +6,13 @@ const expect = std.testing.expect;
|
|
|
6
6
|
const expectEqual = std.testing.expectEqual;
|
|
7
7
|
const expectError = std.testing.expectError;
|
|
8
8
|
|
|
9
|
+
const Int = if (@hasField(std.builtin.Type, "int")) .int else .Int;
|
|
10
|
+
const Float = if (@hasField(std.builtin.Type, "float")) .float else .Float;
|
|
11
|
+
const ComptimeInt =
|
|
12
|
+
if (@hasField(std.builtin.Type, "comptime_int")) .comptime_int else .ComptimeInt;
|
|
13
|
+
const ComptimeFloat =
|
|
14
|
+
if (@hasField(std.builtin.Type, "comptime_float")) .comptime_float else .ComptimeFloat;
|
|
15
|
+
|
|
9
16
|
/// Specialization of a rational number used by the engine to compute probabilties.
|
|
10
17
|
/// For performance reasons the rational is only reduced lazily and thus `reduce` must be
|
|
11
18
|
/// invoked explicitly before reading.
|
|
@@ -22,15 +29,15 @@ pub fn Rational(comptime T: type) type {
|
|
|
22
29
|
// start reducing when we get sufficiently close to the limit of the mantissa (in our domain
|
|
23
30
|
// we expect updates to involve numbers < 2**10, so we should be safe not reducing before we
|
|
24
31
|
// are 2**10 away from "overflowing" the mantissa)
|
|
25
|
-
const REDUCE = if (@typeInfo(T) ==
|
|
32
|
+
const REDUCE = if (@typeInfo(T) == Float)
|
|
26
33
|
std.math.pow(T, 2, std.math.floatMantissaBits(T) - 10)
|
|
27
34
|
else
|
|
28
35
|
0;
|
|
29
36
|
|
|
30
37
|
/// Possible error returned by operations on the Rational.
|
|
31
38
|
pub const Error = switch (@typeInfo(T)) {
|
|
32
|
-
|
|
33
|
-
|
|
39
|
+
Int => error{Overflow},
|
|
40
|
+
Float => error{},
|
|
34
41
|
else => unreachable,
|
|
35
42
|
};
|
|
36
43
|
|
|
@@ -43,20 +50,19 @@ pub fn Rational(comptime T: type) type {
|
|
|
43
50
|
/// Update the rational by multiplying its numerator by p and its denominator by q.
|
|
44
51
|
/// Both p and q must be >= 1, and if computable at comptime must have no common factors.
|
|
45
52
|
pub fn update(r: *Self, p: anytype, q: anytype) Error!void {
|
|
46
|
-
//
|
|
47
|
-
// std.debug.print("({d}/{d}) * ", .{p, q});
|
|
53
|
+
// std.debug.print("({d}/{d}) * ", .{ p, q }); // DEBUG
|
|
48
54
|
assert(p >= 1);
|
|
49
55
|
assert(q >= 1);
|
|
50
56
|
|
|
51
57
|
// If our parameters are not fully reduced they may prematurely
|
|
52
58
|
// cause overflow/loss of precision after the multiplication below
|
|
53
59
|
assert(switch (@typeInfo(@TypeOf(p, q))) {
|
|
54
|
-
|
|
60
|
+
ComptimeInt, ComptimeFloat => comptime gcd(p, q),
|
|
55
61
|
else => 1,
|
|
56
62
|
} == 1);
|
|
57
63
|
|
|
58
64
|
switch (@typeInfo(T)) {
|
|
59
|
-
|
|
65
|
+
Int => {
|
|
60
66
|
// Greedily attempt to multiply and if it fails, reduce and try again
|
|
61
67
|
r.multiplication(p, q) catch |err| switch (err) {
|
|
62
68
|
error.Overflow => {
|
|
@@ -66,16 +72,16 @@ pub fn Rational(comptime T: type) type {
|
|
|
66
72
|
else => unreachable,
|
|
67
73
|
};
|
|
68
74
|
},
|
|
69
|
-
|
|
75
|
+
Float => {
|
|
70
76
|
// Reduce in situations where we're likely to start losing precision
|
|
71
77
|
if (r.q > REDUCE or r.p > REDUCE) r.reduce();
|
|
72
78
|
|
|
73
79
|
r.p *= switch (@typeInfo(@TypeOf(p))) {
|
|
74
|
-
|
|
80
|
+
Float, ComptimeFloat => p,
|
|
75
81
|
else => @floatFromInt(p),
|
|
76
82
|
};
|
|
77
83
|
r.q *= switch (@typeInfo(@TypeOf(q))) {
|
|
78
|
-
|
|
84
|
+
Float, ComptimeFloat => q,
|
|
79
85
|
else => @floatFromInt(q),
|
|
80
86
|
};
|
|
81
87
|
|
|
@@ -90,7 +96,7 @@ pub fn Rational(comptime T: type) type {
|
|
|
90
96
|
/// Add two rationals using the identity (a/b) + (c/d) = (ad+bc)/(bd).
|
|
91
97
|
pub fn add(r: *Self, s: *Self) Error!void {
|
|
92
98
|
switch (@typeInfo(T)) {
|
|
93
|
-
|
|
99
|
+
Int => {
|
|
94
100
|
if (r.q == s.q) {
|
|
95
101
|
r.p = std.math.add(T, r.p, s.p) catch |err| switch (err) {
|
|
96
102
|
error.Overflow => val: {
|
|
@@ -111,7 +117,7 @@ pub fn Rational(comptime T: type) type {
|
|
|
111
117
|
};
|
|
112
118
|
}
|
|
113
119
|
},
|
|
114
|
-
|
|
120
|
+
Float => {
|
|
115
121
|
if (r.q == s.q) {
|
|
116
122
|
if (r.p > REDUCE) r.reduce();
|
|
117
123
|
if (s.p > REDUCE) s.reduce();
|
|
@@ -136,7 +142,7 @@ pub fn Rational(comptime T: type) type {
|
|
|
136
142
|
/// Multiplies two rationals.
|
|
137
143
|
pub fn mul(r: *Self, s: *Self) Error!void {
|
|
138
144
|
switch (@typeInfo(T)) {
|
|
139
|
-
|
|
145
|
+
Int => {
|
|
140
146
|
r.multiplication(s.p, s.q) catch |err| switch (err) {
|
|
141
147
|
error.Overflow => {
|
|
142
148
|
r.reduce();
|
|
@@ -146,7 +152,7 @@ pub fn Rational(comptime T: type) type {
|
|
|
146
152
|
else => unreachable,
|
|
147
153
|
};
|
|
148
154
|
},
|
|
149
|
-
|
|
155
|
+
Float => {
|
|
150
156
|
if (r.q > REDUCE or r.p > REDUCE) r.reduce();
|
|
151
157
|
if (s.q > REDUCE or s.p > REDUCE) s.reduce();
|
|
152
158
|
|
|
@@ -185,16 +191,16 @@ pub fn Rational(comptime T: type) type {
|
|
|
185
191
|
try writer.print("{d}/{d}", .{ self.p, self.q });
|
|
186
192
|
}
|
|
187
193
|
|
|
188
|
-
|
|
194
|
+
fn multiplication(r: *Self, p: anytype, q: anytype) !void {
|
|
189
195
|
r.p = try std.math.mul(T, r.p, p);
|
|
190
196
|
r.q = try std.math.mul(T, r.q, q);
|
|
191
197
|
}
|
|
192
198
|
|
|
193
|
-
|
|
199
|
+
fn addition(r: *Self, p: anytype, q: anytype) !void {
|
|
194
200
|
// (a/b) + (c/d) = (ad+bc)/(bd)
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
201
|
+
const d = try std.math.mul(T, r.q, q);
|
|
202
|
+
const n1 = try std.math.mul(T, r.p, q);
|
|
203
|
+
const n2 = try std.math.mul(T, r.q, p);
|
|
198
204
|
|
|
199
205
|
r.p = try std.math.add(T, n1, n2);
|
|
200
206
|
r.q = d;
|
|
@@ -202,23 +208,74 @@ pub fn Rational(comptime T: type) type {
|
|
|
202
208
|
};
|
|
203
209
|
}
|
|
204
210
|
|
|
205
|
-
|
|
206
|
-
inline fn gcd(p: anytype, q: anytype) @TypeOf(p, q) {
|
|
211
|
+
fn gcd(p: anytype, q: anytype) @TypeOf(p, q) {
|
|
207
212
|
assert(p >= 1);
|
|
208
213
|
assert(q >= 1);
|
|
209
214
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
215
|
+
// convert comptime_int to a sized integer within this function so that @ctz will work
|
|
216
|
+
const T = switch (@TypeOf(p, q)) {
|
|
217
|
+
comptime_int => std.math.IntFittingRange(@min(p, q), @max(p, q)),
|
|
218
|
+
else => |U| U,
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
switch (@typeInfo(T)) {
|
|
222
|
+
Int => {
|
|
223
|
+
// std.math.gcd but without some checks because we have a stricter range
|
|
224
|
+
var x: T = @intCast(p);
|
|
225
|
+
var y: T = @intCast(q);
|
|
226
|
+
|
|
227
|
+
const xz = @ctz(x);
|
|
228
|
+
const yz = @ctz(y);
|
|
229
|
+
const shift = @min(xz, yz);
|
|
230
|
+
x >>= @intCast(xz);
|
|
231
|
+
y >>= @intCast(yz);
|
|
232
|
+
|
|
233
|
+
var diff = y -% x;
|
|
234
|
+
while (diff != 0) : (diff = y -% x) {
|
|
235
|
+
const zeros = @ctz(diff);
|
|
236
|
+
if (x > y) diff = -%diff;
|
|
237
|
+
y = @min(x, y);
|
|
238
|
+
x = diff >> @intCast(zeros);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const result = y << @intCast(shift);
|
|
242
|
+
assert(result > 0);
|
|
243
|
+
return result;
|
|
244
|
+
},
|
|
245
|
+
else => {
|
|
246
|
+
var a = p;
|
|
247
|
+
var b = q;
|
|
248
|
+
var c: T = undefined;
|
|
249
|
+
|
|
250
|
+
while (b != 0) {
|
|
251
|
+
c = b;
|
|
252
|
+
b = @mod(a, b);
|
|
253
|
+
a = c;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
assert(a > 0);
|
|
257
|
+
return a;
|
|
258
|
+
},
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
test gcd {
|
|
263
|
+
const seed = if (@hasDecl(std.testing, "random_seed")) std.testing.random_seed else 0x12345678;
|
|
264
|
+
var prng = (if (@hasDecl(std, "Random")) std.Random else std.rand).DefaultPrng.init(seed);
|
|
265
|
+
var random = prng.random();
|
|
266
|
+
|
|
267
|
+
for (0..1000) |_| {
|
|
268
|
+
const a = random.int(u32);
|
|
269
|
+
const b = random.int(u32);
|
|
270
|
+
if (a == 0 or b == 0) continue;
|
|
213
271
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
272
|
+
try expectEqual(
|
|
273
|
+
gcd(a, b),
|
|
274
|
+
@as(u32, @intFromFloat(gcd(@as(f64, @floatFromInt(a)), @as(f64, @floatFromInt(b))))),
|
|
275
|
+
);
|
|
218
276
|
}
|
|
219
277
|
|
|
220
|
-
|
|
221
|
-
return a;
|
|
278
|
+
try expectEqual(gcd(300_000, @as(u32, 2_300_000)), 100_000); // NB: @ctz requires an @intCast
|
|
222
279
|
}
|
|
223
280
|
|
|
224
281
|
fn doTurn(r: anytype) !void {
|
|
@@ -234,6 +291,8 @@ test Rational {
|
|
|
234
291
|
var r: Rational(t) = .{};
|
|
235
292
|
|
|
236
293
|
var c: t = 128;
|
|
294
|
+
_ = &c;
|
|
295
|
+
|
|
237
296
|
try r.update(c, 256);
|
|
238
297
|
try doTurn(&r);
|
|
239
298
|
|
|
@@ -275,7 +334,7 @@ pub const BigRational = struct {
|
|
|
275
334
|
/// Create a new BigRational wrapper. A small amount of memory will be allocated on
|
|
276
335
|
/// initialization. Not default initialized to 1 - you must explicitly `reset` first.
|
|
277
336
|
pub fn init(alloc: std.mem.Allocator) !BigRational {
|
|
278
|
-
return
|
|
337
|
+
return .{ .val = try std.math.big.Rational.init(alloc) };
|
|
279
338
|
}
|
|
280
339
|
|
|
281
340
|
/// Frees all memory associated with a rational.
|
|
@@ -320,6 +379,8 @@ test BigRational {
|
|
|
320
379
|
try r.reset();
|
|
321
380
|
|
|
322
381
|
var c: u8 = 128;
|
|
382
|
+
_ = &c;
|
|
383
|
+
|
|
323
384
|
try r.update(c, 256);
|
|
324
385
|
try doTurn(&r);
|
|
325
386
|
|
|
@@ -351,3 +412,36 @@ test BigRational {
|
|
|
351
412
|
try s.setRatio(71, 78);
|
|
352
413
|
try expect((try s.order(r.val)) == .eq);
|
|
353
414
|
}
|
|
415
|
+
|
|
416
|
+
test "minimum" {
|
|
417
|
+
// TODO: ziglang/zig#21069
|
|
418
|
+
if (builtin.mode == .ReleaseFast or builtin.mode == .ReleaseSmall) {
|
|
419
|
+
return error.SkipZigTest;
|
|
420
|
+
}
|
|
421
|
+
var r = try BigRational.init(std.testing.allocator);
|
|
422
|
+
defer r.deinit();
|
|
423
|
+
var s = try std.math.big.Rational.init(std.testing.allocator);
|
|
424
|
+
defer s.deinit();
|
|
425
|
+
|
|
426
|
+
try r.reset();
|
|
427
|
+
|
|
428
|
+
try r.update(1, 2); // Speed Tie
|
|
429
|
+
for (0..2) |_| {
|
|
430
|
+
try r.update(1, 2); // Confusion
|
|
431
|
+
try r.update(1, 2); // Infatuation
|
|
432
|
+
try r.update(3, 4); // Paralysis
|
|
433
|
+
// Population Bomb
|
|
434
|
+
for (0..10) |_| {
|
|
435
|
+
try r.update(9, 10); // Accuracy
|
|
436
|
+
try r.update(1, 15); // Damage roll
|
|
437
|
+
try r.update(1, 24); // Critical Hit
|
|
438
|
+
try r.update(9, 10); // King's Rock non-proc
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const ZEROS = std.math.pow(u310, 10, 31);
|
|
443
|
+
const n = 36472996377170786403;
|
|
444
|
+
const d: u310 = 146267071761884981524886149560653378220687632500762654519853056 * ZEROS;
|
|
445
|
+
try s.setRatio(n, d);
|
|
446
|
+
try expect((try s.order(r.val)) == .eq);
|
|
447
|
+
}
|
package/src/lib/common/rng.zig
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const std = @import("std");
|
|
2
2
|
|
|
3
|
-
const options = @import("
|
|
3
|
+
const options = @import("options.zig");
|
|
4
4
|
|
|
5
5
|
const assert = std.debug.assert;
|
|
6
6
|
const expectEqual = std.testing.expectEqual;
|
|
@@ -25,6 +25,11 @@ pub fn PRNG(comptime gen: comptime_int) type {
|
|
|
25
25
|
pub fn next(self: *Self) Output(gen) {
|
|
26
26
|
return self.src.next();
|
|
27
27
|
}
|
|
28
|
+
|
|
29
|
+
pub fn advance(self: *Self, n: usize) void {
|
|
30
|
+
if (!options.advance) return;
|
|
31
|
+
for (0..n) |_| self.src.advance();
|
|
32
|
+
}
|
|
28
33
|
};
|
|
29
34
|
}
|
|
30
35
|
|
|
@@ -61,10 +66,14 @@ pub const PSRNG = extern struct {
|
|
|
61
66
|
(@as(u64, self.range(u16, 0, 0x10000)) << 16) |
|
|
62
67
|
(@as(u64, self.range(u16, 0, 0x10000)));
|
|
63
68
|
}
|
|
69
|
+
|
|
70
|
+
pub fn Bound(comptime T: type) type {
|
|
71
|
+
return std.math.IntFittingRange(0, std.math.maxInt(T) + 1);
|
|
72
|
+
}
|
|
64
73
|
};
|
|
65
74
|
|
|
66
75
|
test PSRNG {
|
|
67
|
-
var psrng =
|
|
76
|
+
var psrng: PSRNG = .{ .src = .{ .seed = 0x0001000200030004 } };
|
|
68
77
|
try expectEqual(@as(u8, 121), psrng.range(u8, 0, 256));
|
|
69
78
|
try expectEqual(false, psrng.chance(u8, 128, 256)); // 226 < 128
|
|
70
79
|
}
|
|
@@ -79,7 +88,7 @@ pub const Gen12 = extern struct {
|
|
|
79
88
|
assert(@sizeOf(Gen12) == 10);
|
|
80
89
|
}
|
|
81
90
|
|
|
82
|
-
pub fn percent(p:
|
|
91
|
+
pub fn percent(comptime p: comptime_int) u8 {
|
|
83
92
|
return @intCast((@as(u16, p) * 0xFF) / 100);
|
|
84
93
|
}
|
|
85
94
|
|
|
@@ -89,11 +98,15 @@ pub const Gen12 = extern struct {
|
|
|
89
98
|
self.index = (self.index + 1) % 9;
|
|
90
99
|
return val;
|
|
91
100
|
}
|
|
101
|
+
|
|
102
|
+
pub fn advance(self: *Gen12) void {
|
|
103
|
+
_ = self.next();
|
|
104
|
+
}
|
|
92
105
|
};
|
|
93
106
|
|
|
94
107
|
test Gen12 {
|
|
95
108
|
const expected = [_]u8{ 6, 11, 16, 21, 26, 31, 36, 41, 46, 31, 56, 81 };
|
|
96
|
-
var rng =
|
|
109
|
+
var rng: Gen12 = .{ .seed = .{ 1, 2, 3, 4, 5, 6, 7, 8, 9 } };
|
|
97
110
|
for (expected) |e| {
|
|
98
111
|
try expectEqual(e, rng.next());
|
|
99
112
|
}
|
|
@@ -129,7 +142,7 @@ test Gen34 {
|
|
|
129
142
|
.{ 0x80000000, 5, 0x0E425287 }, .{ 0x80000000, 10, 0x6F2CF4B2 },
|
|
130
143
|
};
|
|
131
144
|
for (data) |d| {
|
|
132
|
-
var rng =
|
|
145
|
+
var rng: Gen34 = .{ .seed = d[0] };
|
|
133
146
|
for (0..d[1]) |_| _ = rng.next();
|
|
134
147
|
try expectEqual(d[2], rng.seed);
|
|
135
148
|
}
|
|
@@ -161,7 +174,7 @@ test Gen56 {
|
|
|
161
174
|
.{ 0x8000000000000000, 10, 0xE7795501267F125A },
|
|
162
175
|
};
|
|
163
176
|
for (data) |d| {
|
|
164
|
-
var rng =
|
|
177
|
+
var rng: Gen56 = .{ .seed = d[0] };
|
|
165
178
|
for (0..d[1]) |_| _ = rng.next();
|
|
166
179
|
try expectEqual(d[2], rng.seed);
|
|
167
180
|
}
|
|
@@ -188,7 +201,7 @@ pub fn FixedRNG(comptime gen: comptime_int, comptime len: usize) type {
|
|
|
188
201
|
for (0..n) |_| _ = self.next();
|
|
189
202
|
}
|
|
190
203
|
|
|
191
|
-
pub fn range(self: *Self, comptime T: type, from: T, to: Bound(T)) T {
|
|
204
|
+
pub fn range(self: *Self, comptime T: type, from: T, to: PSRNG.Bound(T)) T {
|
|
192
205
|
assert(showdown);
|
|
193
206
|
return @intCast(@as(u64, self.next()) * (to - from) / divisor + from);
|
|
194
207
|
}
|
|
@@ -197,7 +210,7 @@ pub fn FixedRNG(comptime gen: comptime_int, comptime len: usize) type {
|
|
|
197
210
|
self: *Self,
|
|
198
211
|
comptime T: type,
|
|
199
212
|
numerator: T,
|
|
200
|
-
denominator: Bound(T),
|
|
213
|
+
denominator: PSRNG.Bound(T),
|
|
201
214
|
) bool {
|
|
202
215
|
assert(showdown);
|
|
203
216
|
assert(denominator > 0);
|
|
@@ -213,7 +226,7 @@ pub fn FixedRNG(comptime gen: comptime_int, comptime len: usize) type {
|
|
|
213
226
|
test FixedRNG {
|
|
214
227
|
const Type = if (showdown) u32 else u8;
|
|
215
228
|
const expected = [_]Type{ 42, 255, 0 };
|
|
216
|
-
var rng
|
|
229
|
+
var rng: FixedRNG(1, expected.len) = .{ .rolls = expected };
|
|
217
230
|
for (expected) |e| {
|
|
218
231
|
try expectEqual(e, rng.next());
|
|
219
232
|
}
|
|
@@ -228,7 +241,3 @@ fn Output(comptime gen: comptime_int) type {
|
|
|
228
241
|
else => unreachable,
|
|
229
242
|
};
|
|
230
243
|
}
|
|
231
|
-
|
|
232
|
-
fn Bound(comptime T: type) type {
|
|
233
|
-
return std.math.IntFittingRange(0, std.math.maxInt(T) + 1);
|
|
234
|
-
}
|
package/src/lib/common/util.zig
CHANGED
|
@@ -1,12 +1,61 @@
|
|
|
1
1
|
const std = @import("std");
|
|
2
2
|
|
|
3
|
+
const expect = std.testing.expect;
|
|
3
4
|
const expectEqual = std.testing.expectEqual;
|
|
4
5
|
|
|
6
|
+
const Pointer = if (@hasField(std.builtin.Type, "pointer")) .pointer else .Pointer;
|
|
7
|
+
|
|
5
8
|
pub fn PointerType(comptime P: type, comptime C: type) type {
|
|
6
|
-
return if (@typeInfo(P)
|
|
9
|
+
return if (@field(@typeInfo(P), @tagName(Pointer)).is_const) *const C else *C;
|
|
7
10
|
}
|
|
8
11
|
|
|
9
12
|
test PointerType {
|
|
10
13
|
try expectEqual(*bool, PointerType(*u8, bool));
|
|
11
14
|
try expectEqual(*const f64, PointerType(*const i32, f64));
|
|
12
15
|
}
|
|
16
|
+
|
|
17
|
+
pub fn isPointerTo(p: anytype, comptime P: type) bool {
|
|
18
|
+
const info = @typeInfo(@TypeOf(p));
|
|
19
|
+
return switch (info) {
|
|
20
|
+
Pointer => @field(info, @tagName(Pointer)).child == P,
|
|
21
|
+
else => false,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
test isPointerTo {
|
|
26
|
+
const S = struct {};
|
|
27
|
+
const s: S = .{};
|
|
28
|
+
try expect(!isPointerTo(s, S));
|
|
29
|
+
try expect(isPointerTo(&s, S));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// NOTE: std.mem.bytesAsValue backported from ziglang/zig#18061
|
|
33
|
+
pub fn bytesAsValue(comptime T: type, bytes: anytype) BytesAsValueReturnType(T, @TypeOf(bytes)) {
|
|
34
|
+
return @as(BytesAsValueReturnType(T, @TypeOf(bytes)), @ptrCast(bytes));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
fn BytesAsValueReturnType(comptime T: type, comptime B: type) type {
|
|
38
|
+
return CopyPtrAttrs(B, .One, T);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
fn CopyPtrAttrs(
|
|
42
|
+
comptime source: type,
|
|
43
|
+
comptime size: std.builtin.Type.Pointer.Size,
|
|
44
|
+
comptime child: type,
|
|
45
|
+
) type {
|
|
46
|
+
const info = @field(@typeInfo(source), @tagName(Pointer));
|
|
47
|
+
const args = .{
|
|
48
|
+
.size = size,
|
|
49
|
+
.is_const = info.is_const,
|
|
50
|
+
.is_volatile = info.is_volatile,
|
|
51
|
+
.is_allowzero = info.is_allowzero,
|
|
52
|
+
.alignment = info.alignment,
|
|
53
|
+
.address_space = info.address_space,
|
|
54
|
+
.child = child,
|
|
55
|
+
.sentinel = null,
|
|
56
|
+
};
|
|
57
|
+
return @Type(if (@hasField(std.builtin.Type, "pointer"))
|
|
58
|
+
.{ .pointer = args }
|
|
59
|
+
else
|
|
60
|
+
.{ .Pointer = args });
|
|
61
|
+
}
|