@pkmn/engine 0.1.0-dev.62399ed5 → 0.1.0-dev.6be9a775

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.
@@ -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: 13, patch: 0};
13
+ const ZIG_VERSION = {major: 0, minor: 11, 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';
@@ -163,8 +163,10 @@ const install = async () => {
163
163
  }
164
164
 
165
165
  const index = JSON.parse(await fetch(INDEX));
166
- const version = Object.keys(index)[+!ZIG_VERSION.dev];
167
- const release = index[version][`${arch}-${platform}`];
166
+ // TODO: ziglang/zig#17768
167
+ // const version = Object.keys(index)[+!ZIG_VERSION.dev];
168
+ const version = VERSION;
169
+ const release = index[VERSION][`${arch}-${platform}`];
168
170
  const url = release.tarball;
169
171
 
170
172
  let base = path.basename(url);
@@ -389,11 +391,11 @@ const downloadImportLib = async () => {
389
391
  const ext = process.platform === 'darwin'
390
392
  ? 'dylib' : process.platform === 'win32' ? 'dll' : 'so';
391
393
  try {
392
- const actual = path.join('build', 'lib', `${prefix}pkmn${suffix}.node.${ext}`);
394
+ const actual = path.join(ROOT, 'build', 'lib', `${prefix}pkmn${suffix}.node.${ext}`);
393
395
  fs.renameSync(actual, artifact);
394
396
  } catch (err) {
395
397
  // ziglang/zig#19743 changed this path
396
- const actual = path.join('build', 'bin', `${prefix}pkmn${suffix}.node.${ext}`);
398
+ const actual = path.join(ROOT, 'build', 'bin', `${prefix}pkmn${suffix}.node.${ext}`);
397
399
  fs.renameSync(actual, artifact);
398
400
  }
399
401
  }
@@ -0,0 +1,77 @@
1
+ const std = @import("std");
2
+
3
+ const expectEqual = std.testing.expectEqual;
4
+ const assert = std.debug.assert;
5
+
6
+ const Int = if (@hasField(std.builtin.Type, "int")) .int else .Int;
7
+ const Enum = if (@hasField(std.builtin.Type, "enum")) .@"enum" else .Enum;
8
+
9
+ /// Helpers for working with bit-packed arrays of non-powers-of-2 types.
10
+ /// NOTE: ziglang/zig#12547
11
+ pub fn Array(comptime n: comptime_int, comptime U: type) type {
12
+ return struct {
13
+ const size = @bitSizeOf(U);
14
+ const options = .{ .signedness = .unsigned, .bits = size * n };
15
+ pub const T = @Type(if (@hasField(std.builtin.Type, "int"))
16
+ .{ .int = options }
17
+ else
18
+ .{ .Int = options });
19
+
20
+ /// Returns the value stored at index `i` in the array `a`.
21
+ pub fn get(a: T, i: usize) U {
22
+ assert(i < n);
23
+ const shift = i * size;
24
+ const mask: T = (1 << size) - 1;
25
+ const result = (a >> @intCast(shift)) & mask;
26
+ return switch (@typeInfo(U)) {
27
+ Enum => @enumFromInt(result),
28
+ Int => @intCast(result),
29
+ else => unreachable,
30
+ };
31
+ }
32
+
33
+ /// Sets the value at index `i` to `val` in the array `a`.
34
+ pub fn set(a: T, i: usize, val: U) T {
35
+ assert(i < n);
36
+ const v: T = switch (@typeInfo(U)) {
37
+ Enum => @intFromEnum(val),
38
+ Int => @intCast(val),
39
+ else => unreachable,
40
+ };
41
+ const shift = i * size;
42
+ const mask: T = @as(T, @intCast((1 << size) - 1)) << @intCast(shift);
43
+ const result: T = a & ~mask;
44
+ return result | (v << @intCast(shift));
45
+ }
46
+ };
47
+ }
48
+
49
+ test Array {
50
+ const A = Array(5, u8);
51
+ var a: A.T = 0;
52
+ try expectEqual(u40, @TypeOf(a));
53
+
54
+ a = A.set(a, 4, 241);
55
+ try expectEqual(@as(u8, 241), A.get(a, 4));
56
+ a = A.set(a, 4, 1);
57
+ try expectEqual(@as(u8, 1), A.get(a, 4));
58
+
59
+ for (0..5) |i| a = A.set(a, i, @intCast(i));
60
+ for (0..5) |i| try expectEqual(@as(u8, @intCast(i)), A.get(a, i));
61
+
62
+ const Optional = @import("optional.zig").Optional;
63
+
64
+ const B = Array(4, Optional(bool));
65
+ var b: B.T = 0;
66
+ try expectEqual(u8, @TypeOf(b));
67
+
68
+ b = B.set(b, 2, .true);
69
+ try expectEqual(Optional(bool).None, B.get(b, 1));
70
+ try expectEqual(Optional(bool).true, B.get(b, 2));
71
+ try expectEqual(@as(u8, 0b00100000), b);
72
+ b = B.set(b, 2, .None);
73
+ b = B.set(b, 0, .false);
74
+ try expectEqual(Optional(bool).None, B.get(b, 2));
75
+ try expectEqual(Optional(bool).false, B.get(b, 0));
76
+ try expectEqual(@as(u8, 0b0000001), b);
77
+ }
@@ -22,8 +22,8 @@ pub const Player = enum(u1) {
22
22
 
23
23
  test Player {
24
24
  try expectEqual(Player.P2, Player.P1.foe());
25
- try expectEqual(0b0001, @as(u8, @bitCast(Player.P1.ident(1))));
26
- try expectEqual(0b1101, @as(u8, @bitCast(Player.P2.ident(5))));
25
+ try expectEqual(@as(u8, 0b0001), @as(u8, @bitCast(Player.P1.ident(1))));
26
+ try expectEqual(@as(u8, 0b1101), @as(u8, @bitCast(Player.P2.ident(5))));
27
27
  }
28
28
 
29
29
  /// An identifier for a specific Pokémon in battle.
@@ -46,8 +46,8 @@ pub const ID = packed struct(u8) {
46
46
  };
47
47
 
48
48
  test ID {
49
- try expectEqual(0b0001, @as(u8, @bitCast(ID{ .player = .P1, .id = 1 })));
50
- try expectEqual(0b1101, @as(u8, @bitCast(ID{ .player = .P2, .id = 5 })));
49
+ try expectEqual(@as(u8, 0b0001), @as(u8, @bitCast(ID{ .player = .P1, .id = 1 })));
50
+ try expectEqual(@as(u8, 0b1101), @as(u8, @bitCast(ID{ .player = .P2, .id = 5 })));
51
51
  const id: ID = .{ .player = .P2, .id = 4 };
52
52
  try expectEqual(id, ID.from(id.int()));
53
53
  }
@@ -76,8 +76,8 @@ test Choice {
76
76
  const p2: Choice = .{ .type = .Switch, .data = 5 };
77
77
  try expectEqual(5, p2.data);
78
78
  try expectEqual(Choice.Type.Move, p1.type);
79
- try expectEqual(0b0001_0001, @as(u8, @bitCast(p1)));
80
- try expectEqual(0b0001_0110, @as(u8, @bitCast(p2)));
79
+ try expectEqual(@as(u8, 0b0001_0001), @as(u8, @bitCast(p1)));
80
+ try expectEqual(@as(u8, 0b0001_0110), @as(u8, @bitCast(p2)));
81
81
  }
82
82
 
83
83
  /// The result of the battle - all results other than 'None' should be considered terminal.
@@ -112,6 +112,6 @@ pub const Result = packed struct(u8) {
112
112
  };
113
113
 
114
114
  test Result {
115
- try expectEqual(0b0101_0000, @as(u8, @bitCast(Result.Default)));
116
- try expectEqual(0b1000_0000, @as(u8, @bitCast(Result{ .p2 = .Switch })));
115
+ try expectEqual(@as(u8, 0b0101_0000), @as(u8, @bitCast(Result.Default)));
116
+ try expectEqual(@as(u8, 0b1000_0000), @as(u8, @bitCast(Result{ .p2 = .Switch })));
117
117
  }
@@ -2,6 +2,8 @@ const std = @import("std");
2
2
 
3
3
  const assert = std.debug.assert;
4
4
 
5
+ const Int = if (@hasField(std.builtin.Type, "int")) .int else .Int;
6
+
5
7
  const c = @cImport({
6
8
  @cDefine("NAPI_VERSION", "8");
7
9
  @cInclude("node_api.h");
@@ -35,7 +37,7 @@ pub const Number = struct {
35
37
  const T = @TypeOf(value);
36
38
  var result: c.napi_value = undefined;
37
39
  assert(c.napi_ok == switch (@typeInfo(T)) {
38
- .Int => |info| switch (info.bits) {
40
+ Int => |info| switch (info.bits) {
39
41
  0...32 => switch (info.signedness) {
40
42
  .signed => c.napi_create_int32(env, @as(i32, value), &result),
41
43
  .unsigned => c.napi_create_uint32(env, @as(u32, value), &result),
@@ -50,7 +52,7 @@ pub const Number = struct {
50
52
 
51
53
  pub fn get(env: c.napi_env, value: c.napi_value, comptime T: type) T {
52
54
  switch (@typeInfo(T)) {
53
- .Int => |info| switch (info.bits) {
55
+ Int => |info| switch (info.bits) {
54
56
  0...32 => switch (info.signedness) {
55
57
  .signed => {
56
58
  var result: i32 = undefined;
@@ -3,10 +3,12 @@ const std = @import("std");
3
3
  const expect = std.testing.expect;
4
4
  const assert = std.debug.assert;
5
5
 
6
+ const Bool = if (@hasField(std.builtin.Type, "bool")) .bool else .Bool;
7
+
6
8
  // TODO: ziglang/zig#104
7
9
  pub fn Optional(comptime T: type) type {
8
10
  const fields = std.meta.fields(switch (@typeInfo(T)) {
9
- .Bool => enum { false, true },
11
+ Bool => enum { false, true },
10
12
  else => T,
11
13
  });
12
14
 
@@ -23,14 +25,16 @@ pub fn Optional(comptime T: type) type {
23
25
  };
24
26
  }
25
27
 
26
- return @Type(.{
27
- .Enum = .{
28
- .tag_type = std.math.IntFittingRange(0, fields.len),
29
- .fields = &enumFields,
30
- .decls = &decls,
31
- .is_exhaustive = true,
32
- },
33
- });
28
+ const options = .{
29
+ .tag_type = std.math.IntFittingRange(0, fields.len),
30
+ .fields = &enumFields,
31
+ .decls = &decls,
32
+ .is_exhaustive = true,
33
+ };
34
+ return @Type(if (@hasField(std.builtin.Type, "enum"))
35
+ .{ .@"enum" = options }
36
+ else
37
+ .{ .Enum = options });
34
38
  }
35
39
 
36
40
  test Optional {
@@ -15,6 +15,11 @@ const Player = data.Player;
15
15
  const ID = data.ID;
16
16
 
17
17
  const endian = builtin.cpu.arch.endian();
18
+ const Endian = std.builtin.Endian;
19
+ const big = if (@hasField(Endian, "big")) Endian.big else Endian.Big;
20
+ const little = if (@hasField(Endian, "little")) Endian.little else Endian.Little;
21
+
22
+ const Int = if (@hasField(std.builtin.Type, "int")) .int else .Int;
18
23
 
19
24
  pub const ArgType = enum(u8) {
20
25
  None,
@@ -840,7 +845,7 @@ pub const ByteStream = struct {
840
845
 
841
846
  pub fn writeInt(self: Writer, comptime T: type, v: T, end: std.builtin.Endian) Error!void {
842
847
  // TODO: rework this to write directly to the buffer?
843
- var bytes: [@divExact(@typeInfo(T).Int.bits, 8)]u8 = undefined;
848
+ var bytes: [@divExact(@field(@typeInfo(T), @tagName(Int)).bits, 8)]u8 = undefined;
844
849
  std.mem.writeInt(std.math.ByteAlignedInt(@TypeOf(v)), &bytes, v, end);
845
850
  return self.writeAll(&bytes);
846
851
  }
@@ -864,7 +869,7 @@ pub const ByteStream = struct {
864
869
  pub const Kind = enum { Move, Species, Type, Status, Item, Weather };
865
870
 
866
871
  pub fn format(
867
- comptime gen: anytype,
872
+ gen: anytype,
868
873
  a: []const u8,
869
874
  b: ?[]const u8,
870
875
  color: bool,
@@ -956,13 +961,13 @@ pub fn format(
956
961
  }
957
962
  printc(" L{d}", .{a[i]}, a, b, &i, 1, color);
958
963
  switch (endian) {
959
- .big => {
964
+ big => {
960
965
  var hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
961
966
  printc(" {d}", .{hp}, a, b, &i, 2, color);
962
967
  hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
963
968
  printc("/{d}", .{hp}, a, b, &i, 2, color);
964
969
  },
965
- .little => {
970
+ little => {
966
971
  var hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
967
972
  printc(" {d}", .{hp}, a, b, &i, 2, color);
968
973
  hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
@@ -993,8 +998,8 @@ pub fn format(
993
998
  },
994
999
  .Turn => {
995
1000
  const turn = switch (endian) {
996
- .big => @as(u16, a[i]) << 8 | @as(u16, a[i + 1]),
997
- .little => @as(u16, a[i + 1]) << 8 | @as(u16, a[i]),
1001
+ big => @as(u16, a[i]) << 8 | @as(u16, a[i + 1]),
1002
+ little => @as(u16, a[i + 1]) << 8 | @as(u16, a[i]),
998
1003
  };
999
1004
  printc(" {d}", .{turn}, a, b, &i, 2, color);
1000
1005
  },
@@ -1005,13 +1010,13 @@ pub fn format(
1005
1010
  var id = ID.from(@intCast(a[i]));
1006
1011
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1007
1012
  switch (endian) {
1008
- .big => {
1013
+ big => {
1009
1014
  var hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
1010
1015
  printc(" {d}", .{hp}, a, b, &i, 2, color);
1011
1016
  hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
1012
1017
  printc("/{d}", .{hp}, a, b, &i, 2, color);
1013
1018
  },
1014
- .little => {
1019
+ little => {
1015
1020
  var hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
1016
1021
  printc(" {d}", .{hp}, a, b, &i, 2, color);
1017
1022
  hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
@@ -1133,13 +1138,13 @@ pub fn format(
1133
1138
  const id = ID.from(@intCast(a[i]));
1134
1139
  printc(" {s}({d})", .{ @tagName(id.player), id.id }, a, b, &i, 1, color);
1135
1140
  switch (endian) {
1136
- .big => {
1141
+ big => {
1137
1142
  var hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
1138
1143
  printc(" {d}", .{hp}, a, b, &i, 2, color);
1139
1144
  hp = @as(u16, a[i]) << 8 | @as(u16, a[i + 1]);
1140
1145
  printc("/{d}", .{hp}, a, b, &i, 2, color);
1141
1146
  },
1142
- .little => {
1147
+ little => {
1143
1148
  var hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
1144
1149
  printc(" {d}", .{hp}, a, b, &i, 2, color);
1145
1150
  hp = @as(u16, a[i + 1]) << 8 | @as(u16, a[i]);
@@ -1345,8 +1350,8 @@ test "|switch|" {
1345
1350
  try log.switched(.{ p2.ident(3), &snorlax });
1346
1351
  const par = 0b1000000;
1347
1352
  var expected: []const u8 = switch (endian) {
1348
- .big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 91, 0, 200, 1, 144, par },
1349
- .little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 91, 200, 0, 144, 1, par },
1353
+ big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 91, 0, 200, 1, 144, par },
1354
+ little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 91, 200, 0, 144, 1, par },
1350
1355
  };
1351
1356
  try expectLog1(expected, buf[0..9]);
1352
1357
  stream.reset();
@@ -1356,8 +1361,8 @@ test "|switch|" {
1356
1361
  snorlax.status = 0;
1357
1362
  try log.switched(.{ p2.ident(3), &snorlax });
1358
1363
  expected = switch (endian) {
1359
- .big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 0, 0, 1, 144, 0 },
1360
- .little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 0, 0, 144, 1, 0 },
1364
+ big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 0, 0, 1, 144, 0 },
1365
+ little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 0, 0, 144, 1, 0 },
1361
1366
  };
1362
1367
  try expectLog1(expected, buf[0..9]);
1363
1368
  stream.reset();
@@ -1365,8 +1370,8 @@ test "|switch|" {
1365
1370
  snorlax.hp = 400;
1366
1371
  try log.switched(.{ p2.ident(3), &snorlax });
1367
1372
  expected = switch (endian) {
1368
- .big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 1, 144, 1, 144, 0 },
1369
- .little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 144, 1, 144, 1, 0 },
1373
+ big => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 1, 144, 1, 144, 0 },
1374
+ little => &.{ N(ArgType.Switch), 0b1011, N(S1.Snorlax), 100, 144, 1, 144, 1, 0 },
1370
1375
  };
1371
1376
  try expectLog1(expected, buf[0..9]);
1372
1377
  stream.reset();
@@ -1384,8 +1389,8 @@ test "|switch|" {
1384
1389
  N(gen2.Gender.Female),
1385
1390
  91,
1386
1391
  } ++ switch (endian) {
1387
- .big => .{ 0, 200, 1, 144, par },
1388
- .little => .{ 200, 0, 144, 1, par },
1392
+ big => .{ 0, 200, 1, 144, par },
1393
+ little => .{ 200, 0, 144, 1, par },
1389
1394
  });
1390
1395
  try expectLog2(expected, buf[0..10]);
1391
1396
  stream.reset();
@@ -1414,8 +1419,8 @@ test "|faint|" {
1414
1419
  test "|turn|" {
1415
1420
  try log.turn(.{42});
1416
1421
  const expected = switch (endian) {
1417
- .big => &.{ N(ArgType.Turn), 0, 42, N(ArgType.None) },
1418
- .little => &.{ N(ArgType.Turn), 42, 0, N(ArgType.None) },
1422
+ big => &.{ N(ArgType.Turn), 0, 42, N(ArgType.None) },
1423
+ little => &.{ N(ArgType.Turn), 42, 0, N(ArgType.None) },
1419
1424
  };
1420
1425
  try expectLog1(expected, buf[0..4]);
1421
1426
  stream.reset();
@@ -1439,8 +1444,8 @@ test "|-damage|" {
1439
1444
  chansey.status = gen1.Status.slp(1);
1440
1445
  try log.damage(.{ p2.ident(2), &chansey, .None });
1441
1446
  var expected: []const u8 = switch (endian) {
1442
- .big => &.{ N(ArgType.Damage), 0b1010, 2, 100, 2, 191, 1, N(Damage.None) },
1443
- .little => &.{ N(ArgType.Damage), 0b1010, 100, 2, 191, 2, 1, N(Damage.None) },
1447
+ big => &.{ N(ArgType.Damage), 0b1010, 2, 100, 2, 191, 1, N(Damage.None) },
1448
+ little => &.{ N(ArgType.Damage), 0b1010, 100, 2, 191, 2, 1, N(Damage.None) },
1444
1449
  };
1445
1450
  try expectLog1(expected, buf[0..8]);
1446
1451
  stream.reset();
@@ -1450,8 +1455,8 @@ test "|-damage|" {
1450
1455
  chansey.status = 0;
1451
1456
  try log.damage(.{ p2.ident(2), &chansey, .Confusion });
1452
1457
  expected = switch (endian) {
1453
- .big => &.{ N(ArgType.Damage), 0b1010, 0, 100, 1, 0, 0, N(Damage.Confusion) },
1454
- .little => &.{ N(ArgType.Damage), 0b1010, 100, 0, 0, 1, 0, N(Damage.Confusion) },
1458
+ big => &.{ N(ArgType.Damage), 0b1010, 0, 100, 1, 0, 0, N(Damage.Confusion) },
1459
+ little => &.{ N(ArgType.Damage), 0b1010, 100, 0, 0, 1, 0, N(Damage.Confusion) },
1455
1460
  };
1456
1461
  try expectLog1(expected, buf[0..8]);
1457
1462
  stream.reset();
@@ -1459,8 +1464,8 @@ test "|-damage|" {
1459
1464
  chansey.status = gen1.Status.init(.PSN);
1460
1465
  try log.damage(.{ p2.ident(2), &chansey, .RecoilOf, p1.ident(1) });
1461
1466
  expected = switch (endian) {
1462
- .big => &.{ N(ArgType.Damage), 0b1010, 0, 100, 1, 0, 0b1000, N(Damage.RecoilOf), 1 },
1463
- .little => &.{ N(ArgType.Damage), 0b1010, 100, 0, 0, 1, 0b1000, N(Damage.RecoilOf), 1 },
1467
+ big => &.{ N(ArgType.Damage), 0b1010, 0, 100, 1, 0, 0b1000, N(Damage.RecoilOf), 1 },
1468
+ little => &.{ N(ArgType.Damage), 0b1010, 100, 0, 0, 1, 0b1000, N(Damage.RecoilOf), 1 },
1464
1469
  };
1465
1470
  try expectLog1(expected, buf[0..9]);
1466
1471
  stream.reset();
@@ -1472,8 +1477,8 @@ test "|-heal|" {
1472
1477
  chansey.status = gen1.Status.slp(1);
1473
1478
  try log.heal(.{ p2.ident(2), &chansey, .None });
1474
1479
  var expected: []const u8 = switch (endian) {
1475
- .big => &.{ N(ArgType.Heal), 0b1010, 2, 100, 2, 191, 1, N(Heal.None) },
1476
- .little => &.{ N(ArgType.Heal), 0b1010, 100, 2, 191, 2, 1, N(Heal.None) },
1480
+ big => &.{ N(ArgType.Heal), 0b1010, 2, 100, 2, 191, 1, N(Heal.None) },
1481
+ little => &.{ N(ArgType.Heal), 0b1010, 100, 2, 191, 2, 1, N(Heal.None) },
1477
1482
  };
1478
1483
  try expectLog1(expected, buf[0..8]);
1479
1484
  stream.reset();
@@ -1483,16 +1488,16 @@ test "|-heal|" {
1483
1488
  chansey.status = 0;
1484
1489
  try log.heal(.{ p2.ident(2), &chansey, .Silent });
1485
1490
  expected = switch (endian) {
1486
- .big => &.{ N(ArgType.Heal), 0b1010, 0, 100, 1, 0, 0, N(Heal.Silent) },
1487
- .little => &.{ N(ArgType.Heal), 0b1010, 100, 0, 0, 1, 0, N(Heal.Silent) },
1491
+ big => &.{ N(ArgType.Heal), 0b1010, 0, 100, 1, 0, 0, N(Heal.Silent) },
1492
+ little => &.{ N(ArgType.Heal), 0b1010, 100, 0, 0, 1, 0, N(Heal.Silent) },
1488
1493
  };
1489
1494
  try expectLog1(expected, buf[0..8]);
1490
1495
  stream.reset();
1491
1496
 
1492
1497
  try log.heal(.{ p2.ident(2), &chansey, .Drain, p1.ident(1) });
1493
1498
  expected = switch (endian) {
1494
- .big => &.{ N(ArgType.Heal), 0b1010, 0, 100, 1, 0, 0, N(Heal.Drain), 1 },
1495
- .little => &.{ N(ArgType.Heal), 0b1010, 100, 0, 0, 1, 0, N(Heal.Drain), 1 },
1499
+ big => &.{ N(ArgType.Heal), 0b1010, 0, 100, 1, 0, 0, N(Heal.Drain), 1 },
1500
+ little => &.{ N(ArgType.Heal), 0b1010, 100, 0, 0, 1, 0, N(Heal.Drain), 1 },
1496
1501
  };
1497
1502
  try expectLog1(expected, buf[0..9]);
1498
1503
  stream.reset();
@@ -1735,8 +1740,8 @@ test "|drag|" {
1735
1740
  N(gen2.Gender.Female),
1736
1741
  91,
1737
1742
  } ++ switch (endian) {
1738
- .big => .{ 0, 200, 1, 144, par },
1739
- .little => .{ 200, 0, 144, 1, par },
1743
+ big => .{ 0, 200, 1, 144, par },
1744
+ little => .{ 200, 0, 144, 1, par },
1740
1745
  });
1741
1746
  try expectLog2(expected, buf[0..10]);
1742
1747
  stream.reset();
@@ -1769,8 +1774,8 @@ test "|-sethp|" {
1769
1774
  blissey.hp = 612;
1770
1775
  try log.sethp(.{ p2.ident(2), &blissey, .Silent });
1771
1776
  const expected: []const u8 = switch (endian) {
1772
- .big => &.{ N(ArgType.SetHP), 0b1010, 2, 100, 2, 201, 0, N(SetHP.Silent) },
1773
- .little => &.{ N(ArgType.SetHP), 0b1010, 100, 2, 201, 2, 0, N(SetHP.Silent) },
1777
+ big => &.{ N(ArgType.SetHP), 0b1010, 2, 100, 2, 201, 0, N(SetHP.Silent) },
1778
+ little => &.{ N(ArgType.SetHP), 0b1010, 100, 2, 201, 2, 0, N(SetHP.Silent) },
1774
1779
  };
1775
1780
  try expectLog2(expected, buf[0..8]);
1776
1781
  stream.reset();
@@ -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) == .Float)
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
- .Int => error{Overflow},
33
- .Float => error{},
39
+ Int => error{Overflow},
40
+ Float => error{},
34
41
  else => unreachable,
35
42
  };
36
43
 
@@ -50,12 +57,12 @@ pub fn Rational(comptime T: type) type {
50
57
  // If our parameters are not fully reduced they may prematurely
51
58
  // cause overflow/loss of precision after the multiplication below
52
59
  assert(switch (@typeInfo(@TypeOf(p, q))) {
53
- .ComptimeInt, .ComptimeFloat => comptime gcd(p, q),
60
+ ComptimeInt, ComptimeFloat => comptime gcd(p, q),
54
61
  else => 1,
55
62
  } == 1);
56
63
 
57
64
  switch (@typeInfo(T)) {
58
- .Int => {
65
+ Int => {
59
66
  // Greedily attempt to multiply and if it fails, reduce and try again
60
67
  r.multiplication(p, q) catch |err| switch (err) {
61
68
  error.Overflow => {
@@ -65,16 +72,16 @@ pub fn Rational(comptime T: type) type {
65
72
  else => unreachable,
66
73
  };
67
74
  },
68
- .Float => {
75
+ Float => {
69
76
  // Reduce in situations where we're likely to start losing precision
70
77
  if (r.q > REDUCE or r.p > REDUCE) r.reduce();
71
78
 
72
79
  r.p *= switch (@typeInfo(@TypeOf(p))) {
73
- .Float, .ComptimeFloat => p,
80
+ Float, ComptimeFloat => p,
74
81
  else => @floatFromInt(p),
75
82
  };
76
83
  r.q *= switch (@typeInfo(@TypeOf(q))) {
77
- .Float, .ComptimeFloat => q,
84
+ Float, ComptimeFloat => q,
78
85
  else => @floatFromInt(q),
79
86
  };
80
87
 
@@ -89,7 +96,7 @@ pub fn Rational(comptime T: type) type {
89
96
  /// Add two rationals using the identity (a/b) + (c/d) = (ad+bc)/(bd).
90
97
  pub fn add(r: *Self, s: *Self) Error!void {
91
98
  switch (@typeInfo(T)) {
92
- .Int => {
99
+ Int => {
93
100
  if (r.q == s.q) {
94
101
  r.p = std.math.add(T, r.p, s.p) catch |err| switch (err) {
95
102
  error.Overflow => val: {
@@ -110,7 +117,7 @@ pub fn Rational(comptime T: type) type {
110
117
  };
111
118
  }
112
119
  },
113
- .Float => {
120
+ Float => {
114
121
  if (r.q == s.q) {
115
122
  if (r.p > REDUCE) r.reduce();
116
123
  if (s.p > REDUCE) s.reduce();
@@ -135,7 +142,7 @@ pub fn Rational(comptime T: type) type {
135
142
  /// Multiplies two rationals.
136
143
  pub fn mul(r: *Self, s: *Self) Error!void {
137
144
  switch (@typeInfo(T)) {
138
- .Int => {
145
+ Int => {
139
146
  r.multiplication(s.p, s.q) catch |err| switch (err) {
140
147
  error.Overflow => {
141
148
  r.reduce();
@@ -145,7 +152,7 @@ pub fn Rational(comptime T: type) type {
145
152
  else => unreachable,
146
153
  };
147
154
  },
148
- .Float => {
155
+ Float => {
149
156
  if (r.q > REDUCE or r.p > REDUCE) r.reduce();
150
157
  if (s.q > REDUCE or s.p > REDUCE) s.reduce();
151
158
 
@@ -201,46 +208,37 @@ pub fn Rational(comptime T: type) type {
201
208
  };
202
209
  }
203
210
 
204
- // https://lemire.me/blog/greatest-common-divisor-the-extended-euclidean-algorithm-and-speed/
205
211
  fn gcd(p: anytype, q: anytype) @TypeOf(p, q) {
206
212
  assert(p >= 1);
207
213
  assert(q >= 1);
208
214
 
209
- const T = @TypeOf(p, q);
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
+
210
221
  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;
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);
241
239
  }
242
240
 
243
- const result = u << @intCast(shift);
241
+ const result = y << @intCast(shift);
244
242
  assert(result > 0);
245
243
  return result;
246
244
  },
@@ -263,7 +261,7 @@ fn gcd(p: anytype, q: anytype) @TypeOf(p, q) {
263
261
 
264
262
  test gcd {
265
263
  const seed = if (@hasDecl(std.testing, "random_seed")) std.testing.random_seed else 0x12345678;
266
- var prng = std.Random.DefaultPrng.init(seed);
264
+ var prng = (if (@hasDecl(std, "Random")) std.Random else std.rand).DefaultPrng.init(seed);
267
265
  var random = prng.random();
268
266
 
269
267
  for (0..1000) |_| {
@@ -276,6 +274,8 @@ test gcd {
276
274
  @as(u32, @intFromFloat(gcd(@as(f64, @floatFromInt(a)), @as(f64, @floatFromInt(b))))),
277
275
  );
278
276
  }
277
+
278
+ try expectEqual(gcd(300_000, @as(u32, 2_300_000)), 100_000); // NB: @ctz requires an @intCast
279
279
  }
280
280
 
281
281
  fn doTurn(r: anytype) !void {
@@ -74,7 +74,7 @@ pub const PSRNG = extern struct {
74
74
 
75
75
  test PSRNG {
76
76
  var psrng: PSRNG = .{ .src = .{ .seed = 0x0001000200030004 } };
77
- try expectEqual(121, psrng.range(u8, 0, 256));
77
+ try expectEqual(@as(u8, 121), psrng.range(u8, 0, 256));
78
78
  try expectEqual(false, psrng.chance(u8, 128, 256)); // 226 < 128
79
79
  }
80
80
 
@@ -111,9 +111,9 @@ test Gen12 {
111
111
  try expectEqual(e, rng.next());
112
112
  }
113
113
 
114
- try expectEqual(16, Gen12.percent(6) + 1);
115
- try expectEqual(16, Gen12.percent(7) - 1);
116
- try expectEqual(128, Gen12.percent(50) + 1);
114
+ try expectEqual(@as(u8, 16), Gen12.percent(6) + 1);
115
+ try expectEqual(@as(u8, 16), Gen12.percent(7) - 1);
116
+ try expectEqual(@as(u8, 128), Gen12.percent(50) + 1);
117
117
  }
118
118
 
119
119
  // https://pkmn.cc/pokeemerald/src/random.c