@pkmn/engine 0.1.0-dev.c5fe6d07 → 0.1.0-dev.d1b39ff0
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 +44 -19
- package/build/pkg/addon.js +6 -7
- 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 +4 -4
- package/build/pkg/data.js.map +1 -1
- package/build/pkg/gen1.js +2 -2
- package/build/pkg/gen1.js.map +1 -1
- package/build/pkg/index.d.ts +3 -2
- package/build/pkg/index.js.map +1 -1
- package/build/pkg/protocol.js +61 -42
- package/build/pkg/protocol.js.map +1 -1
- package/build/test/display.js +8 -3
- package/build/test/display.js.map +1 -1
- package/build/tools/debug.js +5 -4
- package/build/tools/debug.js.map +1 -1
- package/build.zig +105 -107
- package/package.json +43 -23
- package/src/bin/install-pkmn-engine +26 -18
- package/src/lib/common/data.zig +12 -24
- package/src/lib/common/debug.zig +2 -2
- package/src/lib/common/optional.zig +9 -2
- package/src/lib/common/options.zig +2 -0
- package/src/lib/common/protocol.zig +802 -327
- package/src/lib/common/rational.zig +120 -19
- package/src/lib/common/rng.zig +26 -17
- package/src/lib/gen1/calc.zig +507 -132
- package/src/lib/gen1/chance.zig +401 -286
- 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 +50 -62
- package/src/lib/gen1/helpers.zig +89 -548
- package/src/lib/gen1/mechanics.zig +569 -514
- package/src/lib/gen2/calc.zig +135 -0
- package/src/lib/gen2/chance.zig +895 -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 +106 -79
- package/src/lib/gen2/generated.zig +806 -0
- package/src/lib/gen2/helpers.zig +45 -19
- package/src/lib/gen2/mechanics.zig +3564 -9
- 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/test/display/pkmn.html.tmpl +5 -5
- package/src/lib/gen1/README.md +0 -892
- package/src/lib/gen2/README.md +0 -308
|
@@ -43,8 +43,7 @@ pub fn Rational(comptime T: type) type {
|
|
|
43
43
|
/// Update the rational by multiplying its numerator by p and its denominator by q.
|
|
44
44
|
/// Both p and q must be >= 1, and if computable at comptime must have no common factors.
|
|
45
45
|
pub fn update(r: *Self, p: anytype, q: anytype) Error!void {
|
|
46
|
-
//
|
|
47
|
-
// std.debug.print("({d}/{d}) * ", .{p, q});
|
|
46
|
+
// std.debug.print("({d}/{d}) * ", .{ p, q }); // DEBUG
|
|
48
47
|
assert(p >= 1);
|
|
49
48
|
assert(q >= 1);
|
|
50
49
|
|
|
@@ -185,16 +184,16 @@ pub fn Rational(comptime T: type) type {
|
|
|
185
184
|
try writer.print("{d}/{d}", .{ self.p, self.q });
|
|
186
185
|
}
|
|
187
186
|
|
|
188
|
-
|
|
187
|
+
fn multiplication(r: *Self, p: anytype, q: anytype) !void {
|
|
189
188
|
r.p = try std.math.mul(T, r.p, p);
|
|
190
189
|
r.q = try std.math.mul(T, r.q, q);
|
|
191
190
|
}
|
|
192
191
|
|
|
193
|
-
|
|
192
|
+
fn addition(r: *Self, p: anytype, q: anytype) !void {
|
|
194
193
|
// (a/b) + (c/d) = (ad+bc)/(bd)
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
194
|
+
const d = try std.math.mul(T, r.q, q);
|
|
195
|
+
const n1 = try std.math.mul(T, r.p, q);
|
|
196
|
+
const n2 = try std.math.mul(T, r.q, p);
|
|
198
197
|
|
|
199
198
|
r.p = try std.math.add(T, n1, n2);
|
|
200
199
|
r.q = d;
|
|
@@ -202,23 +201,88 @@ pub fn Rational(comptime T: type) type {
|
|
|
202
201
|
};
|
|
203
202
|
}
|
|
204
203
|
|
|
205
|
-
// https://
|
|
206
|
-
|
|
204
|
+
// https://lemire.me/blog/greatest-common-divisor-the-extended-euclidean-algorithm-and-speed/
|
|
205
|
+
fn gcd(p: anytype, q: anytype) @TypeOf(p, q) {
|
|
207
206
|
assert(p >= 1);
|
|
208
207
|
assert(q >= 1);
|
|
209
208
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
209
|
+
// convert comptime_int to a sized integer within this function so that @ctz will work
|
|
210
|
+
const T = switch (@TypeOf(p, q)) {
|
|
211
|
+
comptime_int => std.math.IntFittingRange(@min(p, q), @max(p, q)),
|
|
212
|
+
else => |U| U,
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
switch (@typeInfo(T)) {
|
|
216
|
+
.Int => {
|
|
217
|
+
var u: T = undefined;
|
|
218
|
+
var v: T = undefined;
|
|
219
|
+
if (p < q) {
|
|
220
|
+
u = q;
|
|
221
|
+
v = p;
|
|
222
|
+
} else {
|
|
223
|
+
u = p;
|
|
224
|
+
v = q;
|
|
225
|
+
}
|
|
226
|
+
assert(v <= u);
|
|
227
|
+
u %= v;
|
|
228
|
+
if (u == 0) return v;
|
|
229
|
+
|
|
230
|
+
const zu = @ctz(u);
|
|
231
|
+
const zv = @ctz(v);
|
|
232
|
+
const shift = @min(zu, zv);
|
|
233
|
+
u >>= @intCast(zu);
|
|
234
|
+
v >>= @intCast(zv);
|
|
235
|
+
|
|
236
|
+
while (true) {
|
|
237
|
+
const diff = u -% v;
|
|
238
|
+
if (u > v) {
|
|
239
|
+
u = v;
|
|
240
|
+
v = diff;
|
|
241
|
+
} else {
|
|
242
|
+
v -= u;
|
|
243
|
+
}
|
|
244
|
+
if (diff != 0) v >>= @intCast(@ctz(diff));
|
|
245
|
+
if (v == 0) break;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const result = u << @intCast(shift);
|
|
249
|
+
assert(result > 0);
|
|
250
|
+
return result;
|
|
251
|
+
},
|
|
252
|
+
else => {
|
|
253
|
+
var a = p;
|
|
254
|
+
var b = q;
|
|
255
|
+
var c: T = undefined;
|
|
256
|
+
|
|
257
|
+
while (b != 0) {
|
|
258
|
+
c = b;
|
|
259
|
+
b = @mod(a, b);
|
|
260
|
+
a = c;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
assert(a > 0);
|
|
264
|
+
return a;
|
|
265
|
+
},
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
test gcd {
|
|
270
|
+
const seed = if (@hasDecl(std.testing, "random_seed")) std.testing.random_seed else 0x12345678;
|
|
271
|
+
var prng = std.Random.DefaultPrng.init(seed);
|
|
272
|
+
var random = prng.random();
|
|
273
|
+
|
|
274
|
+
for (0..1000) |_| {
|
|
275
|
+
const a = random.int(u32);
|
|
276
|
+
const b = random.int(u32);
|
|
277
|
+
if (a == 0 or b == 0) continue;
|
|
213
278
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
279
|
+
try expectEqual(
|
|
280
|
+
gcd(a, b),
|
|
281
|
+
@as(u32, @intFromFloat(gcd(@as(f64, @floatFromInt(a)), @as(f64, @floatFromInt(b))))),
|
|
282
|
+
);
|
|
218
283
|
}
|
|
219
284
|
|
|
220
|
-
|
|
221
|
-
return a;
|
|
285
|
+
try expectEqual(gcd(300_000, @as(u32, 2_300_000)), 100_000); // NB: @ctz requires an @intCast
|
|
222
286
|
}
|
|
223
287
|
|
|
224
288
|
fn doTurn(r: anytype) !void {
|
|
@@ -234,6 +298,8 @@ test Rational {
|
|
|
234
298
|
var r: Rational(t) = .{};
|
|
235
299
|
|
|
236
300
|
var c: t = 128;
|
|
301
|
+
_ = &c;
|
|
302
|
+
|
|
237
303
|
try r.update(c, 256);
|
|
238
304
|
try doTurn(&r);
|
|
239
305
|
|
|
@@ -275,7 +341,7 @@ pub const BigRational = struct {
|
|
|
275
341
|
/// Create a new BigRational wrapper. A small amount of memory will be allocated on
|
|
276
342
|
/// initialization. Not default initialized to 1 - you must explicitly `reset` first.
|
|
277
343
|
pub fn init(alloc: std.mem.Allocator) !BigRational {
|
|
278
|
-
return
|
|
344
|
+
return .{ .val = try std.math.big.Rational.init(alloc) };
|
|
279
345
|
}
|
|
280
346
|
|
|
281
347
|
/// Frees all memory associated with a rational.
|
|
@@ -320,6 +386,8 @@ test BigRational {
|
|
|
320
386
|
try r.reset();
|
|
321
387
|
|
|
322
388
|
var c: u8 = 128;
|
|
389
|
+
_ = &c;
|
|
390
|
+
|
|
323
391
|
try r.update(c, 256);
|
|
324
392
|
try doTurn(&r);
|
|
325
393
|
|
|
@@ -351,3 +419,36 @@ test BigRational {
|
|
|
351
419
|
try s.setRatio(71, 78);
|
|
352
420
|
try expect((try s.order(r.val)) == .eq);
|
|
353
421
|
}
|
|
422
|
+
|
|
423
|
+
test "minimum" {
|
|
424
|
+
// TODO: ziglang/zig#21069
|
|
425
|
+
if (builtin.mode == .ReleaseFast or builtin.mode == .ReleaseSmall) {
|
|
426
|
+
return error.SkipZigTest;
|
|
427
|
+
}
|
|
428
|
+
var r = try BigRational.init(std.testing.allocator);
|
|
429
|
+
defer r.deinit();
|
|
430
|
+
var s = try std.math.big.Rational.init(std.testing.allocator);
|
|
431
|
+
defer s.deinit();
|
|
432
|
+
|
|
433
|
+
try r.reset();
|
|
434
|
+
|
|
435
|
+
try r.update(1, 2); // Speed Tie
|
|
436
|
+
for (0..2) |_| {
|
|
437
|
+
try r.update(1, 2); // Confusion
|
|
438
|
+
try r.update(1, 2); // Infatuation
|
|
439
|
+
try r.update(3, 4); // Paralysis
|
|
440
|
+
// Population Bomb
|
|
441
|
+
for (0..10) |_| {
|
|
442
|
+
try r.update(9, 10); // Accuracy
|
|
443
|
+
try r.update(1, 15); // Damage roll
|
|
444
|
+
try r.update(1, 24); // Critical Hit
|
|
445
|
+
try r.update(9, 10); // King's Rock non-proc
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const ZEROS = std.math.pow(u310, 10, 31);
|
|
450
|
+
const n = 36472996377170786403;
|
|
451
|
+
const d: u310 = 146267071761884981524886149560653378220687632500762654519853056 * ZEROS;
|
|
452
|
+
try s.setRatio(n, d);
|
|
453
|
+
try expect((try s.order(r.val)) == .eq);
|
|
454
|
+
}
|
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,11 +66,15 @@ 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 =
|
|
68
|
-
try expectEqual(
|
|
76
|
+
var psrng: PSRNG = .{ .src = .{ .seed = 0x0001000200030004 } };
|
|
77
|
+
try expectEqual(121, psrng.range(u8, 0, 256));
|
|
69
78
|
try expectEqual(false, psrng.chance(u8, 128, 256)); // 226 < 128
|
|
70
79
|
}
|
|
71
80
|
|
|
@@ -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,18 +98,22 @@ 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
|
}
|
|
100
113
|
|
|
101
|
-
try expectEqual(
|
|
102
|
-
try expectEqual(
|
|
103
|
-
try expectEqual(
|
|
114
|
+
try expectEqual(16, Gen12.percent(6) + 1);
|
|
115
|
+
try expectEqual(16, Gen12.percent(7) - 1);
|
|
116
|
+
try expectEqual(128, Gen12.percent(50) + 1);
|
|
104
117
|
}
|
|
105
118
|
|
|
106
119
|
// https://pkmn.cc/pokeemerald/src/random.c
|
|
@@ -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
|
-
}
|