#pokemon #battle #state #search #engine #competitive #space

bin+lib poke-engine

A Pokemon battle engine that can be used to search through the state space of a Pokemon battle

16 releases

0.1.0 Aug 31, 2024
0.0.21 Dec 14, 2024
0.0.17 Nov 28, 2024
0.0.13 Oct 25, 2024
0.0.11 Sep 30, 2024

#31 in Games

Download history 212/week @ 2024-08-31 107/week @ 2024-09-07 435/week @ 2024-09-14 39/week @ 2024-09-21 324/week @ 2024-09-28 25/week @ 2024-10-05 166/week @ 2024-10-12 50/week @ 2024-10-19 68/week @ 2024-10-26 5/week @ 2024-11-02 288/week @ 2024-11-09 25/week @ 2024-11-16 129/week @ 2024-11-23 143/week @ 2024-11-30 241/week @ 2024-12-07

543 downloads per month

Custom license

2MB
51K SLoC

Poke Engine

An engine for searching through Pokémon battles (singles only).

This is not a perfect engine

This battle engine is meant to capture important aspects of Pokémon for the purposes of competitive single battles. It is nowhere near as complete or robust as the PokemonShowdown battle engine.

Python Bindings

CHANGELOG

Running Directly

Building

Make sure you have Rust / Cargo installed.

Features are used to conditionally compile code for different generations of Pokemon. The simplest way to build the project is with the Makefile.

e.g. To build for generation 4:

make gen4

Run with

./target/release/poke-engine

Generations 4 through 8 are available

Usage

There are several ways to interact with the engine through subcommands:

  1. Generate Instructions
poke-engine generate-instructions --state <state-string> -o <s1_move> -t <s2_move>

Generate and display the different Instructions that could be applied to the state if side 1 and side 2 used the given moves.

e.g.

poke-engine generate-instructions --state <state-string> -o shadowball -t breloom
Index: 0
StateInstruction: 
	Percentage: 80.00
	Instructions:
		Switch SideTwo: P0 -> P2
		Damage SideTwo: 184

Index: 1
StateInstruction: 
	Percentage: 20.00
	Instructions:
		Switch SideTwo: P0 -> P2
		Damage SideTwo: 184
		Boost SideTwo SpecialDefense: -1
  1. Expectiminimax
poke-engine expectiminimax --state <state-string> --depth <depth> [--ab-prune]

Search through the state using expectiminimax to the given depth. Displays the results along with the best move found.

e.g.

poke-engine expectiminimax --state <state-string> -d 3
side one options: psychic,grassknot,shadowball,hiddenpowerfire70,switch skarmory,switch tyranitar,switch mamoswine,switch jellicent,switch excadrill
side two options: closecombat,stoneedge,stealthrock,taunt,xscissor,quickattack,switch lucario,switch breloom,switch keldeo,switch conkeldurr,switch toxicroak
matrix: 32.39,11.99,39.72,99.72,-9.94,69.44,55.46,75.91,75.91,75.91,101.19,32.39,-2.94,39.72,99.72,-28.60,69.44,53.51,79.84,108.92,78.63,-23.62,32.39,-20.35,34.37,94.37,-49.04,49.60,53.51,81.39,88.49,89.01,0.00,17.65,-43.57,11.15,71.15,-72.26,26.38,75.91,75.91,65.27,83.70,0.00,-76.18,-85.66,-72.00,-36.99,-34.19,-34.19,-50.07,-11.07,-25.16,-31.11,15.53,-119.69,-85.88,-101.20,-29.40,-100.00,-82.60,-90.04,-107.86,-77.15,-73.11,-25.90,-100.00,-95.17,-118.42,-75.85,-86.53,-86.53,-97.97,-102.52,-83.18,-74.85,-44.47,-45.01,-74.53,-117.55,-45.01,-56.64,-45.01,-84.08,-120.08,-45.01,-74.85,-44.47,-100.00,-47.20,-96.28,-32.62,-52.23,-42.56,-41.19,-120.08,-74.58,-74.85,-41.19
choice: psychic
evaluation: -9.944763
  1. Iterative Deepening
poke-engine iterative-deepening --state <state-string> --time-to-search-ms <time>

Similar to expectiminimax, search through the state but use iterative deepening. Searches for the given amount of time, then returns the best move found.

e.g.

poke-engine iterative-deepening --state <state-string> -t 100
side one options: psychic,switch jellicent,grassknot,shadowball,hiddenpowerfire70,switch skarmory,switch mamoswine,switch excadrill,switch tyranitar
side two options: closecombat,stoneedge,stealthrock,taunt,xscissor,quickattack,switch lucario,switch breloom,switch keldeo,switch conkeldurr,switch toxicroak
matrix: 32.39,11.99,39.72,99.72,-9.94,69.44,55.46,75.91,75.91,75.91,101.19,-45.01,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,32.39,-2.94,39.72,99.72,-28.60,NaN,NaN,NaN,NaN,NaN,NaN,32.39,-20.35,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,17.65,-43.57,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,-76.18,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,-100.00,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,-100.00,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,-119.69,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN
choice: psychic
evaluation: -9.944763
  1. Monte Carlo Tree Search
poke-engine monte-carlo-tree-search --state <state-string> --time-to-search-ms <time>

Search through the state using Monte Carlo Tree Search for the given amount of time.

e.g.

poke-engine monte-carlo-tree-search --state <state-string> -t 100
Total Iterations: 25000
side one: switch mamoswine,115.31,300|switch tyranitar,41.00,123|hiddenpowerfire70,58.14,165|switch jellicent,1067.52,2402|switch excadrill,3754.58,8173|shadowball,115.37,300|grassknot,298.20,715|psychic,4038.05,8780|switch skarmory,1826.44,4042
side two: stoneedge,915.55,1723|switch lucario,70.53,159|closecombat,827.19,1562|switch breloom,181.84,373|switch keldeo,141.66,297|stealthrock,413.54,805|quickattack,84.78,187|taunt,123.90,263|xscissor,10745.95,19240|switch conkeldurr,153.71,320|switch toxicroak,26.94,71
  1. Calculate Damage
poke-engine calculate-damage --state <state-string> -o <s1_move> -t <s2_move>

Calculate the damage rolls for the given moves.

e.g.

poke-engine calculate-damage --state <state-string> -o shadowball -t closecombat
Damage Rolls: 122,123,125,126,128,129,131,132,133,135,136,138,139,141,142,144
Damage Rolls: 155,157,159,161,162,164,166,168,170,172,173,175,177,179,181,183
  1. Interactive Mode: Run the engine and input commands directly

e.g.

poke-engine --state <state-string>

Available commands:

Command Shorthand Function
state state-string s Reset the state to state-string
matchup m Display some information about the current state
generate-instructions side-1-move side-2-move g Generate all of the instructions that would be applied to the state if side 1 and side 2 used the given moves
instructions i Display the last instructions generated by generate-instructions
apply instruction-index a Apply the last instructions instructions to the state, modifying it
pop p Pops the last instructions from the state, undoing their changes
pop-all pa Pops all applied instructions from the state
evaluate ev Calculate the current state's evaluation
calculate-damage side-1-move side-2-move d Calculate the damage rolls for the given moves
expectiminimax depth [ab-prune=false] e Perform expectiminimax (see above), and display the results
iterative-deepening time-ms id Perform iterative-deepening (see above), and display the results
monte-carlo-tree-search time-ms mcts Perform monte-carlo-tree-search (see above), and display the results
serialize ser Display the current state's serialized string
exit/quit q Quit interactive mode

State Representation

When running directly, the engine parses the state of the game from a string.

Properly representing the state of a Pokémon battle gets really complicated. See the doctest for State::deserialize in state.rs for the source of truth on how to parse a state string.

Dependencies

~1.4–2MB
~37K SLoC