@pkmn/engine 0.1.0-dev.3a62fd35 → 0.1.0-dev.3de821b9

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/build.zig CHANGED
@@ -1,26 +1,6 @@
1
1
  const std = @import("std");
2
2
  const builtin = @import("builtin");
3
3
 
4
- pub const Options = struct {
5
- showdown: ?bool = null,
6
- log: ?bool = null,
7
- chance: ?bool = null,
8
- calc: ?bool = null,
9
- };
10
-
11
- pub fn module(b: *std.Build, options: Options) *std.Build.Module {
12
- const dirname = comptime std.fs.path.dirname(@src().file) orelse ".";
13
- const build_options = b.addOptions();
14
- build_options.addOption(?bool, "showdown", options.showdown);
15
- build_options.addOption(?bool, "log", options.log);
16
- build_options.addOption(?bool, "chance", options.chance);
17
- build_options.addOption(?bool, "calc", options.calc);
18
- return b.createModule(.{
19
- .root_source_file = .{ .path = dirname ++ "/src/lib/pkmn.zig" },
20
- .imports = &.{.{ .name = "build_options", .module = build_options.createModule() }},
21
- });
22
- }
23
-
24
4
  pub fn build(b: *std.Build) !void {
25
5
  const target = b.standardTargetOptions(.{});
26
6
  const optimize = b.standardOptimizeOption(.{});
@@ -44,7 +24,7 @@ pub fn build(b: *std.Build) !void {
44
24
  defer parsed.deinit();
45
25
  const version = parsed.value.object.get("version").?.string;
46
26
  const description = parsed.value.object.get("description").?.string;
47
- var repository = std.mem.split(u8, parsed.value.object.get("repository").?.string, ":");
27
+ var repository = std.mem.splitSequence(u8, parsed.value.object.get("repository").?.string, ":");
48
28
  std.debug.assert(std.mem.eql(u8, repository.first(), "github"));
49
29
 
50
30
  const showdown =
@@ -61,22 +41,29 @@ pub fn build(b: *std.Build) !void {
61
41
 
62
42
  const name = if (showdown) "pkmn-showdown" else "pkmn";
63
43
 
44
+ const module = b.addModule("pkmn", .{
45
+ .root_source_file = b.path("src/lib/pkmn.zig"),
46
+ .optimize = optimize,
47
+ .target = target,
48
+ .imports = &.{.{ .name = "build_options", .module = options.createModule() }},
49
+ });
50
+
64
51
  var c = false;
65
52
  if (node_headers) |headers| {
66
53
  const addon = b.fmt("{s}.node", .{name});
67
54
  const lib = b.addSharedLibrary(.{
68
55
  .name = addon,
69
- .root_source_file = .{ .path = "src/lib/node.zig" },
56
+ .root_source_file = b.path("src/lib/node.zig"),
70
57
  .optimize = optimize,
71
58
  .target = target,
72
59
  .strip = strip,
73
60
  .pic = pic,
74
61
  });
75
62
  lib.root_module.addOptions("build_options", options);
76
- lib.addSystemIncludePath(.{ .path = headers });
63
+ lib.addSystemIncludePath(b.path(headers));
77
64
  lib.linkLibC();
78
65
  if (node_import_lib) |il| {
79
- lib.addObjectFile(.{ .path = il });
66
+ lib.addObjectFile(b.path(il));
80
67
  } else if (target.result.os.tag == .windows) {
81
68
  try std.io.getStdErr().writeAll("Must provide --node-import-library path on Windows\n");
82
69
  std.process.exit(1);
@@ -84,7 +71,7 @@ pub fn build(b: *std.Build) !void {
84
71
  lib.linker_allow_shlib_undefined = true;
85
72
  maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
86
73
  // Always emit to build/lib because this is where the driver code expects to find it
87
- // TODO(ziglang/zig#2231): using the following used to work (though was hacky):
74
+ // TODO: ziglang/zig#2231 - using the following used to work (though was hacky):
88
75
  //
89
76
  // lib.emit_bin = .{ .emit_to = b.fmt("build/lib/{s}", .{addon}) };
90
77
  // b.getInstallStep().dependOn(&lib.step);
@@ -95,7 +82,7 @@ pub fn build(b: *std.Build) !void {
95
82
  } else if (wasm) {
96
83
  const exe = b.addExecutable(.{
97
84
  .name = name,
98
- .root_source_file = .{ .path = "src/lib/wasm.zig" },
85
+ .root_source_file = b.path("src/lib/wasm.zig"),
99
86
  .optimize = switch (optimize) {
100
87
  .ReleaseFast, .ReleaseSafe => .ReleaseSmall,
101
88
  else => optimize,
@@ -121,7 +108,7 @@ pub fn build(b: *std.Build) !void {
121
108
  const sh = b.addSystemCommand(&.{ opt.?, "-O4" });
122
109
  sh.addArtifactArg(exe);
123
110
  sh.addArg("-o");
124
- sh.addFileArg(.{ .path = out });
111
+ sh.addFileArg(b.path(out));
125
112
  b.getInstallStep().dependOn(&sh.step);
126
113
  } else {
127
114
  b.getInstallStep().dependOn(&b.addInstallArtifact(exe, .{
@@ -131,7 +118,7 @@ pub fn build(b: *std.Build) !void {
131
118
  } else if (dynamic) {
132
119
  const lib = b.addSharedLibrary(.{
133
120
  .name = name,
134
- .root_source_file = .{ .path = "src/lib/c.zig" },
121
+ .root_source_file = b.path("src/lib/c.zig"),
135
122
  .version = try std.SemanticVersion.parse(version),
136
123
  .optimize = optimize,
137
124
  .target = target,
@@ -139,21 +126,21 @@ pub fn build(b: *std.Build) !void {
139
126
  .pic = pic,
140
127
  });
141
128
  lib.root_module.addOptions("build_options", options);
142
- lib.addIncludePath(.{ .path = "src/include" });
129
+ lib.addIncludePath(b.path("src/include"));
143
130
  maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
144
131
  b.installArtifact(lib);
145
132
  c = true;
146
133
  } else {
147
134
  const lib = b.addStaticLibrary(.{
148
135
  .name = name,
149
- .root_source_file = .{ .path = "src/lib/c.zig" },
136
+ .root_source_file = b.path("src/lib/c.zig"),
150
137
  .optimize = optimize,
151
138
  .target = target,
152
139
  .strip = strip,
153
140
  .pic = pic,
154
141
  });
155
142
  lib.root_module.addOptions("build_options", options);
156
- lib.addIncludePath(.{ .path = "src/include" });
143
+ lib.addIncludePath(b.path("src/include"));
157
144
  lib.bundle_compiler_rt = true;
158
145
  maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
159
146
  if (emit_asm) {
@@ -176,14 +163,18 @@ pub fn build(b: *std.Build) !void {
176
163
 
177
164
  if (c) {
178
165
  const header = b.addInstallFileWithDir(
179
- .{ .path = "src/include/pkmn.h" },
166
+ b.path("src/include/pkmn.h"),
180
167
  .header,
181
168
  "pkmn.h",
182
169
  );
183
170
  b.getInstallStep().dependOn(&header.step);
184
171
 
185
172
  const pc = b.fmt("lib{s}.pc", .{name});
186
- const file = try b.cache_root.join(b.allocator, &.{pc});
173
+ const file = try std.fs.path.relative(
174
+ b.allocator,
175
+ try std.process.getCwdAlloc(b.allocator),
176
+ try b.cache_root.join(b.allocator, &.{pc}),
177
+ );
187
178
  const pkgconfig_file = try std.fs.cwd().createFile(file, .{});
188
179
 
189
180
  const dirname = comptime std.fs.path.dirname(@src().file) orelse ".";
@@ -218,12 +209,8 @@ pub fn build(b: *std.Build) !void {
218
209
 
219
210
  var exes = std.ArrayList(*std.Build.Step.Compile).init(b.allocator);
220
211
  const tools: ToolConfig = .{
221
- .options = .{
222
- .showdown = showdown,
223
- .log = log,
224
- .chance = chance,
225
- .calc = calc,
226
- },
212
+ .showdown = showdown,
213
+ .module = module,
227
214
  .general = config,
228
215
  .tool = .{
229
216
  .tests = if (tests.build) tests else null,
@@ -294,7 +281,6 @@ const TestStep = struct {
294
281
 
295
282
  pub fn create(b: *std.Build, options: *std.Build.Step.Options, config: Config) *TestStep {
296
283
  const coverage = b.option([]const u8, "test-coverage", "Generate test coverage");
297
- const test_file = b.option([]const u8, "test-file", "Input file for test");
298
284
  const test_filter =
299
285
  b.option([]const u8, "test-filter", "Skip tests that do not match filter");
300
286
 
@@ -302,13 +288,8 @@ const TestStep = struct {
302
288
  const step = std.Build.Step.init(.{ .id = .custom, .name = "Run all tests", .owner = b });
303
289
  self.* = .{ .step = step, .build = test_filter == null };
304
290
 
305
- const path = test_file orelse "src/lib/test.zig";
306
291
  const tests = b.addTest(.{
307
- .name = b.fmt("{s}-{s}", .{
308
- std.fs.path.basename(std.fs.path.dirname(path).?),
309
- std.fs.path.stem(std.fs.path.basename(path)),
310
- }),
311
- .root_source_file = .{ .path = path },
292
+ .root_source_file = b.path("src/lib/test.zig"),
312
293
  .optimize = config.optimize,
313
294
  .target = config.target,
314
295
  .filter = test_filter,
@@ -328,7 +309,8 @@ const TestStep = struct {
328
309
  };
329
310
 
330
311
  const ToolConfig = struct {
331
- options: Options,
312
+ showdown: ?bool,
313
+ module: *std.Build.Module,
332
314
  general: Config,
333
315
  tool: struct {
334
316
  tests: ?*TestStep,
@@ -345,18 +327,18 @@ fn tool(b: *std.Build, path: []const u8, config: ToolConfig) !?*std.Build.Step.R
345
327
  var name = config.tool.name orelse std.fs.path.basename(path);
346
328
  const index = std.mem.lastIndexOfScalar(u8, name, '.');
347
329
  if (index) |i| name = name[0..i];
348
- if (config.options.showdown orelse false) name = b.fmt("{s}-showdown", .{name});
330
+ if (config.showdown orelse false) name = b.fmt("{s}-showdown", .{name});
349
331
 
350
332
  const exe = b.addExecutable(.{
351
333
  .name = name,
352
- .root_source_file = .{ .path = path },
334
+ .root_source_file = b.path(path),
353
335
  .target = config.general.target,
354
336
  .optimize = config.general.optimize,
355
337
  .single_threaded = true,
356
338
  .strip = config.general.strip,
357
339
  .pic = config.general.pic,
358
340
  });
359
- exe.root_module.addImport("pkmn", module(b, config.options));
341
+ exe.root_module.addImport("pkmn", config.module);
360
342
 
361
343
  if (config.tool.tests) |ts| ts.step.dependOn(&exe.step);
362
344
  config.tool.exes.append(exe) catch @panic("OOM");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pkmn/engine",
3
- "version": "0.1.0-dev.3a62fd35",
3
+ "version": "0.1.0-dev.3de821b9",
4
4
  "description": "A minimal, complete, Pokémon battle simulation engine optimized for performance",
5
5
  "repository": "github:pkmn/engine",
6
6
  "license": "MIT",
@@ -31,7 +31,6 @@
31
31
  "build/test/display.js",
32
32
  "build/tools/debug.js.map",
33
33
  "build/tools/debug.js",
34
- "src/bin/install-pkmn-engine",
35
34
  "src/lib/common/battle.zig",
36
35
  "src/lib/common/data.zig",
37
36
  "src/lib/common/debug.zig",
@@ -76,31 +75,31 @@
76
75
  "access": "public"
77
76
  },
78
77
  "dependencies": {
79
- "@pkmn/data": "^0.8.1",
80
- "@pkmn/protocol": "^0.6.17"
78
+ "@pkmn/data": "^0.9.11",
79
+ "@pkmn/protocol": "^0.6.25"
81
80
  },
82
81
  "devDependencies": {
83
- "@pkmn/eslint-config": "^6.4.0",
84
- "@pkmn/img": "^0.2.20",
85
- "@pkmn/sets": "^5.1.0",
86
- "@pkmn/sim": "0.8.1",
82
+ "@pkmn/eslint-config": "^8.1.0",
83
+ "@pkmn/img": "^0.2.31",
84
+ "@pkmn/sets": "^5.1.2",
85
+ "@pkmn/sim": "0.9.11",
87
86
  "@types/html-minifier": "^4.0.5",
88
- "@types/jest": "^29.5.11",
87
+ "@types/jest": "^29.5.12",
89
88
  "@types/minimist": "^1.2.5",
90
89
  "@types/mustache": "^4.2.5",
91
- "@types/node": "^20.10.5",
92
- "@vitest/coverage-v8": "^1.0.4",
93
- "binaryen": "^116.0.0",
94
- "eslint": "^8.56.0",
90
+ "@types/node": "^22.0.2",
91
+ "@vitest/coverage-v8": "^2.0.5",
92
+ "binaryen": "^118.0.0",
93
+ "eslint": "<=8",
95
94
  "html-minifier": "^4.0.0",
96
- "json-stringify-pretty-compact": "3.0.0",
95
+ "json-stringify-pretty-compact": "4.0.0",
97
96
  "minimist": "^1.2.8",
98
97
  "mustache": "^4.2.0",
99
98
  "source-map-support": "^0.5.21",
100
- "table": "^6.8.1",
99
+ "table": "^6.8.2",
101
100
  "trakr": "^0.2.0",
102
- "typescript": "^5.3.3",
103
- "vitest": "^1.0.4"
101
+ "typescript": "^5.5.4",
102
+ "vitest": "^2.0.5"
104
103
  },
105
104
  "scripts": {
106
105
  "lint": "eslint --cache src --ext ts,js && eslint src/bin/*",
@@ -142,6 +141,14 @@
142
141
  ]
143
142
  }
144
143
  },
144
+ {
145
+ "files": [
146
+ "src/test/display.ts"
147
+ ],
148
+ "rules": {
149
+ "@typescript-eslint/no-unnecessary-type-assertion": "off"
150
+ }
151
+ },
145
152
  {
146
153
  "files": [
147
154
  "src/pkg/index.ts",
@@ -10,7 +10,7 @@ const path = require('path');
10
10
  const {pipeline} = require('stream/promises');
11
11
  const tty = require('tty');
12
12
 
13
- const ZIG_VERSION = {major: 0, minor: 12, patch: 0, dev: 2036};
13
+ const ZIG_VERSION = {major: 0, minor: 13, patch: 0};
14
14
  const DEV = ZIG_VERSION.dev ? `-dev.${ZIG_VERSION.dev}` : '';
15
15
  const VERSION = `${ZIG_VERSION.major}.${ZIG_VERSION.minor}.${ZIG_VERSION.patch}${DEV}`;
16
16
  const INDEX = 'https://ziglang.org/download/index.json';
@@ -370,8 +370,10 @@ const downloadImportLib = async () => {
370
370
  const args = ['build', '-p', 'build', ...opts];
371
371
  if (!process.env.DEBUG_PKMN_ENGINE) args.push('-Doptimize=ReleaseFast', '-Dstrip');
372
372
  if (config.type === 'node') {
373
- args.push(`-Dnode-headers=${headers}`);
374
- if (process.platform === 'win32') args.push(`-Dnode-import-library=${lib}`);
373
+ args.push(`-Dnode-headers=${path.relative(ROOT, headers)}`);
374
+ if (process.platform === 'win32') {
375
+ args.push(`-Dnode-import-library=${path.relative(ROOT, lib)}`);
376
+ }
375
377
  } else {
376
378
  args.push('-Dwasm');
377
379
  }
@@ -386,8 +388,14 @@ const downloadImportLib = async () => {
386
388
  const prefix = process.platform === 'win32' ? '' : 'lib';
387
389
  const ext = process.platform === 'darwin'
388
390
  ? 'dylib' : process.platform === 'win32' ? 'dll' : 'so';
389
- const actual = path.join('build', 'lib', `${prefix}pkmn${suffix}.node.${ext}`);
390
- fs.renameSync(path.join(ROOT, actual), path.join(ROOT, artifact));
391
+ try {
392
+ const actual = path.join('build', 'lib', `${prefix}pkmn${suffix}.node.${ext}`);
393
+ fs.renameSync(actual, artifact);
394
+ } catch (err) {
395
+ // ziglang/zig#19743 changed this path
396
+ const actual = path.join('build', 'bin', `${prefix}pkmn${suffix}.node.${ext}`);
397
+ fs.renameSync(actual, artifact);
398
+ }
391
399
  }
392
400
  }
393
401
  })().catch(e => {
@@ -4,8 +4,8 @@ const debug = std.debug;
4
4
  const io = std.io;
5
5
 
6
6
  pub fn print(value: anytype) void {
7
- debug.getStderrMutex().lock();
8
- defer debug.getStderrMutex().unlock();
7
+ debug.lockStdErr();
8
+ defer debug.unlockStdErr();
9
9
  const stderr = io.getStdErr().writer();
10
10
 
11
11
  nosuspend {
@@ -10,6 +10,7 @@ pub const Options = struct {
10
10
  advance: ?bool = null,
11
11
  ebc: ?bool = null,
12
12
  key: ?bool = null,
13
+ miss: ?bool = null,
13
14
  internal: ?bool = null,
14
15
  };
15
16
 
@@ -25,6 +26,7 @@ pub const calc = get("calc", false);
25
26
  pub const advance = get("advance", true);
26
27
  pub const ebc = get("ebc", true);
27
28
  pub const key = get("key", false);
29
+ pub const miss = get("miss", true);
28
30
  pub const internal = get("internal", false);
29
31
 
30
32
  fn get(comptime name: []const u8, default: bool) bool {
@@ -220,6 +220,7 @@ pub const Activate = enum(u8) {
220
220
  BeatUp, // FIXME of
221
221
 
222
222
  Magnitude,
223
+ Spite,
223
224
  };
224
225
 
225
226
  pub const Start = enum(u8) {
@@ -544,6 +545,7 @@ pub fn Log(comptime Writer: type) type {
544
545
  // ident: ID, reason: Activate
545
546
  // ident: ID, reason: .SubstituteBlock, m: <Move>
546
547
  // ident: ID, reason: .Magnitude, num: u8
548
+ // ident: ID, reason: .Spite, m: <Move>, num: u8
547
549
  pub fn activate(self: Self, args: anytype) Error!void {
548
550
  if (!enabled) return;
549
551
 
@@ -561,6 +563,9 @@ pub fn Log(comptime Writer: type) type {
561
563
  assert(reason == .Magnitude);
562
564
  try self.writer.writeByte(args[2]);
563
565
  }
566
+ } else if (args.len == 4) {
567
+ assert(reason == .Spite);
568
+ try self.writer.writeAll(&.{ @intFromEnum(args[2]), args[3] });
564
569
  }
565
570
  }
566
571
 
@@ -859,7 +864,7 @@ pub const ByteStream = struct {
859
864
  pub const Kind = enum { Move, Species, Type, Status, Item, Weather };
860
865
 
861
866
  pub fn format(
862
- comptime gen: anytype,
867
+ gen: anytype,
863
868
  a: []const u8,
864
869
  b: ?[]const u8,
865
870
  color: bool,
@@ -1202,14 +1207,11 @@ pub fn expectLog(
1202
1207
  ) !void {
1203
1208
  if (!enabled) return;
1204
1209
 
1205
- const color = color: {
1206
- if (std.process.hasEnvVarConstant("ZIG_DEBUG_COLOR")) {
1207
- break :color true;
1208
- } else if (std.process.hasEnvVarConstant("NO_COLOR")) {
1209
- break :color false;
1210
- } else {
1211
- break :color std.io.getStdErr().supportsAnsiEscapeCodes();
1212
- }
1210
+ const color = if (std.process.hasEnvVarConstant("ZIG_DEBUG_COLOR"))
1211
+ true
1212
+ else switch (std.io.tty.detectConfig(std.io.getStdErr())) {
1213
+ .escape_codes => true,
1214
+ else => false,
1213
1215
  };
1214
1216
 
1215
1217
  expectEqualBytes(expected, actual, offset) catch |err| switch (err) {
@@ -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
- // FIXME
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
 
@@ -202,23 +201,81 @@ pub fn Rational(comptime T: type) type {
202
201
  };
203
202
  }
204
203
 
205
- // https://en.wikipedia.org/wiki/Euclidean_algorithm
204
+ // https://lemire.me/blog/greatest-common-divisor-the-extended-euclidean-algorithm-and-speed/
206
205
  fn gcd(p: anytype, q: anytype) @TypeOf(p, q) {
207
206
  assert(p >= 1);
208
207
  assert(q >= 1);
209
208
 
210
- var a = p;
211
- var b = q;
212
- var c: @TypeOf(p, q) = undefined;
209
+ const T = @TypeOf(p, q);
210
+ switch (@typeInfo(T)) {
211
+ .Int => {
212
+ var u: T = undefined;
213
+ var v: T = undefined;
214
+ if (p < q) {
215
+ u = q;
216
+ v = p;
217
+ } else {
218
+ u = p;
219
+ v = q;
220
+ }
221
+ assert(v <= u);
222
+ u %= v;
223
+ if (u == 0) return v;
224
+
225
+ const zu = @ctz(u);
226
+ const zv = @ctz(v);
227
+ const shift = @min(zu, zv);
228
+ u >>= @intCast(zu);
229
+ v >>= @intCast(zv);
230
+
231
+ while (true) {
232
+ const diff = u -% v;
233
+ if (u > v) {
234
+ u = v;
235
+ v = diff;
236
+ } else {
237
+ v -= u;
238
+ }
239
+ if (diff != 0) v >>= @intCast(@ctz(diff));
240
+ if (v == 0) break;
241
+ }
242
+
243
+ const result = u << @intCast(shift);
244
+ assert(result > 0);
245
+ return result;
246
+ },
247
+ else => {
248
+ var a = p;
249
+ var b = q;
250
+ var c: T = undefined;
251
+
252
+ while (b != 0) {
253
+ c = b;
254
+ b = @mod(a, b);
255
+ a = c;
256
+ }
213
257
 
214
- while (b != 0) {
215
- c = b;
216
- b = @mod(a, b);
217
- a = c;
258
+ assert(a > 0);
259
+ return a;
260
+ },
218
261
  }
262
+ }
263
+
264
+ test gcd {
265
+ const seed = if (@hasDecl(std.testing, "random_seed")) std.testing.random_seed else 0x12345678;
266
+ var prng = std.Random.DefaultPrng.init(seed);
267
+ var random = prng.random();
219
268
 
220
- assert(a > 0);
221
- return a;
269
+ for (0..1000) |_| {
270
+ const a = random.int(u32);
271
+ const b = random.int(u32);
272
+ if (a == 0 or b == 0) continue;
273
+
274
+ try expectEqual(
275
+ gcd(a, b),
276
+ @as(u32, @intFromFloat(gcd(@as(f64, @floatFromInt(a)), @as(f64, @floatFromInt(b))))),
277
+ );
278
+ }
222
279
  }
223
280
 
224
281
  fn doTurn(r: anytype) !void {
@@ -355,3 +412,36 @@ test BigRational {
355
412
  try s.setRatio(71, 78);
356
413
  try expect((try s.order(r.val)) == .eq);
357
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
+ }
@@ -66,6 +66,10 @@ pub const PSRNG = extern struct {
66
66
  (@as(u64, self.range(u16, 0, 0x10000)) << 16) |
67
67
  (@as(u64, self.range(u16, 0, 0x10000)));
68
68
  }
69
+
70
+ pub fn Bound(comptime T: type) type {
71
+ return std.math.IntFittingRange(0, std.math.maxInt(T) + 1);
72
+ }
69
73
  };
70
74
 
71
75
  test PSRNG {
@@ -197,7 +201,7 @@ pub fn FixedRNG(comptime gen: comptime_int, comptime len: usize) type {
197
201
  for (0..n) |_| _ = self.next();
198
202
  }
199
203
 
200
- 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 {
201
205
  assert(showdown);
202
206
  return @intCast(@as(u64, self.next()) * (to - from) / divisor + from);
203
207
  }
@@ -206,7 +210,7 @@ pub fn FixedRNG(comptime gen: comptime_int, comptime len: usize) type {
206
210
  self: *Self,
207
211
  comptime T: type,
208
212
  numerator: T,
209
- denominator: Bound(T),
213
+ denominator: PSRNG.Bound(T),
210
214
  ) bool {
211
215
  assert(showdown);
212
216
  assert(denominator > 0);
@@ -237,7 +241,3 @@ fn Output(comptime gen: comptime_int) type {
237
241
  else => unreachable,
238
242
  };
239
243
  }
240
-
241
- fn Bound(comptime T: type) type {
242
- return std.math.IntFittingRange(0, std.math.maxInt(T) + 1);
243
- }