Skip to content

koisland/SuperAutoTest

Repository files navigation

SAPTest

CI codecov

Database and testing framework for Super Auto Pets.

Game information is queried from the Super Auto Pets wiki page and stored in a SQLite database.


Usage

Add it to a project with cargo.

cargo add saptest

Teams

Build a Team and simulate battles between them.

Then visualize the results in .dot format!

use saptest::{
    Pet, PetName, Food, FoodName,
    Team, TeamCombat, Position, create_battle_digraph
};
// Create a team.
let mut team = Team::new(
    &vec![Some(Pet::try_from(PetName::Ant).unwrap()); 5],
    5
).unwrap();
let mut enemy_team = team.clone();

// Set a seed for a team.
team.set_seed(Some(25));

// Give food to pets.
team.set_item(&Position::First, Food::try_from(FoodName::Garlic).ok()).unwrap();
enemy_team.set_item(&Position::First, Food::try_from(FoodName::Garlic).ok()).unwrap();

// And fight!
team.fight(&mut enemy_team).unwrap();

// Create a graph of the fight.
println!("{}", create_battle_digraph(&team, false));
digraph {
    rankdir=LR
    node [shape=box, style="rounded, filled", fontname="Arial"]
    edge [fontname="Arial"]
    0 [ label = "Ant_0 - The Fragile Truckers_copy" ]
    1 [ label = "Ant_0 - The Fragile Truckers", fillcolor = "yellow" ]
    2 [ label = "Ant_3 - The Fragile Truckers", fillcolor = "yellow" ]
    3 [ label = "Ant_4 - The Fragile Truckers_copy" ]
    0 -> 1 [ label = "(Attack, Damage (0, 2), Phase: 1)" ]
    1 -> 0 [ label = "(Attack, Damage (0, 2), Phase: 1)" ]
    1 -> 2 [ label = "(Faint, Add (1, 1), Phase: 1)" ]
    0 -> 3 [ label = "(Faint, Add (1, 1), Phase: 1)" ]
}

Graphs can be as simple as the example above... or extremely complex.

Using Graphviz Online.

Shops

Add shop functionality to a Team and roll, freeze, buy/sell pets and foods.

use saptest::{
    Shop, ShopItem, TeamShopping, Team,
    Position, Entity, EntityName, Food, FoodName,
    db::pack::Pack
};

// All teams are constructed with a shop at tier 1.
let mut team = Team::default();

// All shop functionality is supported.
team.set_shop_seed(Some(1212))
    .set_shop_packs(&[Pack::Turtle])
    .open_shop().unwrap()
    .buy(
        &Position::First, // From first.
        &Entity::Pet, // Pet
        &Position::First // To first position, merging if possible.
    ).unwrap()
    .move_pets(
        &Position::First, // First pet.
        &Position::Relative(-2), // To pet 2 slots behind. Otherwise, ignore.
        true // And merge them if possible.
    ).unwrap()
    .sell(&Position::First).unwrap()
    .freeze_shop(&Position::Last, &Entity::Pet).unwrap()
    .roll_shop().unwrap()
    .close_shop().unwrap();

// Shops can be built separately and can replace a team's shop.
let mut tier_5_shop = Shop::new(3, Some(42)).unwrap();
let weakness = ShopItem::new(
    Food::try_from(FoodName::Weak).unwrap()
);
tier_5_shop.add_item(weakness).unwrap();
team.replace_shop(tier_5_shop).unwrap();

Pets

Build custom Pets and Effects.

use saptest::{
    Pet, PetName, PetCombat,
    Food, FoodName,
    Entity, Position, Effect, Statistics,
    effects::{
        trigger::TRIGGER_START_BATTLE,
        actions::GainType,
        state::Target,
        actions::Action
    }
};
// Create known pets.
let mut pet = Pet::try_from(PetName::Ant).unwrap();

// Or custom pets and effects.
let custom_effect = Effect::new(
    TRIGGER_START_BATTLE, // Effect trigger
    Target::Friend, // Target
    Position::Adjacent, // Positions
    Action::Gain(GainType::DefaultItem(FoodName::Melon)), // Action
    Some(1), // Number of uses.
    false, // Is temporary.
);
let mut custom_pet = Pet::custom(
    "MelonBear",
    Statistics::new(50, 50).unwrap(),
    &[custom_effect],
);

// Fight two pets individually as well.
// Note: Effects don't activate here.
pet.attack(&mut custom_pet);

Logging

Enable logging with a crate like simple_logger.

Config

To configure the global SapDB's startup, create a .saptest.toml file in the root of your project.

  • Specify page versions for pets, foods, and tokens to query.
  • Toggle recurring updates on startup.
  • Set database filename.
[database]
# https://superautopets.wiki.gg/index.php?title=Pets&oldid=4634
pets_version = 4634
filename = "./sap.db"
update_on_startup = false

Graph building can also be disabled in [general] with build_graph.

[general]
build_graph = false

Benchmarks

Benchmarks for saptest are located in benches/battle_benchmarks.rs and run using the criterion crate.

  • Compared against sapai, a Super Auto Pets testing framework written in Python.
  • Both tests were run on an AMD Ryzen 5 5600 6-Core Processor @ 3.50 GHz.
# saptest
git clone [email protected]:koisland/SuperAutoTest.git --depth 1
cargo add cargo-tarpaulin
cargo bench && open target/criterion/sapai_example/report/index.html
# sapai
cd benches/
git clone https://github.com/manny405/sapai.git && cd sapai
python setup.py install
# Then run `battle_benchmarks_sapai.ipynb`.

saptest (No Graphs)

  • TODO

saptest (Graphs)

  • TODO

sapai

  • 4.29 ms ± 51.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

TODO:

  • Add trait for randomly generating teams.
  • Add method to iterate through record fields/fieldnames and build macro to construct SQL statements.
    • Manually adding fields is tedious and error-prone.
  • Build lexer to parse raw effect text into Effect struct.
  • Add feature flags for each pack.
  • Improve interface.
    • Function arguments with impls like AsRef and Into/TryInto. ex. Shop.add_item
    • Type state pattern with Shop<Open/Close>

Sources