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

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.
Files changed (73) hide show
  1. package/README.md +4 -2
  2. package/build/pkg/addon/browser.d.ts +3 -0
  3. package/build/pkg/addon/browser.js +44 -0
  4. package/build/pkg/addon/browser.js.map +1 -0
  5. package/build/pkg/addon/node.d.ts +3 -0
  6. package/build/pkg/addon/node.js +97 -0
  7. package/build/pkg/addon/node.js.map +1 -0
  8. package/build/pkg/addon/wasm.d.ts +2 -0
  9. package/build/pkg/addon/wasm.js +21 -0
  10. package/build/pkg/addon/wasm.js.map +1 -0
  11. package/build/pkg/addon.d.ts +22 -0
  12. package/build/pkg/addon.js +29 -51
  13. package/build/pkg/addon.js.map +1 -1
  14. package/build/pkg/data.d.ts +23 -1
  15. package/build/pkg/data.js.map +1 -1
  16. package/build/pkg/gen1.js +1 -1
  17. package/build/pkg/gen1.js.map +1 -1
  18. package/build/pkg/index.d.ts +23 -9
  19. package/build/pkg/index.js +17 -11
  20. package/build/pkg/index.js.map +1 -1
  21. package/build/pkg/protocol.d.ts +20 -1
  22. package/build/pkg/protocol.js +105 -103
  23. package/build/pkg/protocol.js.map +1 -1
  24. package/build/tools/debug.js +35 -68
  25. package/build/tools/debug.js.map +1 -1
  26. package/build/tools/display/debug.jsx +141 -0
  27. package/build/tools/display/debug.jsx.map +1 -0
  28. package/build/tools/display/index.js +141 -0
  29. package/build/tools/display/index.js.map +1 -0
  30. package/build/tools/display/ui.jsx +349 -0
  31. package/build/tools/display/ui.jsx.map +1 -0
  32. package/build/tools/display/util.js +18 -0
  33. package/build/tools/display/util.js.map +1 -0
  34. package/build.zig +249 -77
  35. package/package.json +51 -31
  36. package/src/bin/install-pkmn-engine +7 -5
  37. package/src/bin/pkmn-debug +1 -1
  38. package/src/lib/common/array.zig +77 -0
  39. package/src/lib/common/data.zig +8 -8
  40. package/src/lib/common/debug.zig +39 -8
  41. package/src/lib/common/js.zig +4 -2
  42. package/src/lib/common/optional.zig +13 -9
  43. package/src/lib/common/options.zig +4 -0
  44. package/src/lib/common/protocol.zig +44 -43
  45. package/src/lib/common/rational.zig +53 -51
  46. package/src/lib/common/rng.zig +5 -7
  47. package/src/lib/common/util.zig +50 -1
  48. package/src/lib/gen1/calc.zig +247 -108
  49. package/src/lib/gen1/chance.zig +130 -121
  50. package/src/lib/gen1/data/moves.zig +2 -4
  51. package/src/lib/gen1/data/species.zig +1 -3
  52. package/src/lib/gen1/data/types.zig +1 -2
  53. package/src/lib/gen1/data.zig +35 -38
  54. package/src/lib/gen1/helpers.zig +15 -27
  55. package/src/lib/gen1/mechanics.zig +112 -94
  56. package/src/lib/gen2/calc.zig +37 -27
  57. package/src/lib/gen2/chance.zig +86 -66
  58. package/src/lib/gen2/data/items.zig +1 -3
  59. package/src/lib/gen2/data/moves.zig +2 -4
  60. package/src/lib/gen2/data/species.zig +1 -3
  61. package/src/lib/gen2/data/types.zig +1 -2
  62. package/src/lib/gen2/data.zig +26 -29
  63. package/src/lib/gen2/generated.zig +18 -23
  64. package/src/lib/gen2/helpers.zig +9 -18
  65. package/src/lib/gen2/mechanics.zig +62 -73
  66. package/src/lib/node.zig +2 -4
  67. package/src/lib/pkmn.zig +11 -5
  68. package/src/lib/wasm.zig +1 -2
  69. package/src/tools/display/dom.ts +96 -0
  70. package/src/tools/display/ui.css +354 -0
  71. package/build/test/display.js +0 -405
  72. package/build/test/display.js.map +0 -1
  73. package/src/test/display/pkmn.html.tmpl +0 -368
@@ -1,26 +1,31 @@
1
- const std = @import("std");
2
-
3
- const assert = std.debug.assert;
4
- const print = std.debug.print;
5
-
6
- const expect = std.testing.expect;
7
- const expectEqual = std.testing.expectEqual;
8
-
9
1
  const DEBUG = @import("../common/debug.zig").print;
2
+
3
+ const array = @import("../common/array.zig");
4
+ const common = @import("../common/data.zig");
5
+ const data = @import("data.zig");
6
+ const optional = @import("../common/optional.zig");
10
7
  const options = @import("../common/options.zig");
11
8
  const rational = @import("../common/rational.zig");
9
+ const std = @import("std");
12
10
  const util = @import("../common/util.zig");
13
11
 
14
- const Player = @import("../common/data.zig").Player;
15
- const Optional = @import("../common/optional.zig").Optional;
16
-
17
- const data = @import("data.zig");
18
-
12
+ const Array = array.Array;
13
+ const assert = std.debug.assert;
19
14
  const enabled = options.chance;
20
- const showdown = options.showdown;
21
-
15
+ const expect = std.testing.expect;
16
+ const expectEqual = std.testing.expectEqual;
17
+ const isPointerTo = util.isPointerTo;
22
18
  const Move = data.Move;
23
19
  const MoveSlot = data.MoveSlot;
20
+ const Optional = optional.Optional;
21
+ const Player = common.Player;
22
+ const PointerType = util.PointerType;
23
+ const print = std.debug.print;
24
+ const showdown = options.showdown;
25
+
26
+ const Int = if (@hasField(std.builtin.Type, "int")) .int else .Int;
27
+ const Enum = if (@hasField(std.builtin.Type, "enum")) .@"enum" else .Enum;
28
+ const Struct = if (@hasField(std.builtin.Type, "struct")) .@"struct" else .Struct;
24
29
 
25
30
  /// Actions taken by a hypothetical "chance player" that convey information about which RNG events
26
31
  /// were observed during a Generation I battle `update`. This can additionally be provided as input
@@ -37,8 +42,8 @@ pub const Actions = extern struct {
37
42
  }
38
43
 
39
44
  /// Returns the `Action` for the given `player`.
40
- pub fn get(self: anytype, player: Player) util.PointerType(@TypeOf(self), Action) {
41
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Actions);
45
+ pub fn get(self: anytype, player: Player) PointerType(@TypeOf(self), Action) {
46
+ assert(isPointerTo(self, Actions));
42
47
  return if (player == .P1) &self.p1 else &self.p2;
43
48
  }
44
49
 
@@ -51,15 +56,15 @@ pub const Actions = extern struct {
51
56
  /// same shape if they have the same fields set (though those fields need not necessarily be
52
57
  /// set to the same value).
53
58
  pub fn matches(a: Actions, b: Actions) bool {
54
- inline for (@typeInfo(Actions).Struct.fields) |player| {
55
- inline for (@typeInfo(Action).Struct.fields) |field| {
59
+ inline for (@field(@typeInfo(Actions), @tagName(Struct)).fields) |player| {
60
+ inline for (@field(@typeInfo(Action), @tagName(Struct)).fields) |field| {
56
61
  const a_val = @field(@field(a, player.name), field.name);
57
62
  const b_val = @field(@field(b, player.name), field.name);
58
63
 
59
64
  switch (@typeInfo(@TypeOf(a_val))) {
60
- .Enum => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
65
+ Enum => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
61
66
  return false,
62
- .Int => if ((a_val > 0) != (b_val > 0)) return false,
67
+ Int => if ((a_val > 0) != (b_val > 0)) return false,
63
68
  else => unreachable,
64
69
  }
65
70
  }
@@ -67,6 +72,25 @@ pub const Actions = extern struct {
67
72
  return true;
68
73
  }
69
74
 
75
+ /// TODO
76
+ pub fn matchesAny(a: Actions, bs: []Actions, i: usize) bool {
77
+ for (bs, 0..) |b, j| {
78
+ // TODO: is skipping this redundant check worth it?
79
+ if (i == j) continue;
80
+ if (b.matches(a)) return true;
81
+ }
82
+ return false;
83
+ }
84
+
85
+ /// TODO
86
+ pub fn relax(actions: Actions) Actions {
87
+ if (!options.overwrite) return actions;
88
+ var a = actions;
89
+ if (a.p1.confusion == .overwritten) a.p1.confusion = .continuing;
90
+ if (a.p2.confusion == .overwritten) a.p2.confusion = .continuing;
91
+ return a;
92
+ }
93
+
70
94
  pub fn fmt(self: Actions, writer: anytype, shape: bool) !void {
71
95
  try writer.writeAll("<P1 = ");
72
96
  try self.p1.fmt(writer, shape);
@@ -144,15 +168,15 @@ pub const Action = packed struct(u64) {
144
168
  /// TODO
145
169
  disable: Optional(Observation) = .None,
146
170
  /// TODO
147
- bide: Optional(Observation) = .None,
171
+ attacking: Optional(Observation) = .None,
148
172
  /// TODO
149
173
  binding: Optional(Observation) = .None,
150
- /// TODO
151
- thrashing: Optional(Observation) = .None,
174
+
175
+ _: u1 = 0,
152
176
 
153
177
  /// If not 0, the move slot (1-4) to return in Rolls.moveSlot. If present as an override,
154
178
  /// invalid values (eg. due to empty move slots or 0 PP) will be ignored.
155
- move_slot: u3 = 0,
179
+ move_slot: u4 = 0,
156
180
 
157
181
  /// TODO
158
182
  pp: u4 = 0,
@@ -175,10 +199,10 @@ pub const Action = packed struct(u64) {
175
199
  pub fn fmt(self: Action, writer: anytype, shape: bool) !void {
176
200
  try writer.writeByte('(');
177
201
  var printed = false;
178
- inline for (@typeInfo(Action).Struct.fields) |field| {
202
+ inline for (@field(@typeInfo(Action), @tagName(Struct)).fields) |field| {
179
203
  const val = @field(self, field.name);
180
204
  switch (@typeInfo(@TypeOf(val))) {
181
- .Enum => if (val != .None) {
205
+ Enum => if (val != .None) {
182
206
  if (printed) try writer.writeAll(", ");
183
207
  if (shape) {
184
208
  try writer.print("{s}:?", .{field.name});
@@ -199,7 +223,7 @@ pub const Action = packed struct(u64) {
199
223
  }
200
224
  printed = true;
201
225
  },
202
- .Int => if (val != 0) {
226
+ Int => if (val != 0) {
203
227
  if (printed) try writer.writeAll(", ");
204
228
  if (shape) {
205
229
  try writer.print("{s}:?", .{field.name});
@@ -216,15 +240,19 @@ pub const Action = packed struct(u64) {
216
240
  };
217
241
 
218
242
  /// TODO
219
- pub const Durations = struct {
243
+ pub const Durations = extern struct {
220
244
  /// TODO
221
245
  p1: Duration = .{},
222
246
  /// TODO
223
247
  p2: Duration = .{},
224
248
 
249
+ comptime {
250
+ assert(@sizeOf(Durations) == 8);
251
+ }
252
+
225
253
  /// TODO
226
- pub fn get(self: anytype, player: Player) util.PointerType(@TypeOf(self), Duration) {
227
- assert(@typeInfo(@TypeOf(self)).Pointer.child == Durations);
254
+ pub fn get(self: anytype, player: Player) PointerType(@TypeOf(self), Duration) {
255
+ assert(isPointerTo(self, Durations));
228
256
  return if (player == .P1) &self.p1 else &self.p2;
229
257
  }
230
258
 
@@ -239,15 +267,18 @@ pub const Durations = struct {
239
267
  }
240
268
  };
241
269
 
270
+ pub const Sleeps = Array(6, u3);
271
+
242
272
  /// TODO
243
- pub const Duration = struct {
244
- sleeps: [6]u3 = .{0} ** 6,
273
+ pub const Duration = packed struct(u32) {
274
+ sleeps: Sleeps.T = 0,
245
275
  confusion: u3 = 0,
246
276
  disable: u4 = 0,
247
- bide: u3 = 0,
248
- thrashing: u3 = 0,
277
+ attacking: u3 = 0,
249
278
  binding: u3 = 0,
250
279
 
280
+ _: u1 = 0,
281
+
251
282
  pub fn format(
252
283
  self: Duration,
253
284
  comptime fmt: []const u8,
@@ -257,27 +288,22 @@ pub const Duration = struct {
257
288
  _ = .{ fmt, opts };
258
289
  try writer.writeByte('(');
259
290
  var printed = false;
260
- inline for (@typeInfo(Duration).Struct.fields) |field| {
291
+ inline for (@field(@typeInfo(Duration), @tagName(Struct)).fields) |field| {
261
292
  const val = @field(self, field.name);
262
293
  switch (@typeInfo(@TypeOf(val))) {
263
- .Int => if (val != 0) {
294
+ Int => if (val != 0) {
264
295
  if (printed) try writer.writeAll(", ");
265
- try writer.print("{s}:{d}", .{ field.name, val });
266
- printed = true;
267
- },
268
- .Array => {
269
- var total: usize = 0;
270
- for (val) |v| total += v;
271
- if (total > 0) {
272
- if (printed) try writer.writeAll(", ");
296
+ if (comptime std.mem.eql(u8, field.name, "sleeps")) {
273
297
  try writer.print("{s}:[", .{field.name});
274
- for (val, 0..) |v, i| {
298
+ for (0..6) |i| {
275
299
  if (i != 0) try writer.writeByte(',');
276
- try writer.print("{d}", .{v});
300
+ try writer.print("{d}", .{Sleeps.get(val, i)});
277
301
  }
278
302
  try writer.writeAll("]");
279
- printed = true;
303
+ } else {
304
+ try writer.print("{s}:{d}", .{ field.name, val });
280
305
  }
306
+ printed = true;
281
307
  },
282
308
  else => unreachable,
283
309
  }
@@ -365,7 +391,7 @@ pub fn Chance(comptime Rational: type) type {
365
391
 
366
392
  // If the move actually lands we can commit any past critical hit / damage rolls. Note
367
393
  // we can't rely on the presence or absence of a damage roll to determine whether a
368
- // "critical hit" was spurious or not as moves that do 1 or less damage don't rol for
394
+ // "critical hit" was spurious or not as moves that do 1 or less damage don't roll for
369
395
  // damage but can still crit (instead, whether or not a roll is deemed to be a no-op is
370
396
  // passed to the critical hit helper).
371
397
  //
@@ -381,7 +407,7 @@ pub fn Chance(comptime Rational: type) type {
381
407
  action.critical_hit = if (self.pending.crit) .true else .false;
382
408
  } else assert(!self.pending.glitch);
383
409
 
384
- if (self.pending.damage_roll > 0) {
410
+ if (self.pending.damage_roll > 0 and (!self.pending.glitch or self.pending.hit)) {
385
411
  try self.probability.update(1, 39);
386
412
  action.damage = self.pending.damage_roll;
387
413
  }
@@ -408,14 +434,13 @@ pub fn Chance(comptime Rational: type) type {
408
434
 
409
435
  var d = self.durations.get(player);
410
436
 
411
- const out = d.sleeps[0];
412
- d.sleeps[0] = d.sleeps[slot - 1];
413
- d.sleeps[slot - 1] = out;
437
+ const out = Sleeps.get(d.sleeps, 0);
438
+ d.sleeps = Sleeps.set(d.sleeps, 0, Sleeps.get(d.sleeps, slot - 1));
439
+ d.sleeps = Sleeps.set(d.sleeps, slot - 1, out);
414
440
 
415
441
  d.confusion = 0;
416
442
  d.disable = 0;
417
- d.bide = 0;
418
- d.thrashing = 0;
443
+ d.attacking = 0;
419
444
  d.binding = 0;
420
445
 
421
446
  self.durations.get(player.foe()).binding = 0;
@@ -544,7 +569,8 @@ pub fn Chance(comptime Rational: type) type {
544
569
  .None => {
545
570
  @field(a, @tagName(field)) = .None;
546
571
  if (field == .sleep) {
547
- self.durations.get(player).sleeps[0] = 0;
572
+ var d = self.durations.get(player);
573
+ d.sleeps = Sleeps.set(d.sleeps, 0, 0);
548
574
  } else {
549
575
  @field(self.durations.get(player), @tagName(field)) = 0;
550
576
  }
@@ -558,7 +584,8 @@ pub fn Chance(comptime Rational: type) type {
558
584
  });
559
585
  @field(a, @tagName(field)) = .started;
560
586
  if (field == .sleep) {
561
- self.durations.get(player).sleeps[0] = 1;
587
+ var d = self.durations.get(player);
588
+ d.sleeps = Sleeps.set(d.sleeps, 0, 1);
562
589
  } else {
563
590
  @field(self.durations.get(player), @tagName(field)) = 1;
564
591
  }
@@ -575,19 +602,19 @@ pub fn Chance(comptime Rational: type) type {
575
602
  a.sleep = obs;
576
603
 
577
604
  var d = self.durations.get(player);
578
- const n = d.sleeps[0];
605
+ const n = Sleeps.get(d.sleeps, 0);
579
606
 
580
607
  if (obs == .None) {
581
- d.sleeps[0] = 0;
608
+ d.sleeps = Sleeps.set(d.sleeps, 0, 0);
582
609
  } else if (obs == .ended) {
583
610
  assert(n >= 1 and n <= 7);
584
611
  if (n != 7) try self.probability.update(1, 8 - @as(u4, n));
585
- d.sleeps[0] = 0;
612
+ d.sleeps = Sleeps.set(d.sleeps, 0, 0);
586
613
  } else {
587
614
  assert(obs == .continuing);
588
615
  assert(n >= 1 and n < 7);
589
616
  try self.probability.update(8 - @as(u4, n) - 1, 8 - @as(u4, n));
590
- d.sleeps[0] += 1;
617
+ d.sleeps = Sleeps.set(d.sleeps, 0, n + 1);
591
618
  }
592
619
  }
593
620
 
@@ -635,38 +662,25 @@ pub fn Chance(comptime Rational: type) type {
635
662
  }
636
663
  }
637
664
 
638
- pub fn bide(self: *Self, player: Player, obs: Optional(Observation)) Error!void {
639
- return self.attacking(.bide, player, obs);
640
- }
641
-
642
- pub fn thrashing(self: *Self, player: Player, obs: Optional(Observation)) Error!void {
643
- return self.attacking(.thrashing, player, obs);
644
- }
645
-
646
- fn attacking(
647
- self: *Self,
648
- comptime field: Action.Field,
649
- player: Player,
650
- obs: Optional(Observation),
651
- ) Error!void {
665
+ pub fn attacking(self: *Self, player: Player, obs: Optional(Observation)) Error!void {
652
666
  if (!enabled) return;
653
667
 
654
- const f = @tagName(field);
655
668
  var a = self.actions.get(player);
656
- assert(@field(a, f) == .None or @field(a, f) == .started);
657
- @field(a, f) = obs;
669
+ assert(a.attacking == .None or a.attacking == .started);
670
+ a.attacking = obs;
658
671
 
659
672
  var d = self.durations.get(player);
660
- const n = @field(d, f);
673
+ const n = d.attacking;
661
674
  if (obs == .ended) {
675
+ // "3-4 turns" includes the turn for the initial attack *plus* the forced attacks
662
676
  assert(n >= 2 and n <= 3);
663
677
  if (n != 3) try self.probability.update(1, 4 - @as(u4, n));
664
- @field(d, f) = 0;
678
+ d.attacking = 0;
665
679
  } else {
666
680
  assert(obs == .continuing);
667
681
  assert(n >= 1 and n < 3);
668
682
  if (n > 1) try self.probability.update(4 - @as(u4, n) - 1, 4 - @as(u4, n));
669
- @field(d, f) += 1;
683
+ d.attacking += 1;
670
684
  }
671
685
  }
672
686
 
@@ -685,6 +699,7 @@ pub fn Chance(comptime Rational: type) type {
685
699
  const q: u4 = if (n < 3) 8 - ((n - 1) * p) else 2;
686
700
 
687
701
  if (obs == .ended) {
702
+ // "2-5 turns" includes the turn for the initial attack *plus* the forced attacks
688
703
  assert(n >= 1 and n <= 4);
689
704
  if (n != 4) try self.probability.update(p, q);
690
705
  d.binding = 0;
@@ -710,7 +725,7 @@ pub fn Chance(comptime Rational: type) type {
710
725
  self.actions.get(player).metronome = move;
711
726
  }
712
727
 
713
- pub fn incrementPP(self: *Self, player: Player, n: u4) bool {
728
+ pub fn pp(self: *Self, player: Player, n: u4) bool {
714
729
  if (!enabled) return true;
715
730
 
716
731
  var a = self.actions.get(player);
@@ -818,16 +833,16 @@ test "Chance.damage" {
818
833
 
819
834
  try chance.damage(.P1, 217);
820
835
  if (showdown) {
821
- try expectValue(217, chance.actions.p1.damage);
836
+ try expectValue(@as(u8, 217), chance.actions.p1.damage);
822
837
  try expectProbability(&chance.probability, 1, 39);
823
838
  } else {
824
839
  try expectProbability(&chance.probability, 1, 1);
825
- try expectValue(0, chance.actions.p1.damage);
840
+ try expectValue(@as(u8, 0), chance.actions.p1.damage);
826
841
 
827
842
  try chance.commit(.P1, .hit);
828
843
 
829
844
  try expectProbability(&chance.probability, 1, 39);
830
- try expectValue(217, chance.actions.p1.damage);
845
+ try expectValue(@as(u8, 217), chance.actions.p1.damage);
831
846
  }
832
847
  }
833
848
 
@@ -879,13 +894,13 @@ test "Chance.moveSlot" {
879
894
 
880
895
  try chance.moveSlot(.P2, 2, &ms, 2);
881
896
  try expectProbability(&chance.probability, 1, 2);
882
- try expectValue(2, chance.actions.p2.move_slot);
897
+ try expectValue(@as(u4, 2), chance.actions.p2.move_slot);
883
898
 
884
899
  chance.reset();
885
900
 
886
901
  try chance.moveSlot(.P1, 1, &ms, 0);
887
902
  try expectProbability(&chance.probability, 1, 3);
888
- try expectValue(1, chance.actions.p1.move_slot);
903
+ try expectValue(@as(u4, 1), chance.actions.p1.move_slot);
889
904
  }
890
905
 
891
906
  test "Chance.multiHit" {
@@ -893,43 +908,43 @@ test "Chance.multiHit" {
893
908
 
894
909
  try chance.multiHit(.P1, 3);
895
910
  try expectProbability(&chance.probability, 3, 8);
896
- try expectValue(3, chance.actions.p1.multi_hit);
911
+ try expectValue(@as(u4, 3), chance.actions.p1.multi_hit);
897
912
 
898
913
  chance.reset();
899
914
 
900
915
  try chance.multiHit(.P2, 5);
901
916
  try expectProbability(&chance.probability, 1, 8);
902
- try expectValue(5, chance.actions.p2.multi_hit);
917
+ try expectValue(@as(u4, 5), chance.actions.p2.multi_hit);
903
918
  }
904
919
 
905
920
  test "Chance.duration" {
906
921
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
907
922
 
908
923
  chance.duration(.P1, 2);
909
- try expectValue(2, chance.actions.p1.duration);
924
+ try expectValue(@as(u4, 2), chance.actions.p1.duration);
910
925
 
911
926
  chance.reset();
912
927
 
913
928
  chance.duration(.P2, 4);
914
- try expectValue(4, chance.actions.p2.duration);
929
+ try expectValue(@as(u4, 4), chance.actions.p2.duration);
915
930
  }
916
931
 
917
932
  test "Chance.sleep" {
918
933
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
919
934
 
920
935
  for ([_]u8{ 7, 6, 5, 4, 3, 2, 1 }, 1..8) |d, i| {
921
- chance.durations.p1.sleeps[0] = @intCast(i);
936
+ chance.durations.p1.sleeps = Sleeps.set(chance.durations.p1.sleeps, 0, @intCast(i));
922
937
  try chance.sleep(.P1, .ended);
923
938
  try expectProbability(&chance.probability, 1, d);
924
- try expectValue(0, chance.durations.p1.sleeps[0]);
939
+ try expectValue(@as(u3, 0), Sleeps.get(chance.durations.p1.sleeps, 0));
925
940
 
926
941
  chance.reset();
927
942
 
928
943
  if (i < 7) {
929
- chance.durations.p1.sleeps[0] = @intCast(i);
944
+ chance.durations.p1.sleeps = Sleeps.set(chance.durations.p1.sleeps, 0, @intCast(i));
930
945
  try chance.sleep(.P1, .continuing);
931
946
  try expectProbability(&chance.probability, d - 1, d);
932
- try expectValue(@as(u3, @intCast(i)) + 1, chance.durations.p1.sleeps[0]);
947
+ try expectValue(@as(u3, @intCast(i)) + 1, Sleeps.get(chance.durations.p1.sleeps, 0));
933
948
 
934
949
  chance.reset();
935
950
  }
@@ -944,7 +959,7 @@ test "Chance.confusion" {
944
959
  chance.durations.p2.confusion = @intCast(i);
945
960
  try chance.confusion(.P2, .ended);
946
961
  try expectProbability(&chance.probability, 1, d);
947
- try expectValue(0, chance.durations.p2.confusion);
962
+ try expectValue(@as(u3, 0), chance.durations.p2.confusion);
948
963
 
949
964
  chance.reset();
950
965
  }
@@ -967,7 +982,7 @@ test "Chance.disable" {
967
982
  chance.durations.p1.disable = @intCast(i);
968
983
  try chance.disable(.P1, .ended);
969
984
  try expectProbability(&chance.probability, 1, d);
970
- try expectValue(0, chance.durations.p1.disable);
985
+ try expectValue(@as(u4, 0), chance.durations.p1.disable);
971
986
 
972
987
  chance.reset();
973
988
 
@@ -985,25 +1000,23 @@ test "Chance.disable" {
985
1000
  test "Chance.attacking" {
986
1001
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
987
1002
 
988
- inline for (.{ .bide, .thrashing }) |f| {
989
- for ([_]u8{ 1, 2, 1 }, 1..4) |d, i| {
990
- if (i > 1) {
991
- @field(chance.durations.p2, @tagName(f)) = @intCast(i);
992
- try chance.attacking(f, .P2, .ended);
993
- try expectProbability(&chance.probability, 1, d);
994
- try expectValue(0, @field(chance.durations.p2, @tagName(f)));
1003
+ for ([_]u8{ 1, 2, 1 }, 1..4) |d, i| {
1004
+ if (i > 1) {
1005
+ chance.durations.p2.attacking = @intCast(i);
1006
+ try chance.attacking(.P2, .ended);
1007
+ try expectProbability(&chance.probability, 1, d);
1008
+ try expectValue(@as(u3, 0), chance.durations.p2.attacking);
995
1009
 
996
- chance.reset();
997
- }
1010
+ chance.reset();
1011
+ }
998
1012
 
999
- if (i < 3) {
1000
- @field(chance.durations.p2, @tagName(f)) = @intCast(i);
1001
- try chance.attacking(f, .P2, .continuing);
1002
- try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
1003
- try expectValue(@as(u3, @intCast(i)) + 1, @field(chance.durations.p2, @tagName(f)));
1013
+ if (i < 3) {
1014
+ chance.durations.p2.attacking = @intCast(i);
1015
+ try chance.attacking(.P2, .continuing);
1016
+ try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
1017
+ try expectValue(@as(u3, @intCast(i)) + 1, chance.durations.p2.attacking);
1004
1018
 
1005
- chance.reset();
1006
- }
1019
+ chance.reset();
1007
1020
  }
1008
1021
  }
1009
1022
  }
@@ -1018,7 +1031,7 @@ test "Chance.binding" {
1018
1031
  chance.durations.p1.binding = @intCast(i);
1019
1032
  try chance.binding(.P1, .ended);
1020
1033
  try expectProbability(&chance.probability, p, q);
1021
- try expectValue(0, chance.durations.p1.binding);
1034
+ try expectValue(@as(u3, 0), chance.durations.p1.binding);
1022
1035
 
1023
1036
  chance.reset();
1024
1037
 
@@ -1038,7 +1051,7 @@ test "Chance.psywave" {
1038
1051
 
1039
1052
  try chance.psywave(.P2, 100, 150);
1040
1053
  try expectProbability(&chance.probability, 1, 150);
1041
- try expectValue(101, chance.actions.p2.psywave);
1054
+ try expectValue(@as(u8, 101), chance.actions.p2.psywave);
1042
1055
  }
1043
1056
 
1044
1057
  test "Chance.metronome" {
@@ -1149,11 +1162,7 @@ const Null = struct {
1149
1162
  _ = .{ self, player, obs };
1150
1163
  }
1151
1164
 
1152
- pub fn bide(self: Null, player: Player, obs: Optional(Observation)) Error!void {
1153
- _ = .{ self, player, obs };
1154
- }
1155
-
1156
- pub fn thrashing(self: Null, player: Player, obs: Optional(Observation)) Error!void {
1165
+ pub fn attacking(self: Null, player: Player, obs: Optional(Observation)) Error!void {
1157
1166
  _ = .{ self, player, obs };
1158
1167
  }
1159
1168
 
@@ -1169,7 +1178,7 @@ const Null = struct {
1169
1178
  _ = .{ self, player, move };
1170
1179
  }
1171
1180
 
1172
- pub fn incrementPP(self: Null, player: Player, n: u4) bool {
1181
+ pub fn pp(self: Null, player: Player, n: u4) bool {
1173
1182
  _ = .{ self, player, n };
1174
1183
  return true;
1175
1184
  }
@@ -1,12 +1,10 @@
1
1
  //! Code generated by `tools/generate` - manual edits will be overwritten.
2
2
 
3
- const std = @import("std");
4
-
5
- const rng = @import("../../common/rng.zig");
6
3
  const gen1 = @import("../../gen1/data.zig");
4
+ const rng = @import("../../common/rng.zig");
5
+ const std = @import("std");
7
6
 
8
7
  const assert = std.debug.assert;
9
-
10
8
  const percent = rng.Gen12.percent;
11
9
  const Type = gen1.Type;
12
10
 
@@ -1,11 +1,9 @@
1
1
  //! Code generated by `tools/generate` - manual edits will be overwritten.
2
2
 
3
- const std = @import("std");
4
-
5
3
  const gen1 = @import("../../gen1/data.zig");
4
+ const std = @import("std");
6
5
 
7
6
  const assert = std.debug.assert;
8
-
9
7
  const Stats = gen1.Stats;
10
8
  const Types = gen1.Types;
11
9
 
@@ -1,8 +1,7 @@
1
1
  //! Code generated by `tools/generate` - manual edits will be overwritten.
2
2
 
3
- const std = @import("std");
4
-
5
3
  const gen1 = @import("../../gen1/data.zig");
4
+ const std = @import("std");
6
5
 
7
6
  const assert = std.debug.assert;
8
7
  const Effectiveness = gen1.Effectiveness;