@pkmn/engine 0.1.0-dev.89cc1c98 → 0.1.0-dev.8b192003

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 (42) hide show
  1. package/LICENSE +1 -3
  2. package/README.md +44 -19
  3. package/build/pkg/addon.js +6 -7
  4. package/build/pkg/addon.js.map +1 -1
  5. package/build/pkg/data.d.ts +4 -4
  6. package/build/pkg/data.js.map +1 -1
  7. package/build/pkg/gen1.js.map +1 -1
  8. package/build/pkg/index.d.ts +2 -1
  9. package/build/pkg/index.js.map +1 -1
  10. package/build/pkg/protocol.js +5 -5
  11. package/build/pkg/protocol.js.map +1 -1
  12. package/build/test/display.js +2 -2
  13. package/build/test/display.js.map +1 -1
  14. package/build/tools/debug.js +5 -4
  15. package/build/tools/debug.js.map +1 -1
  16. package/build.zig +100 -102
  17. package/package.json +31 -23
  18. package/src/bin/install-pkmn-engine +26 -18
  19. package/src/lib/common/data.zig +4 -4
  20. package/src/lib/common/debug.zig +2 -2
  21. package/src/lib/common/optional.zig +1 -1
  22. package/src/lib/common/options.zig +2 -0
  23. package/src/lib/common/protocol.zig +393 -396
  24. package/src/lib/common/rational.zig +109 -15
  25. package/src/lib/common/rng.zig +20 -11
  26. package/src/lib/gen1/calc.zig +478 -92
  27. package/src/lib/gen1/chance.zig +195 -428
  28. package/src/lib/gen1/data/species.zig +1 -1
  29. package/src/lib/gen1/data.zig +21 -21
  30. package/src/lib/gen1/helpers.zig +88 -534
  31. package/src/lib/gen1/mechanics.zig +377 -360
  32. package/src/lib/gen2/chance.zig +25 -457
  33. package/src/lib/gen2/data.zig +13 -11
  34. package/src/lib/gen2/generated.zig +27 -78
  35. package/src/lib/gen2/helpers.zig +37 -7
  36. package/src/lib/gen2/mechanics.zig +1022 -456
  37. package/src/lib/{binding/node.zig → node.zig} +9 -12
  38. package/src/lib/pkmn.zig +27 -12
  39. package/src/lib/{binding/wasm.zig → wasm.zig} +2 -1
  40. package/src/test/display/pkmn.html.tmpl +5 -5
  41. package/src/lib/gen1/README.md +0 -894
  42. package/src/lib/gen2/README.md +0 -330
@@ -14,7 +14,7 @@ const util = @import("../common/util.zig");
14
14
  const Player = @import("../common/data.zig").Player;
15
15
  const Optional = @import("../common/optional.zig").Optional;
16
16
 
17
- const data = @import("./data.zig");
17
+ const data = @import("data.zig");
18
18
 
19
19
  const enabled = options.chance;
20
20
  const showdown = options.showdown;
@@ -42,12 +42,6 @@ pub const Actions = extern struct {
42
42
  return if (player == .P1) &self.p1 else &self.p2;
43
43
  }
44
44
 
45
- /// Perform a reset by clearing fields which should not persist across updates.
46
- pub fn reset(self: *Actions) void {
47
- self.p1.reset();
48
- self.p2.reset();
49
- }
50
-
51
45
  /// Returns true if `a` is equal to `b`.
52
46
  pub fn eql(a: Actions, b: Actions) bool {
53
47
  return @as(u128, @bitCast(a.p1)) == @as(u128, @bitCast(b.p1)) and
@@ -64,15 +58,6 @@ pub const Actions = extern struct {
64
58
  const b_val = @field(@field(b, player.name), field.name);
65
59
 
66
60
  switch (@typeInfo(@TypeOf(a_val))) {
67
- .Struct => inline for (@typeInfo(@TypeOf(a_val)).Struct.fields) |f| {
68
- const a_val_f = @field(a_val, f.name);
69
- const b_val_f = @field(b_val, f.name);
70
- switch (@typeInfo(@TypeOf(a_val_f))) {
71
- .Int => if ((a_val_f > 0) != (b_val_f > 0)) return false,
72
- .Bool => if (a_val_f != b_val_f) return false,
73
- else => unreachable,
74
- }
75
- },
76
61
  .Enum => if ((@intFromEnum(a_val) > 0) != (@intFromEnum(b_val) > 0))
77
62
  return false,
78
63
  .Int => if ((a_val > 0) != (b_val > 0)) return false,
@@ -97,16 +82,11 @@ pub const Actions = extern struct {
97
82
  }
98
83
  };
99
84
 
85
+ // TODO: ziglang/zig#19730
100
86
  test Actions {
101
87
  const a: Actions = .{ .p1 = .{ .hit = .true, .critical_hit = .false, .damage = 245 } };
102
88
  const b: Actions = .{ .p1 = .{ .hit = .false, .critical_hit = .true, .damage = 246 } };
103
89
  const c: Actions = .{ .p1 = .{ .hit = .true } };
104
- const d: Actions = .{ .p2 = .{ .hit = .true, .durations = .{ .sleep = 2 } } };
105
- const e: Actions = .{ .p2 = .{ .hit = .false, .durations = .{ .sleep = 4 } } };
106
- const f: Actions = .{ .p1 = .{ .hit = .false, .durations = .{ .sleep = 4 } } };
107
- const g: Actions = .{ .p1 = .{ .hit = .false, .durations = .{ .confusion = 1 } } };
108
- const h: Actions =
109
- .{ .p1 = .{ .hit = .false, .durations = .{ .confusion = 1, .thrash = true } } };
110
90
 
111
91
  try expect(a.eql(a));
112
92
  try expect(!a.eql(b));
@@ -119,10 +99,6 @@ test Actions {
119
99
  try expect(b.matches(a));
120
100
  try expect(!a.matches(c));
121
101
  try expect(!c.matches(a));
122
- try expect(d.matches(e));
123
- try expect(!d.matches(f));
124
- try expect(!g.matches(h));
125
- try expect(h.matches(h));
126
102
  }
127
103
 
128
104
  /// Information about the RNG that was observed during a Generation II battle `update` for a
@@ -188,20 +164,10 @@ pub const Action = packed struct(u128) {
188
164
  /// If not None, the Move to return for Rolls.metronome.
189
165
  metronome: Move = .None,
190
166
 
191
- _: u16 = 0,
192
-
193
- /// Observed values of various durations. Does not influence future RNG calls. TODO
194
- durations: Duration = .{},
195
-
196
- pub const DURATIONS: u128 = 0xFFFFFFFF00000000_0000000000000000;
167
+ _: u48 = 0, // TODO
197
168
 
198
169
  pub const Field = std.meta.FieldEnum(Action);
199
170
 
200
- /// Perform a reset by clearing fields which should not persist across updates.
201
- pub fn reset(self: *Action) void {
202
- self.* = @bitCast(@as(u128, @bitCast(self.*)) & DURATIONS);
203
- }
204
-
205
171
  pub fn format(a: Action, comptime f: []const u8, o: std.fmt.FormatOptions, w: anytype) !void {
206
172
  _ = .{ f, o };
207
173
  try fmt(a, w, false);
@@ -213,18 +179,6 @@ pub const Action = packed struct(u128) {
213
179
  inline for (@typeInfo(Action).Struct.fields) |field| {
214
180
  const val = @field(self, field.name);
215
181
  switch (@typeInfo(@TypeOf(val))) {
216
- .Struct => inline for (@typeInfo(@TypeOf(val)).Struct.fields) |f| {
217
- const v = @field(val, f.name);
218
- if (v != 0) {
219
- if (printed) try writer.writeAll(", ");
220
- if (shape) {
221
- try writer.print("{s}:?", .{f.name});
222
- } else {
223
- try writer.print("{s}:{d}", .{ f.name, v });
224
- }
225
- printed = true;
226
- }
227
- },
228
182
  .Enum => if (val != .None) {
229
183
  if (printed) try writer.writeAll(", ");
230
184
  if (shape) {
@@ -255,36 +209,6 @@ pub const Action = packed struct(u128) {
255
209
  }
256
210
  };
257
211
 
258
- test Action {
259
- var a: Action = .{ .hit = .true, .durations = .{ .sleep = 3 }, .damage = 225 };
260
- a.reset();
261
-
262
- try expectEqual(Action{ .hit = .None, .durations = .{ .sleep = 3 }, .damage = 0 }, a);
263
- }
264
-
265
- /// Observed values for various durations that need to be tracked in order to properly
266
- /// deduplicate transitions with a primary key. TODO
267
- pub const Duration = packed struct(u32) {
268
- /// The number of turns a Pokémon has been observed to be sleeping.
269
- sleep: u3 = 0,
270
- /// The number of turns a Pokémon has been observed to be confused.
271
- confusion: u3 = 0,
272
- /// TODO
273
- thrash: bool = false,
274
- /// The number of turns a Pokémon has been observed to be disabled.
275
- disable: u4 = 0,
276
- /// The number of turns a Pokémon has been observed to be attacking.
277
- attacking: u3 = 0,
278
- /// The number of turns a Pokémon has been observed to be binding their opponent.
279
- binding: u3 = 0,
280
- /// The number of turns a Pokémon has been observed to be encored.
281
- encore: u3 = 0,
282
-
283
- _: u12 = 0,
284
-
285
- pub const Field = std.meta.FieldEnum(Duration);
286
- };
287
-
288
212
  /// Tracks chance actions and their associated probability during a Generation II battle update when
289
213
  /// `options.chance` is enabled.
290
214
  pub fn Chance(comptime Rational: type) type {
@@ -297,37 +221,15 @@ pub fn Chance(comptime Rational: type) type {
297
221
  /// RNG events were observed during a battle `update`.
298
222
  actions: Actions = .{},
299
223
 
300
- // Tracks the observed sleep durations for the Pokémon in both player's parties. Unlike
301
- // other durations which are all tied to volatiles, sleep's counter persists through
302
- // switching and so we must store it here. The indices of these arrays correspond to the
303
- // `order` field of a Side. This information could be stored in actions but size is a
304
- // concern so this is tracked separately as actions only purports to track RNG events
305
- // observed during a single `update` (not across updates).
306
- sleeps: [2][6]u3 = .{ .{0} ** 6, .{0} ** 6 },
307
-
308
224
  /// Possible error returned by operations tracking chance probability.
309
225
  pub const Error = Rational.Error;
310
226
 
311
227
  /// Convenience helper to clear fields which typically should be cleared between updates.
312
228
  pub fn reset(self: *Self) void {
313
- self.probability.reset();
314
- self.actions.reset();
315
- // TODO: self.pending = .{};
316
- }
317
-
318
- pub fn switched(self: *Self, player: Player, in: u8, out: u8) void {
319
229
  if (!enabled) return;
320
230
 
321
- assert(in >= 1 and in <= 6);
322
- assert(out >= 1 and out <= 6);
323
-
324
- var action = self.actions.get(player);
325
-
326
- const slp = action.durations.sleep;
327
- action.durations = .{};
328
-
329
- self.sleeps[@intFromEnum(player)][out - 1] = slp;
330
- action.durations.sleep = @intCast(self.sleeps[@intFromEnum(player)][in - 1]);
231
+ self.probability.reset();
232
+ self.actions = .{};
331
233
  }
332
234
 
333
235
  pub fn speedTie(self: *Self, p1: bool) Error!void {
@@ -517,123 +419,11 @@ pub fn Chance(comptime Rational: type) type {
517
419
  self.actions.get(player).multi_hit = n;
518
420
  }
519
421
 
520
- pub fn duration(
521
- self: *Self,
522
- comptime field: Duration.Field,
523
- player: Player,
524
- target: Player,
525
- turns: u4,
526
- ) void {
422
+ pub fn duration(self: *Self, player: Player, turns: u4) void {
527
423
  if (!enabled) return;
528
424
 
529
- var durations = &self.actions.get(target).durations;
530
- assert(@field(durations, @tagName(field)) == 0 or
531
- (field == .confusion and player == target));
532
- @field(durations, @tagName(field)) = 1;
533
- if (field == .confusion) durations.thrash = player == target;
534
425
  self.actions.get(player).duration = if (options.key) 1 else turns;
535
426
  }
536
-
537
- pub fn sleep(self: *Self, player: Player, turns: u4) Error!void {
538
- if (!enabled) return;
539
-
540
- var durations = &self.actions.get(player).durations;
541
- const n = durations.sleep;
542
- if (turns == 0) {
543
- assert(n >= 1 and n <= 6);
544
- if (n != 6) try self.probability.update(1, 7 - @as(u4, n));
545
- durations.sleep = 0;
546
- } else {
547
- assert(n >= 1 and n < 6);
548
- try self.probability.update(7 - @as(u4, n) - 1, 7 - @as(u4, n));
549
- durations.sleep += 1;
550
- }
551
- }
552
-
553
- pub fn confusion(self: *Self, player: Player, turns: u4) Error!void {
554
- if (!enabled) return;
555
-
556
- var durations = &self.actions.get(player).durations;
557
- const n = durations.confusion;
558
- const hi: u8 = if (durations.thrash) 3 else 5;
559
- const p = hi + 1;
560
- if (turns == 0) {
561
- assert(n >= 2 and n <= hi);
562
- if (n != hi) try self.probability.update(1, p - @as(u4, n));
563
- durations.confusion = 0;
564
- } else {
565
- assert(n >= 1 and n < hi);
566
- if (n > 1) try self.probability.update(p - @as(u4, n) - 1, p - @as(u4, n));
567
- durations.confusion += 1;
568
- }
569
- }
570
-
571
- pub fn disable(self: *Self, player: Player, turns: u4) Error!void {
572
- if (!enabled) return;
573
-
574
- var durations = &self.actions.get(player).durations;
575
- const n = durations.disable;
576
- const hi = if (showdown) 5 else 8;
577
- const p = hi + 1;
578
- if (turns == 0) {
579
- assert(n >= 2 and n <= hi);
580
- if (n != hi) try self.probability.update(1, p - n);
581
- durations.disable = 0;
582
- } else {
583
- assert(n >= 1 and n < hi);
584
- if (n > 1) try self.probability.update(p - n - 1, p - n);
585
- durations.disable += 1;
586
- }
587
- }
588
-
589
- pub fn attacking(self: *Self, player: Player, turns: u4) Error!void {
590
- if (!enabled) return;
591
-
592
- var durations = &self.actions.get(player).durations;
593
- const n = durations.attacking;
594
- if (turns == 0) {
595
- assert(n >= 2 and n <= 3);
596
- if (n != 3) try self.probability.update(1, 4 - @as(u4, n));
597
- durations.attacking = 0;
598
- } else {
599
- assert(n >= 1 and n < 3);
600
- if (n > 1) try self.probability.update(4 - @as(u4, n) - 1, 4 - @as(u4, n));
601
- durations.attacking += 1;
602
- }
603
- }
604
-
605
- pub fn binding(self: *Self, player: Player, turns: u4) Error!void {
606
- if (!enabled) return;
607
-
608
- var durations = &self.actions.get(player).durations;
609
- const n = durations.binding;
610
- if (turns == 0) {
611
- assert(n >= 2 and n <= 5);
612
- if (n != 5) try self.probability.update(1, 6 - @as(u4, n));
613
- durations.binding = 0;
614
- } else {
615
- assert(n >= 1 and n < 5);
616
- if (n > 1) try self.probability.update(6 - @as(u4, n) - 1, 6 - @as(u4, n));
617
- durations.binding += 1;
618
- }
619
- }
620
-
621
- // TODO: consider sharing implementation with binding
622
- pub fn encore(self: *Self, player: Player, turns: u4) Error!void {
623
- if (!enabled) return;
624
-
625
- var durations = &self.actions.get(player).durations;
626
- const n = durations.encore;
627
- if (turns == 0) {
628
- assert(n >= 2 and n <= 5);
629
- if (n != 5) try self.probability.update(1, 6 - @as(u4, n));
630
- durations.encore = 0;
631
- } else {
632
- assert(n >= 1 and n < 5);
633
- if (n > 1) try self.probability.update(6 - @as(u4, n) - 1, 6 - @as(u4, n));
634
- durations.encore += 1;
635
- }
636
- }
637
427
  };
638
428
  }
639
429
 
@@ -699,7 +489,7 @@ test "Chance.damage" {
699
489
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
700
490
 
701
491
  try chance.damage(.P1, 217);
702
- try expectValue(@as(u8, 217), chance.actions.p1.damage);
492
+ try expectValue(217, chance.actions.p1.damage);
703
493
  try expectProbability(&chance.probability, 1, 39);
704
494
  }
705
495
 
@@ -824,7 +614,7 @@ test "Chance.present" {
824
614
  } else {
825
615
  try expectProbability(&chance.probability, 25, 256);
826
616
  }
827
- try expectValue(@as(u3, 4), chance.actions.p2.present);
617
+ try expectValue(4, chance.actions.p2.present);
828
618
 
829
619
  chance.reset();
830
620
 
@@ -834,7 +624,7 @@ test "Chance.present" {
834
624
  } else {
835
625
  try expectProbability(&chance.probability, 51, 256);
836
626
  }
837
- try expectValue(@as(u3, 1), chance.actions.p1.present);
627
+ try expectValue(1, chance.actions.p1.present);
838
628
  }
839
629
 
840
630
  test "Chance.magnitude" {
@@ -846,7 +636,7 @@ test "Chance.magnitude" {
846
636
  } else {
847
637
  try expectProbability(&chance.probability, 13, 256);
848
638
  }
849
- try expectValue(@as(u3, 7), chance.actions.p2.magnitude);
639
+ try expectValue(7, chance.actions.p2.magnitude);
850
640
 
851
641
  chance.reset();
852
642
 
@@ -856,7 +646,7 @@ test "Chance.magnitude" {
856
646
  } else {
857
647
  try expectProbability(&chance.probability, 51, 256);
858
648
  }
859
- try expectValue(@as(u3, 5), chance.actions.p1.magnitude);
649
+ try expectValue(5, chance.actions.p1.magnitude);
860
650
  }
861
651
 
862
652
  test "Chance.tripleKick" {
@@ -864,7 +654,7 @@ test "Chance.tripleKick" {
864
654
 
865
655
  try chance.tripleKick(.P1, 2);
866
656
  try expectProbability(&chance.probability, 1, 3);
867
- try expectValue(@as(u2, 2), chance.actions.p1.triple_kick);
657
+ try expectValue(2, chance.actions.p1.triple_kick);
868
658
  }
869
659
 
870
660
  test "Chance.spite" {
@@ -872,7 +662,7 @@ test "Chance.spite" {
872
662
 
873
663
  try chance.spite(.P1, 3);
874
664
  try expectProbability(&chance.probability, 1, 4);
875
- try expectValue(@as(u3, 3), chance.actions.p1.spite);
665
+ try expectValue(3, chance.actions.p1.spite);
876
666
  }
877
667
 
878
668
  test "Chance.conversion2" {
@@ -899,7 +689,7 @@ test "Chance.psywave" {
899
689
 
900
690
  try chance.psywave(.P2, 100, 150);
901
691
  try expectProbability(&chance.probability, 1, 150);
902
- try expectValue(@as(u8, 100), chance.actions.p2.psywave);
692
+ try expectValue(100, chance.actions.p2.psywave);
903
693
  }
904
694
 
905
695
  test "Chance.metronome" {
@@ -915,19 +705,19 @@ test "Chance.moveSlot" {
915
705
 
916
706
  try chance.moveSlot(.P2, 2, 2);
917
707
  try expectProbability(&chance.probability, 1, 2);
918
- try expectValue(@as(u4, 2), chance.actions.p2.move_slot);
708
+ try expectValue(2, chance.actions.p2.move_slot);
919
709
 
920
710
  chance.reset();
921
711
 
922
712
  try chance.moveSlot(.P1, 1, 3);
923
713
  try expectProbability(&chance.probability, 1, 3);
924
- try expectValue(@as(u4, 1), chance.actions.p1.move_slot);
714
+ try expectValue(1, chance.actions.p1.move_slot);
925
715
 
926
716
  chance.reset();
927
717
 
928
718
  try chance.moveSlot(.P1, 4, 1);
929
719
  try expectProbability(&chance.probability, 1, 1);
930
- try expectValue(@as(u4, 4), chance.actions.p1.move_slot);
720
+ try expectValue(4, chance.actions.p1.move_slot);
931
721
  }
932
722
 
933
723
  test "Chance.forceSwitch" {
@@ -935,19 +725,19 @@ test "Chance.forceSwitch" {
935
725
 
936
726
  try chance.forceSwitch(.P2, 2, 2);
937
727
  try expectProbability(&chance.probability, 1, 2);
938
- try expectValue(@as(u4, 2), chance.actions.p2.force_switch);
728
+ try expectValue(2, chance.actions.p2.force_switch);
939
729
 
940
730
  chance.reset();
941
731
 
942
732
  try chance.forceSwitch(.P1, 1, 3);
943
733
  try expectProbability(&chance.probability, 1, 3);
944
- try expectValue(@as(u4, 1), chance.actions.p1.force_switch);
734
+ try expectValue(1, chance.actions.p1.force_switch);
945
735
 
946
736
  chance.reset();
947
737
 
948
738
  try chance.forceSwitch(.P1, 4, 1);
949
739
  try expectProbability(&chance.probability, 1, 1);
950
- try expectValue(@as(u4, 4), chance.actions.p1.force_switch);
740
+ try expectValue(4, chance.actions.p1.force_switch);
951
741
  }
952
742
 
953
743
  test "Chance.multiHit" {
@@ -955,212 +745,20 @@ test "Chance.multiHit" {
955
745
 
956
746
  try chance.multiHit(.P1, 3);
957
747
  try expectProbability(&chance.probability, 3, 8);
958
- try expectValue(@as(u4, 3), chance.actions.p1.multi_hit);
748
+ try expectValue(3, chance.actions.p1.multi_hit);
959
749
 
960
750
  chance.reset();
961
751
 
962
752
  try chance.multiHit(.P2, 5);
963
753
  try expectProbability(&chance.probability, 1, 8);
964
- try expectValue(@as(u4, 5), chance.actions.p2.multi_hit);
754
+ try expectValue(5, chance.actions.p2.multi_hit);
965
755
  }
966
756
 
967
757
  test "Chance.duration" {
968
758
  var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
969
759
 
970
- chance.duration(.sleep, .P1, .P2, 2);
971
- try expectValue(@as(u4, 2), chance.actions.p1.duration);
972
- try expectValue(@as(u3, 1), chance.actions.p2.durations.sleep);
973
- }
974
-
975
- test "Chance.sleep" {
976
- var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
977
-
978
- for ([_]u8{ 6, 5, 4, 3, 2, 1 }, 1..7) |d, i| {
979
- chance.actions.p1.durations.sleep = @intCast(i);
980
- try chance.sleep(.P1, 0);
981
- try expectProbability(&chance.probability, 1, d);
982
- try expectValue(@as(u3, 0), chance.actions.p1.durations.sleep);
983
-
984
- chance.reset();
985
-
986
- if (i < 6) {
987
- chance.actions.p1.durations.sleep = @intCast(i);
988
- try chance.sleep(.P1, 1);
989
- try expectProbability(&chance.probability, d - 1, d);
990
- try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p1.durations.sleep);
991
-
992
- chance.reset();
993
- }
994
- }
995
- }
996
-
997
- test "Chance.confusion" {
998
- var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
999
-
1000
- chance.actions.p2.durations.thrash = false;
1001
- for ([_]u8{ 1, 4, 3, 2, 1 }, 1..6) |d, i| {
1002
- if (i > 1) {
1003
- chance.actions.p2.durations.confusion = @intCast(i);
1004
- try chance.confusion(.P2, 0);
1005
- try expectProbability(&chance.probability, 1, d);
1006
- try expectValue(@as(u3, 0), chance.actions.p2.durations.confusion);
1007
- try expectValue(false, chance.actions.p2.durations.thrash);
1008
-
1009
- chance.reset();
1010
- }
1011
-
1012
- if (i < 5) {
1013
- chance.actions.p2.durations.confusion = @intCast(i);
1014
- try chance.confusion(.P2, 1);
1015
- try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
1016
- try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations.confusion);
1017
- try expectValue(false, chance.actions.p2.durations.thrash);
1018
-
1019
- chance.reset();
1020
- }
1021
- }
1022
-
1023
- chance.reset();
1024
-
1025
- chance.actions.p2.durations.thrash = true;
1026
- for ([_]u8{ 1, 2, 1 }, 1..4) |d, i| {
1027
- if (i > 1) {
1028
- chance.actions.p2.durations.confusion = @intCast(i);
1029
- try chance.confusion(.P2, 0);
1030
- try expectProbability(&chance.probability, 1, d);
1031
- try expectValue(@as(u3, 0), chance.actions.p2.durations.confusion);
1032
- try expectValue(true, chance.actions.p2.durations.thrash);
1033
-
1034
- chance.reset();
1035
- }
1036
-
1037
- if (i < 3) {
1038
- chance.actions.p2.durations.confusion = @intCast(i);
1039
- try chance.confusion(.P2, 1);
1040
- try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
1041
- try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations.confusion);
1042
- try expectValue(true, chance.actions.p2.durations.thrash);
1043
-
1044
- chance.reset();
1045
- }
1046
- }
1047
- }
1048
-
1049
- test "Chance.disable" {
1050
- var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
1051
- if (showdown) {
1052
- for ([_]u8{ 1, 4, 3, 2, 1 }, 1..6) |d, i| {
1053
- if (i > 1) {
1054
- chance.actions.p2.durations.disable = @intCast(i);
1055
- try chance.disable(.P2, 0);
1056
- try expectProbability(&chance.probability, 1, d);
1057
- try expectValue(@as(u4, 0), chance.actions.p2.durations.disable);
1058
-
1059
- chance.reset();
1060
- }
1061
-
1062
- if (i < 5) {
1063
- chance.actions.p2.durations.disable = @intCast(i);
1064
- try chance.disable(.P2, 1);
1065
- try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
1066
- try expectValue(@as(u4, @intCast(i)) + 1, chance.actions.p2.durations.disable);
1067
-
1068
- chance.reset();
1069
- }
1070
- }
1071
- } else {
1072
- for ([_]u8{ 1, 7, 6, 5, 4, 3, 2, 1 }, 1..9) |d, i| {
1073
- if (i > 1) {
1074
- chance.actions.p2.durations.disable = @intCast(i);
1075
- try chance.disable(.P2, 0);
1076
- try expectProbability(&chance.probability, 1, d);
1077
- try expectValue(@as(u4, 0), chance.actions.p2.durations.disable);
1078
-
1079
- chance.reset();
1080
- }
1081
-
1082
- if (i < 8) {
1083
- chance.actions.p2.durations.disable = @intCast(i);
1084
- try chance.disable(.P2, 1);
1085
- try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
1086
- try expectValue(@as(u4, @intCast(i)) + 1, chance.actions.p2.durations.disable);
1087
-
1088
- chance.reset();
1089
- }
1090
- }
1091
- }
1092
- }
1093
-
1094
- test "Chance.attacking" {
1095
- var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
1096
-
1097
- for ([_]u8{ 1, 2, 1 }, 1..4) |d, i| {
1098
- if (i > 1) {
1099
- chance.actions.p2.durations.attacking = @intCast(i);
1100
- try chance.attacking(.P2, 0);
1101
- try expectProbability(&chance.probability, 1, d);
1102
- try expectValue(@as(u3, 0), chance.actions.p2.durations.attacking);
1103
-
1104
- chance.reset();
1105
- }
1106
-
1107
- if (i < 3) {
1108
- chance.actions.p2.durations.attacking = @intCast(i);
1109
- try chance.attacking(.P2, 1);
1110
- try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
1111
- try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations.attacking);
1112
-
1113
- chance.reset();
1114
- }
1115
- }
1116
- }
1117
-
1118
- test "Chance.binding" {
1119
- var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
1120
-
1121
- for ([_]u8{ 1, 4, 3, 2, 1 }, 1..6) |d, i| {
1122
- if (i > 1) {
1123
- chance.actions.p2.durations.binding = @intCast(i);
1124
- try chance.binding(.P2, 0);
1125
- try expectProbability(&chance.probability, 1, d);
1126
- try expectValue(@as(u3, 0), chance.actions.p2.durations.binding);
1127
-
1128
- chance.reset();
1129
- }
1130
-
1131
- if (i < 5) {
1132
- chance.actions.p2.durations.binding = @intCast(i);
1133
- try chance.binding(.P2, 1);
1134
- try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
1135
- try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations.binding);
1136
-
1137
- chance.reset();
1138
- }
1139
- }
1140
- }
1141
-
1142
- test "Chance.encore" {
1143
- var chance: Chance(rational.Rational(u64)) = .{ .probability = .{} };
1144
-
1145
- for ([_]u8{ 1, 4, 3, 2, 1 }, 1..6) |d, i| {
1146
- if (i > 1) {
1147
- chance.actions.p2.durations.encore = @intCast(i);
1148
- try chance.encore(.P2, 0);
1149
- try expectProbability(&chance.probability, 1, d);
1150
- try expectValue(@as(u3, 0), chance.actions.p2.durations.encore);
1151
-
1152
- chance.reset();
1153
- }
1154
-
1155
- if (i < 5) {
1156
- chance.actions.p2.durations.encore = @intCast(i);
1157
- try chance.encore(.P2, 1);
1158
- try expectProbability(&chance.probability, if (d > 1) d - 1 else d, d);
1159
- try expectValue(@as(u3, @intCast(i)) + 1, chance.actions.p2.durations.encore);
1160
-
1161
- chance.reset();
1162
- }
1163
- }
760
+ chance.duration(.P1, 2);
761
+ try expectValue(2, chance.actions.p1.duration);
1164
762
  }
1165
763
 
1166
764
  pub fn expectProbability(r: anytype, p: u64, q: u64) !void {
@@ -1278,37 +876,7 @@ const Null = struct {
1278
876
  _ = .{ self, player, move, n };
1279
877
  }
1280
878
 
1281
- pub fn duration(
1282
- self: Null,
1283
- comptime field: Duration.Field,
1284
- player: Player,
1285
- target: Player,
1286
- turns: u4,
1287
- ) void {
1288
- _ = .{ self, field, player, target, turns };
1289
- }
1290
-
1291
- pub fn sleep(self: Null, player: Player, turns: u4) Error!void {
1292
- _ = .{ self, player, turns };
1293
- }
1294
-
1295
- pub fn confusion(self: Null, player: Player, turns: u4) Error!void {
1296
- _ = .{ self, player, turns };
1297
- }
1298
-
1299
- pub fn disable(self: Null, player: Player, turns: u4) Error!void {
1300
- _ = .{ self, player, turns };
1301
- }
1302
-
1303
- pub fn attacking(self: Null, player: Player, turns: u4) Error!void {
1304
- _ = .{ self, player, turns };
1305
- }
1306
-
1307
- pub fn binding(self: Null, player: Player, turns: u4) Error!void {
1308
- _ = .{ self, player, turns };
1309
- }
1310
-
1311
- pub fn encore(self: Null, player: Player, turns: u4) Error!void {
879
+ pub fn duration(self: Null, player: Player, turns: u4) void {
1312
880
  _ = .{ self, player, turns };
1313
881
  }
1314
882
  };