@pkmn/engine 0.1.0-dev.3393edb3 → 0.1.0-dev.36b5d56b

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/build/pkg/addon/browser.d.ts +1 -1
  2. package/build/pkg/addon/browser.js +2 -1
  3. package/build/pkg/addon/browser.js.map +1 -1
  4. package/build/pkg/addon/node.js +2 -1
  5. package/build/pkg/addon/node.js.map +1 -1
  6. package/build/pkg/addon/wasm.d.ts +2 -0
  7. package/build/pkg/addon/wasm.js +21 -0
  8. package/build/pkg/addon/wasm.js.map +1 -0
  9. package/build/pkg/addon.d.ts +20 -0
  10. package/build/pkg/addon.js.map +1 -1
  11. package/build/tools/debug.js +1 -1
  12. package/build/tools/debug.js.map +1 -1
  13. package/build/tools/display/index.js +17 -8
  14. package/build/tools/display/index.js.map +1 -1
  15. package/build.zig +89 -68
  16. package/package.json +19 -16
  17. package/src/lib/common/debug.zig +9 -4
  18. package/src/lib/common/options.zig +2 -0
  19. package/src/lib/common/protocol.zig +4 -8
  20. package/src/lib/common/rational.zig +7 -5
  21. package/src/lib/common/rng.zig +1 -3
  22. package/src/lib/gen1/calc.zig +82 -88
  23. package/src/lib/gen1/chance.zig +34 -18
  24. package/src/lib/gen1/data/moves.zig +2 -4
  25. package/src/lib/gen1/data/species.zig +1 -3
  26. package/src/lib/gen1/data/types.zig +1 -2
  27. package/src/lib/gen1/data.zig +7 -11
  28. package/src/lib/gen1/helpers.zig +4 -11
  29. package/src/lib/gen1/mechanics.zig +68 -56
  30. package/src/lib/gen2/calc.zig +9 -17
  31. package/src/lib/gen2/data/items.zig +1 -3
  32. package/src/lib/gen2/data/moves.zig +2 -4
  33. package/src/lib/gen2/data/species.zig +1 -3
  34. package/src/lib/gen2/data/types.zig +1 -2
  35. package/src/lib/gen2/data.zig +11 -15
  36. package/src/lib/gen2/generated.zig +18 -23
  37. package/src/lib/gen2/helpers.zig +5 -12
  38. package/src/lib/gen2/mechanics.zig +22 -30
  39. package/src/lib/node.zig +2 -4
  40. package/src/lib/pkmn.zig +4 -0
  41. package/src/lib/wasm.zig +1 -2
  42. package/src/tools/display/ui.css +8 -5
@@ -1,44 +1,35 @@
1
- const std = @import("std");
2
-
3
- const pkmn = @import("../pkmn.zig");
1
+ const DEBUG = @import("../common/debug.zig").print;
4
2
 
3
+ const chance = @import("chance.zig");
5
4
  const common = @import("../common/data.zig");
6
- const DEBUG = @import("../common/debug.zig").print;
5
+ const data = @import("data.zig");
6
+ const helpers = @import("helpers.zig");
7
7
  const optional = @import("../common/optional.zig");
8
+ const pkmn = @import("../pkmn.zig");
8
9
  const protocol = @import("../common/protocol.zig");
9
10
  const rational = @import("../common/rational.zig");
11
+ const std = @import("std");
10
12
  const util = @import("../common/util.zig");
11
13
 
12
- const chance = @import("chance.zig");
13
- const data = @import("data.zig");
14
- const helpers = @import("helpers.zig");
15
-
16
- const assert = std.debug.assert;
17
-
18
- const expect = std.testing.expect;
19
- const expectEqual = std.testing.expectEqual;
20
- const expectEqualSlices = std.testing.expectEqualSlices;
21
-
22
- const enabled = pkmn.options.calc;
23
-
24
- const Player = common.Player;
25
- const Result = common.Result;
26
- const Choice = common.Choice;
27
-
28
- const Optional = optional.Optional;
29
-
30
- const Rational = rational.Rational;
31
-
32
- const PointerType = util.PointerType;
33
- const isPointerTo = util.isPointerTo;
34
-
35
- const Actions = chance.Actions;
36
14
  const Action = chance.Action;
15
+ const Actions = chance.Actions;
16
+ const assert = std.debug.assert;
37
17
  const Chance = chance.Chance;
18
+ const Choice = common.Choice;
38
19
  const Confusion = chance.Confusion;
39
20
  const Duration = chance.Duration;
40
21
  const Durations = chance.Durations;
22
+ const enabled = pkmn.options.calc;
23
+ const expect = std.testing.expect;
24
+ const expectEqual = std.testing.expectEqual;
25
+ const expectEqualSlices = std.testing.expectEqualSlices;
26
+ const isPointerTo = util.isPointerTo;
41
27
  const Observation = chance.Observation;
28
+ const Optional = optional.Optional;
29
+ const Player = common.Player;
30
+ const PointerType = util.PointerType;
31
+ const Rational = rational.Rational;
32
+ const Result = common.Result;
42
33
  const Sleeps = chance.Sleeps;
43
34
 
44
35
  const tty = true; // DEBUG
@@ -119,6 +110,14 @@ pub const Calc = struct {
119
110
  }) val else null;
120
111
  }
121
112
 
113
+ pub fn confusion(self: *Calc, player: Player) void {
114
+ if (!enabled) return;
115
+
116
+ if (self.overrides.get(player).confusion == .started) {
117
+ self.overrides.get(player).confusion = .None;
118
+ }
119
+ }
120
+
122
121
  pub fn base(self: *Calc, player: Player, val: u16) void {
123
122
  if (!enabled) return;
124
123
 
@@ -152,6 +151,10 @@ const Null = struct {
152
151
  return null;
153
152
  }
154
153
 
154
+ pub fn confusion(self: Null, player: Player) void {
155
+ _ = .{ self, player };
156
+ }
157
+
155
158
  pub fn base(self: Null, player: Player, val: u16) void {
156
159
  _ = .{ self, player, val };
157
160
  }
@@ -179,7 +182,7 @@ pub const Options = struct {
179
182
  metronome: bool = false,
180
183
  };
181
184
 
182
- pub const MAX_FRONTIER = 49;
185
+ pub const MAX_FRONTIER = 81;
183
186
 
184
187
  pub fn transitions(
185
188
  battle: anytype,
@@ -198,11 +201,11 @@ pub fn transitions(
198
201
  var frontier = std.ArrayList(Actions).init(allocator);
199
202
  defer frontier.deinit();
200
203
 
201
- const durations = options.durations;
204
+ const d = options.durations;
202
205
 
203
206
  var opts = pkmn.battle.options(
204
207
  protocol.NULL,
205
- Chance(Rational(u128)){ .probability = .{}, .durations = durations },
208
+ Chance(Rational(u128)){ .probability = .{}, .durations = d },
206
209
  Calc{},
207
210
  );
208
211
 
@@ -242,20 +245,20 @@ pub fn transitions(
242
245
  };
243
246
 
244
247
  for (Rolls.speedTie(f.p1)) |tie| { a.p1.speed_tie = tie; a.p2.speed_tie = tie;
245
- for (Rolls.sleep(f.p1, durations.p1)) |p1_slp| { a.p1.sleep = p1_slp;
246
- for (Rolls.sleep(f.p2, durations.p2)) |p2_slp| { a.p2.sleep = p2_slp;
247
- for (Rolls.disable(f.p1, durations.p1, p1_slp)) |p1_dis| { a.p1.disable = p1_dis;
248
- for (Rolls.disable(f.p2, durations.p2, p2_slp)) |p2_dis| { a.p2.disable = p2_dis;
249
- for (Rolls.confusion(f.p1, durations.p1, p1_slp)) |p1_cfz| { a.p1.confusion = p1_cfz;
250
- for (Rolls.confusion(f.p2, durations.p2, p2_slp)) |p2_cfz| { a.p2.confusion = p2_cfz;
248
+ for (Rolls.sleep(f.p1, d.p1)) |p1_slp| { a.p1.sleep = p1_slp;
249
+ for (Rolls.sleep(f.p2, d.p2)) |p2_slp| { a.p2.sleep = p2_slp;
250
+ for (Rolls.disable(f.p1, d.p1, p1_slp)) |p1_dis| { a.p1.disable = p1_dis;
251
+ for (Rolls.disable(f.p2, d.p2, p2_slp)) |p2_dis| { a.p2.disable = p2_dis;
252
+ for (Rolls.attacking(f.p1, d.p1, p1_slp)) |p1_atk| { a.p1.attacking = p1_atk;
253
+ for (Rolls.attacking(f.p2, d.p2, p2_slp)) |p2_atk| { a.p2.attacking = p2_atk;
254
+ for (Rolls.confusion(f.p1, d.p1, p1_atk, p1_slp)) |p1_cfz| { a.p1.confusion = p1_cfz;
255
+ for (Rolls.confusion(f.p2, d.p2, p2_atk, p2_slp)) |p2_cfz| { a.p2.confusion = p2_cfz;
251
256
  for (Rolls.confused(f.p1, p1_cfz)) |p1_cfzd| { a.p1.confused = p1_cfzd;
252
257
  for (Rolls.confused(f.p2, p2_cfz)) |p2_cfzd| { a.p2.confused = p2_cfzd;
253
258
  for (Rolls.paralyzed(f.p1, p1_cfzd)) |p1_par| { a.p1.paralyzed = p1_par;
254
259
  for (Rolls.paralyzed(f.p2, p2_cfzd)) |p2_par| { a.p2.paralyzed = p2_par;
255
- for (Rolls.attacking(f.p1, durations.p1, p1_par)) |p1_atk| { a.p1.attacking = p1_atk;
256
- for (Rolls.attacking(f.p2, durations.p2, p2_par)) |p2_atk| { a.p2.attacking = p2_atk;
257
- for (Rolls.binding(f.p1, durations.p1, p1_par)) |p1_bind| { a.p1.binding = p1_bind;
258
- for (Rolls.binding(f.p2, durations.p2, p2_par)) |p2_bind| { a.p2.binding = p2_bind;
260
+ for (Rolls.binding(f.p1, d.p1, p1_par)) |p1_bind| { a.p1.binding = p1_bind;
261
+ for (Rolls.binding(f.p2, d.p2, p2_par)) |p2_bind| { a.p2.binding = p2_bind;
259
262
  for (Rolls.hit(f.p1, p1_par)) |p1_hit| { a.p1.hit = p1_hit;
260
263
  for (Rolls.hit(f.p2, p2_par)) |p2_hit| { a.p2.hit = p2_hit;
261
264
  for (Rolls.psywave(f.p1, p1, p1_hit)) |p1_psywave| { a.p1.psywave = p1_psywave;
@@ -283,7 +286,7 @@ pub fn transitions(
283
286
 
284
287
  opts.calc.overrides = a;
285
288
  opts.calc.summaries = .{};
286
- opts.chance = .{ .probability = .{}, .durations = durations };
289
+ opts.chance = .{ .probability = .{}, .durations = d };
287
290
  const q = &opts.chance.probability;
288
291
 
289
292
  b = battle;
@@ -300,7 +303,7 @@ pub fn transitions(
300
303
  try Rolls.coalesce(.P2, @as(u8, @intCast(p2_dmg.min)), summaries, cap);
301
304
 
302
305
  if (opts.chance.actions.matches(f)) {
303
- if (!map(opts.chance.actions).eql(a)) {
306
+ if (!opts.chance.actions.relax().eql(a)) {
304
307
  if (!summary) {
305
308
  try debug(writer, opts.chance.actions, .{
306
309
  .p1_max = p1_max,
@@ -334,10 +337,13 @@ pub fn transitions(
334
337
  }
335
338
  }
336
339
  }
337
-
338
340
  if (p1_max != p1_min) try q.update(p1_max - p1_min + 1, 1);
339
341
  if (p2_max != p2_dmg.min) try q.update(p2_max - p2_dmg.min + 1, 1);
342
+
343
+ q.reduce();
340
344
  try p.add(q);
345
+ p.reduce();
346
+
341
347
  stats.saved += 1;
342
348
 
343
349
  if (p.q < p.p) {
@@ -345,7 +351,7 @@ pub fn transitions(
345
351
  return error.TestUnexpectedResult;
346
352
  }
347
353
  } else {
348
- if (!matches(opts.chance.actions, i, frontier.items)) {
354
+ if (!opts.chance.actions.matchesAny(frontier.items, i)) {
349
355
  try frontier.append(opts.chance.actions);
350
356
 
351
357
  try debug(writer, opts.chance.actions, .{
@@ -515,23 +521,6 @@ fn unfix(actual: anytype) data.Battle(data.PRNG) {
515
521
  };
516
522
  }
517
523
 
518
- fn map(actions: Actions) Actions {
519
- if (!pkmn.options.overwrite) return actions;
520
- var a = actions;
521
- if (a.p1.confusion == .overwritten) a.p1.confusion = .continuing;
522
- if (a.p2.confusion == .overwritten) a.p2.confusion = .continuing;
523
- return a;
524
- }
525
-
526
- fn matches(actions: Actions, i: usize, frontier: []Actions) bool {
527
- for (frontier, 0..) |f, j| {
528
- // TODO: is skipping this redundant check worth it?
529
- if (i == j) continue;
530
- if (f.matches(actions)) return true;
531
- }
532
- return false;
533
- }
534
-
535
524
  fn err(comptime fmt: []const u8, v: anytype, seed: ?u64) void {
536
525
  const w = std.io.getStdErr().writer();
537
526
  w.print(fmt, v) catch return;
@@ -655,52 +644,53 @@ pub const Rolls = struct {
655
644
  };
656
645
  }
657
646
 
647
+ /// FIXME
648
+ pub fn attacking(
649
+ action: Action,
650
+ duration: Duration,
651
+ parent: Optional(Observation),
652
+ ) []const Optional(Observation) {
653
+ return switch (action.attacking) {
654
+ .None => &OBS_NONE,
655
+ .started => &OBS_STARTED,
656
+ else => if (duration.attacking >= 3)
657
+ &OBS_ENDED
658
+ else if ((parent == .continuing and parent == .ended) or duration.attacking < 2)
659
+ &OBS_CONTINUING
660
+ else
661
+ &OBS,
662
+ };
663
+ }
664
+
658
665
  const CFZ_NONE = [_]Optional(Confusion){.None};
659
666
  const CFZ_STARTED = [_]Optional(Confusion){.started};
667
+ const CFZ_OVERWRITTEN = [_]Optional(Confusion){ .started, .overwritten };
660
668
  const CFZ_CONTINUING = [_]Optional(Confusion){.continuing};
661
669
  const CFZ_ENDED = [_]Optional(Confusion){.ended};
662
670
  const CFZ = [_]Optional(Confusion){ .continuing, .ended };
663
671
 
664
- /// Returns a slice with a range of values for confusion given the `action`, observed `durations`,
665
- /// and the state of the `parent` (observation of the player's Pokémon sleep status).
672
+ /// FIXME
666
673
  pub fn confusion(
667
674
  action: Action,
668
675
  duration: Duration,
676
+ sibling: Optional(Observation),
669
677
  parent: Optional(Observation),
670
678
  ) []const Optional(Confusion) {
671
679
  return switch (action.confusion) {
672
680
  .None => &CFZ_NONE,
673
- .started => &CFZ_STARTED,
681
+ .started => if (pkmn.options.overwrite and sibling == .ended and duration.confusion < 5)
682
+ &CFZ_OVERWRITTEN
683
+ else
684
+ &CFZ_STARTED,
674
685
  else => if (duration.confusion >= 5)
675
686
  &CFZ_ENDED
676
- else if ((parent != .None and parent != .started) or duration.confusion < 2)
687
+ else if ((parent == .continuing and parent == .ended) or duration.confusion < 2)
677
688
  &CFZ_CONTINUING
678
689
  else
679
690
  &CFZ,
680
691
  };
681
692
  }
682
693
 
683
- /// Returns a slice with a range of values for attacking given the `action`, observed
684
- /// `durations`, and the state of the `parent` (whether the player's Pokémon was fully
685
- /// paralyzed).
686
- pub fn attacking(
687
- action: Action,
688
- duration: Duration,
689
- parent: Optional(bool),
690
- ) []const Optional(Observation) {
691
- if (parent == .true) return &OBS_NONE;
692
- return switch (action.attacking) {
693
- .None => &OBS_NONE,
694
- .started => &OBS_STARTED,
695
- else => if (duration.attacking >= 3)
696
- &OBS_ENDED
697
- else if (duration.attacking < 2)
698
- &OBS_CONTINUING
699
- else
700
- &OBS,
701
- };
702
- }
703
-
704
694
  /// Returns a slice with a range of values for binding given the `action`, observed `durations`,
705
695
  /// and the state of the `parent` (whether the player's Pokémon was fully paralyzed).
706
696
  pub fn binding(
@@ -909,7 +899,11 @@ test "Rolls.criticalHit" {
909
899
  test "Rolls.confused" {
910
900
  const actions: Actions = .{ .p2 = .{ .confused = .true } };
911
901
  try expectEqualSlices(Optional(bool), &.{.None}, Rolls.confused(actions.p1, .None));
912
- try expectEqualSlices(Optional(bool), &.{ .false, .true }, Rolls.confused(actions.p2, .continuing));
902
+ try expectEqualSlices(
903
+ Optional(bool),
904
+ &.{ .false, .true },
905
+ Rolls.confused(actions.p2, .continuing),
906
+ );
913
907
  try expectEqualSlices(Optional(bool), &.{.None}, Rolls.confused(actions.p2, .ended));
914
908
  }
915
909
 
@@ -1,30 +1,27 @@
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 Array = @import("../common/array.zig").Array;
15
- const Player = @import("../common/data.zig").Player;
16
- const Optional = @import("../common/optional.zig").Optional;
17
-
18
- const data = @import("data.zig");
19
-
12
+ const Array = array.Array;
13
+ const assert = std.debug.assert;
20
14
  const enabled = options.chance;
21
- const showdown = options.showdown;
22
-
23
- const PointerType = util.PointerType;
15
+ const expect = std.testing.expect;
16
+ const expectEqual = std.testing.expectEqual;
24
17
  const isPointerTo = util.isPointerTo;
25
-
26
18
  const Move = data.Move;
27
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;
28
25
 
29
26
  const Int = if (@hasField(std.builtin.Type, "int")) .int else .Int;
30
27
  const Enum = if (@hasField(std.builtin.Type, "enum")) .@"enum" else .Enum;
@@ -75,6 +72,25 @@ pub const Actions = extern struct {
75
72
  return true;
76
73
  }
77
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
+
78
94
  pub fn fmt(self: Actions, writer: anytype, shape: bool) !void {
79
95
  try writer.writeAll("<P1 = ");
80
96
  try self.p1.fmt(writer, shape);
@@ -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;
@@ -1,20 +1,16 @@
1
- const std = @import("std");
2
1
  const builtin = @import("builtin");
3
-
4
- const pkmn = @import("../pkmn.zig");
5
-
2
+ const calc = @import("calc.zig");
3
+ const chance = @import("chance.zig");
6
4
  const data = @import("../common/data.zig");
5
+ const mechanics = @import("mechanics.zig");
6
+ const moves = @import("data/moves.zig");
7
+ const pkmn = @import("../pkmn.zig");
7
8
  const protocol = @import("../common/protocol.zig");
8
9
  const rng = @import("../common/rng.zig");
9
- const util = @import("../common/util.zig");
10
-
11
- const moves = @import("data/moves.zig");
12
10
  const species = @import("data/species.zig");
11
+ const std = @import("std");
13
12
  const types = @import("data/types.zig");
14
-
15
- const calc = @import("calc.zig");
16
- const chance = @import("chance.zig");
17
- const mechanics = @import("mechanics.zig");
13
+ const util = @import("../common/util.zig");
18
14
 
19
15
  const assert = std.debug.assert;
20
16
  const expectEqual = std.testing.expectEqual;
@@ -1,25 +1,19 @@
1
- const std = @import("std");
2
1
  const builtin = @import("builtin");
3
-
4
2
  const common = @import("../common/data.zig");
3
+ const data = @import("data.zig");
5
4
  const options = @import("../common/options.zig");
6
5
  const protocol = @import("../common/protocol.zig");
7
6
  const rng = @import("../common/rng.zig");
7
+ const std = @import("std");
8
8
  const util = @import("../common/util.zig");
9
9
 
10
- const data = @import("data.zig");
11
-
12
10
  const assert = std.debug.assert;
13
-
14
11
  const Choice = common.Choice;
15
-
16
- const showdown = options.showdown;
17
-
18
- const PSRNG = rng.PSRNG;
19
-
20
12
  const DVs = data.DVs;
21
13
  const Move = data.Move;
22
14
  const MoveSlot = data.MoveSlot;
15
+ const PSRNG = rng.PSRNG;
16
+ const showdown = options.showdown;
23
17
  const Species = data.Species;
24
18
  const Stats = data.Stats;
25
19
 
@@ -267,7 +261,6 @@ fn durations(m: Move) bool {
267
261
  // Any moves that have effects that result in duration tracking with -Dchance
268
262
  return switch (Move.get(m).effect) {
269
263
  .Haze,
270
- .Thrashing,
271
264
  .Metronome,
272
265
  => true,
273
266
  else => false,