Skip to content

Project Onix: Representing Battles

August 1, 2016

Last time I gave a high-level overview of how this new usage stats system will be structured. One key difference between Onix and the current usage stats system is that Onix will be processing the whole battle log, not just the parts that are going to immediately lead to reports. Onix will represent battles in a way that the entire battle can be re-created, turn-by-turn, hit-by-hit. The hope is that this will lead to a lot of flexibility in generating novel reports and analyses and give researchers the opportunity to play with well-structured, sanitized, anonymized, and complete data.

This is a non-trivial challenge—it means that Onix will have to contain, if not a full battle engine, then at least one that’s de facto capable of constructing Pokemon Showdown replays. Of course, the alternative would be to store the PS battle logs as they are and work with its existing protocol. And that’s tempting. But at the end of the day, the aim of PS logs is to re-create a battle visually, while Onix’s goal is to facilitate deep Pokemon analyses, which is a markedly different use-case.

So the goal of Onix is to be able to re-create the exact state of a battle at any given time, and the core of that is how we represent a battle’s “state.” Think of everything that goes on in a Pokemon battle: it’s far more than just the HP of the active Pokemon, it’s the weather, it’s the entry hazards, it’s each Pokemon’s boosts and the status of all of the benched Pokemon. Below is a diagram of a logical structural representation of a battle state.Battle State

 

This particular structure represents a two-player singles match where each player is allowed three Pokemon, but it’s easy to see how one might add more Pokemon, more active slots, or even more players. In this structure Pokemon are represented positionally, so if a Pokemon were to switch out, we’d move all its information to the new slot. Note also that there’s a separation between non-volatile statuses (current HP, item, conditions like paralysis…), which are “permanent” changes, and volatile statuses (boosts, ability changes, conditions like taunt), which are lost on switch-out.

As we read through a battle log, this battle state will change. The simplest example is when a turn ends, the “Turn #” will be updated, but pretty much everything that happens in a battle, from switches to moves to ability activation to weather ending, will update the battle state in some way. In the language of Pokemon Showdown, these are all “actions”, but going through the list of major and minor actions, it’s clear that not all actions change a battle state (e.g. “-hint”).

Onix’s battle representations will be limited strictly to changes in battle state, and instead of calling these “actions,” we’ll call them “effects.”

Consider the following battle:

Player A’s team consists of a Qwilfish and an Audino.

Player B’s team consists of a Sandslash and an Emboar.

Start: Player A sends out Qwilfish, Player B sends out Emboar. Emboar’s attack is lowered thanks to Intimidate.

Turn 1: Emboar switches into Sandslash as Qwilfish lays down a layer of Spikes.

Turn 2: Sandslash KOs Qwilfish with an Earthquake. Player A sends out Audino to replace it.

Turn 3: Sandslash switches out into Emboar (Emboar takes Spikes damage) while Audino uses Wish .

Turn 4: Emboar KOs Audino with Close Combat. Player 2 wins the match!

Now let’s structure this log in terms of effects:

Initial state:
 - Turn #: 0
 - Side 0, Slot 0 (active): Qwilfish
 - Side 0, Slot 1: Audino
 - Side 1, Slot 0 (active): Emboar
 - Side 1, Slot 1: Sandslash

Effects:
 - Emboar Atk stage drops to -1
 - Turn # advances to 1
 - Emboar moves to Side 1, Slot 1 (loses volatile conditions)
 - Sandslash moves to Side 1, Slot 0
 - Spikes added to Field Conditions for Side 1
 - Turn # advances to 2
 - Qwilfish's HP drops to 0
 - Qwilfish gains condition: Faint
 - Qwilfish moves to Side 0, Slot 1
 - Audino moves to Side 0, Slot 0
 - Turn # advances to 3
 - Sandslash moves to Side 1, Slot 1
 - Emboar moves to Side 1, Slot 0
 - Emboar's HP drops by 1/8 of Max HP
 - Turn # advances to 4
 - Audino's HP drops to 0
 - Audino gains condition: Faint

End of Match

There’s some ambiguity here (should we be tracking PP? should “Pending Wish” be a field effect?), but you get the general idea—by advancing through this list of effects you can completely recreate the state of the battle at any given point in the match. But iterating through the above log doesn’t feel complete. Sandslash appears on the field, and Qwilfish mysteriously faints. One can infer what has happened (Sandslash KOed Qwilfish with a powerful move), but not saying it explicitly leaves out information important not just to our understanding of the progression of a battle, but potentially for performing analyses. Say I want to know the total damage done by each move over the course of a battle. The above has no record of actual move usage, so that would be impossible!

The solution is to give our effects “causes.” Explicitly, the model that Onix uses is to group effects into “events,” which are pairings of cause with effect. Rather than further describe what I mean, let me just show you with the above example:

Initial state:
 - Turn #: 0
 - Side 0, Slot 0 (active): Qwilfish
 - Side 0, Slot 1: Audino
 - Side 1, Slot 0 (active): Emboar
 - Side 1, Slot 1: Sandslash

Events:
 - Qwilfish's ability, Intimidate, activates
     - Emboar Atk stage drops to -1
 - Turn ends
     - Turn # advances to 1
 - Player 1 switches out
     - Emboar moves to Side 1, Slot 1 (loses volatile conditions)
     - Sandslash moves to Side 1, Slot 0
 - Qwilfish uses Spikes
     - Spikes added to Field Conditions for Side 1
 - Turn ends
     - Turn # advances to 2
 - Sandslash uses Earthquake
     - Qwilfish's HP drops to 0
     - Qwilfish gains condition: Faint
 - Player 0 sends out replacement
     - Qwilfish moves to Side 0, Slot 1
     - Audino moves to Side 0, Slot 0
 - Turn ends
     - Turn # advances to 3
 - Player 1 switches out
     - Sandslash moves to Side 1, Slot 1
     - Emboar moves to Side 1, Slot 0
 - Entry Hazards, Spikes, activate
     - Emboar's HP drops to 322
 - Audino uses Wish
 - Turn ends
     - Turn # advances to 4
 - Emboar uses Close Combat
     - Audino's HP drops to 0
     - Audino gains condition: Faint

End of Match

The basic idea is that every event has a “cause” (even if it’s just “turn ends”) and 0, 1 or many “effects.” Note that there’s some ambiguity here that I haven’t quite worked out: is the cause for Emboar’s spike damage that Player 2 switched it in? Or that there were Spikes on the field? Here, there’s no real harm “giving it” to the entry hazards, but what we had a scenario where a Pokemon used Whirlwind to drag another one onto the field, and that Pokemon died from hazards damage? Who would “get the kill,” the hazard-layer or the Whirlwind-user? I haven’t fully worked all this out yet, and it might be I change my model to allow an event to have multiple causes, but we’ll see. In the meantime, the important takeaway is that cause + effect(s) = event, and now we have a much clearer picture of what happened in a match.

In the end, Onix “events” are not quite so different from PS “actions” (though Showdown’s decisions regarding cause and effect may differ from mine), but there’s another key difference to how Onix’s battle representation that’s a bit more significant.

Referring to the diagrammed structure of a battle’s state that I laid out earlier, you might have noticed a grouping labelled “static data.” That’s metadata about the battle that won’t change as we iterate through the battle. In a lot of ways, it makes sense to not even include that information in the battle state, since it has little relevance (besides labelling) to the actual evolution of the battle. But in addition to player ratings and format information, there’s some other static data that’s included in the battle state’s structure: Pokemon movesets.

Battle State - Onix

By “movesets” I mean anything about a Pokemon that’s set in the teambuilder: so, species, moves, item, ability, stats spread, etc. While it’s true that a lot of this information can change during a battle—items can be knocked off, moves can be disabled, even species can change (Ditto)—movesets as I’ve defined them represent the sum of all decisions made before the start of the match. Success at Pokémon battling can be considered to be the marriage of teambuilding skill with battling skill, and by separating out movesets, I’ve isolated the teambuilding aspects of the match. So in that context, consider the above diagram, where movesets, non-volatile statuses and volatile statuses have been “refactored” apart. This gives us some interesting flexibility: statuses are now no longer tied to movesets, giving them a more “universal” flavor (so, for example, we’ll consider % HP rather than HP value) and battle events no longer reference specific Pokemon. Also note that whereas before, Pokémon were represented positionally, moving from slot to slot, in this model a Pokemon’s “slot” is fixed, and what changes is a reference to which slot is active. We lose some information doing this (namely the ordering of the “benched” Pokemon), but this information isn’t needed for constructing “replays” (that is, while it might matter for Circle Throw or Illusion, we can represent these changes in other ways). Let’s rewrite that battle log one more time:

Static state:
 - Side 0, Slot 0: Audino
 - Side 0, Slot 1: Qwilfish
 - Side 1, Slot 1: Emboar
 - Side 1, Slot 1: Sandslash
Initial state:
 - Turn #: 0
 - Side 0 Active: Slot 1
 - Side 1 Active: Slot 1

Events:
 - Side 0 Active's ability, activates
     - Side 1 Active's Atk stage drops to -1
 - Turn ends
     - Turn # advances to 1
 - Player 2 switches out
     - Side 1 Active set to: Slot 1
     - Side 1 Active volatile status reset
 - Side 0 Active uses Spikes
     - Spikes added to Field Conditions for Side 1
 - Turn ends
     - Turn # advances to 2
 - Side 1 Active uses Earthquake
     - Side 0 Active's %HP set to: 0
     - Side 0, Slot 1's non-volatile status set to: Faint
 - Player 0 sends out replacement
     - Side 0 Active set to: Slot 0
 - Turn ends
     - Turn # advances to 3
 - Player 1 switches out
     - Side 1 Active set to: Slot 0
 - Entry Hazards, Spikes, activate
     - Side 1, Slot 1's %HP set to: 7/8
 - Side 0 Active uses Wish
 - Turn ends
     - Turn # advances to 4
 - Side 1 Active uses Close Combat
     - Side 0, Slot 0's %HP set to: 0
     - Side 0, Slot 0's non-volatile status set to: Faint

End of Match

Now I’ll grant you: this isn’t as human-readable, but humans aren’t the ones processing these logs, are they? A computer has no problem looking up the reference each time, and addressing by reference removes ambiguity for metagames without species clause in addition to allowing greater flexibility for data analysis: say today you want to group events by species. Maybe tomorrow you want to group by full moveset. And maybe the next you want to group by the Pokemon’s type. In all of these cases, rather than having to evaluate each and every event to determine whether it matches one’s criteria, now all one has to do is evaluate the static moveset, and then look up events by slot number.

I know this topic was pretty dense, so if you made it all the way through, I salute you. For those that just skipped here, here’s a tl;dr:

  1. A Battle State encapsulates all the battle-relevant information about the conditions of a battle.
  2. Changes to Battle States are called Effects. The progression of a battle can be charted as a list of effects.
  3. Effects can be grouped by Cause into Events.
  4. Onix’s Battle States are structured so as to isolate teambuilding intent and so that Effects are as universal as possible.

Next time I’ll be talking about databases! Yay!

Advertisements

From → Uncategorized

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: