Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // *** main.rs
- use std::fmt;
- use std::cmp::Ordering;
- fn main() {
- // ONLY CHANGE THINGS BELOW THIS LINE
- let champion_number = 11; // e.g. 5 for Kenny, 10 for Felice
- let pet_number = 10; // e.g. 4 for Lake Lizard, 7 for Elephant Fighter
- let pet_level = 2;
- let arena_league = League::Gold; // e.g. Bronze, Silver, Gold, Diamond
- let arena_division = 1;
- let arena_battle = 1;
- // ONLY CHANGE THINGS ABOVE THIS LINE
- let champion = Champion::build_champion(champion_number);
- println!("\n*** Champion stats:");
- champion.print_stats();
- let base_pet = Pet::build_pet(champion.multiplier, pet_number, pet_level);
- println!("\n*** Base pet stats:");
- base_pet.print_stats();
- let arena = Arena::new(arena_league, arena_division, arena_battle);
- println!("\n*** Arena:");
- arena.print_stats();
- let enemy = arena.get_enemy();
- println!("\n*** Enemy stats:");
- enemy.print_stats();
- println!("\n*** Optimising pets:");
- let bps = arena.get_bps();
- println!("{} BPs available to spend", bps);
- let upgraded_pets = PetUpgrader::get_possible_upgraded_pets(&base_pet, bps);
- println!(
- "Found {} possible upgraded pets to check",
- upgraded_pets.len()
- );
- println!("\n*** Optimising battles...");
- optimise_battles(&upgraded_pets, &enemy);
- }
- fn optimise_battles(pets: &[Pet], enemy: &Enemy) {
- // Try with different combinations of potions in order: ATK & DEF, DEF only, ATK only, neither
- let potion_configs = vec![(true, true), (false, true), (true, false), (false, false)];
- // Try with the first potion config (majority of cases)
- let battle = Battle::new(potion_configs[0].0, potion_configs[0].1);
- let result = battle.get_best_result(pets, enemy);
- if result.0 > 0.25 {
- // We are done
- display_result(potion_configs[0].0, potion_configs[0].1, result);
- return;
- }
- // Now we need to loop through the other potion configs
- let mut prev_result = result;
- for x in 1..4 {
- // Try this potion configuration
- let battle = Battle::new(potion_configs[x].0, potion_configs[x].1);
- let result = battle.get_best_result(pets, enemy);
- if result.0 > 0.25 {
- // We are done - show the previous result
- display_result(
- potion_configs[x - 1].0,
- potion_configs[x - 1].1,
- prev_result,
- );
- return;
- }
- // This is the best yet
- prev_result = result;
- }
- // Display the last result
- display_result(potion_configs[3].0, potion_configs[3].1, prev_result);
- }
- fn display_result(use_atk_potion: bool, use_def_potion: bool, result: (f32, &Pet)) {
- println!("Use ATK potion : {}", use_atk_potion);
- println!("Use DEF potion : {}", use_def_potion);
- println!("HP potions reqd : {:.1}", result.0);
- println!("Optimal pet : {}", result.1.name);
- }
- // *** lib.rs
- fn print_midas_number(number: f32) -> String {
- if number <= 0.0 {
- number.to_string()
- } else {
- let multiplier = number.log(1000.0).floor() as i32;
- let fraction = number / 1000.0_f32.powi(multiplier);
- let suffix = match multiplier {
- 0 => "",
- 1 => " K",
- 2 => " M",
- 3 => " B",
- 4 => " T",
- 5 => " Qa",
- 6 => " Qi",
- 7 => " Sx",
- 8 => " Sp",
- 9 => " Oc",
- 10 => " No",
- _ => panic!("Number too big {}", number),
- };
- format!("{:6.2}{}", fraction, suffix)
- }
- }
- // *** champion.rs
- pub struct Champion {
- pub name: String,
- pub multiplier: f32,
- }
- impl Champion {
- pub fn build_champion(champion_number: i32) -> Champion {
- Champion {
- name: Champion::get_name_for_number(champion_number),
- multiplier: Champion::get_multiplier_for_number(champion_number),
- }
- }
- pub fn print_stats(&self) {
- println!("{}", self.name);
- println!(
- "Multiplier : {} (+{}%)",
- self.multiplier,
- (self.multiplier - 1.0) * 100.0
- );
- }
- fn get_name_for_number(champion_number: i32) -> String {
- match champion_number {
- 1 => "Gilligan",
- 2 => "Audrey",
- 3 => "Scarlet",
- 4 => "Irwin",
- 5 => "Kenny",
- 6 => "Adeline",
- 7 => "Valeria",
- 8 => "Aurelius",
- 9 => "Felix",
- 10 => "Felice",
- 11 => "Tempestus",
- 12 => "Sylvar",
- 13 => "Benedict",
- 14 => "Lin",
- 15 => "Volv",
- _ => panic!("Unknown champion_number: {}", champion_number),
- }.to_string()
- }
- fn get_multiplier_for_number(champion_number: i32) -> f32 {
- match champion_number {
- 1 | 2 => 1.0,
- 3 => 1.5,
- 4 => 3.1,
- 5 => 4.6,
- 6 => 6.3,
- 7 => 8.7,
- 8 => 12.2,
- 9 => 18.0,
- 10 => 27.0,
- 11 => 40.8,
- 12 => 59.2,
- 13 => 90.4,
- 14 => 541.0,
- 15 => 3201.0,
- _ => panic!("Unknown champion_number: {}", champion_number),
- }
- }
- }
- // *** pet.rs
- pub struct Pet {
- pub name: String,
- pub health: f32,
- pub attack: f32,
- pub defence: f32,
- pub lifesteal: f32,
- pub block: f32,
- pub reflect: f32,
- }
- impl Pet {
- pub fn build_pet(champion_multiplier: f32, pet_number: i32, pet_level: i32) -> Pet {
- let pet_multiplier = 6_f32.powi(pet_number - 1) * (1.0 + 0.2 * (pet_level as f32 - 1.0));
- let total_multiplier = champion_multiplier * pet_multiplier;
- Pet {
- name: format!(
- "{} (level {})",
- Pet::get_name_for_number(pet_number),
- pet_level
- ),
- health: 720_f32 * total_multiplier,
- attack: 62_f32 * total_multiplier,
- defence: 24_f32 * total_multiplier,
- lifesteal: if pet_number > 1 {
- 51_f32 * total_multiplier
- } else {
- 0.0
- },
- block: if pet_number > 3 {
- 42_f32 * total_multiplier
- } else {
- 0.0
- },
- reflect: if pet_number > 6 {
- 54_f32 * total_multiplier
- } else {
- 0.0
- },
- }
- }
- pub fn print_stats(&self) {
- println!("{}", self.name);
- println!("Health : {}", print_midas_number(self.health));
- println!("Attack : {}", print_midas_number(self.attack));
- println!("Defence : {}", print_midas_number(self.defence));
- println!("Lifesteal : {}", print_midas_number(self.lifesteal));
- println!("Block : {}", print_midas_number(self.block));
- println!("Reflect : {}", print_midas_number(self.reflect));
- }
- fn get_name_for_number(pet_number: i32) -> String {
- match pet_number {
- 1 => "Midaeum Gardens Parrot",
- 2 => "Wild Mountain Boar",
- 3 => "Bonebreaker Python",
- 4 => "Lake Lizard",
- 5 => "Royal Eagle",
- 6 => "Gastonia Defender",
- 7 => "Elephant Fighter",
- 8 => "Fullmoon Werewolf",
- 9 => "Bloodthirsty Tiger",
- 10 => "Rhino of the Valley",
- 11 => "Flameguard Goblin",
- 12 => "Poisonous Hydra",
- 13 => "Snowmountain Yeti",
- 14 => "Astral Pegasus",
- 15 => "Swarm Soldier",
- 16 => "Lava Hound",
- 17 => "Forest Keeper",
- 18 => "Armored Nightmare",
- 19 => "Crystal Golem",
- 20 => "Dragon of the Void",
- _ => panic!("Unknown pet_number: {}", pet_number),
- }.to_string()
- }
- }
- // *** arena.rs
- pub enum League {
- Bronze,
- Silver,
- Gold,
- Diamond,
- }
- pub struct Arena {
- league: League,
- division: i32,
- battle: i32,
- }
- impl Arena {
- pub fn new(league: League, division: i32, battle: i32) -> Arena {
- if division < 1 || division > 5 {
- panic!("Division {} not allowed", division);
- }
- if battle < 1 || battle > Arena::get_total_battles(&league, division) {
- panic!("Battle {} not allowed", battle);
- }
- Arena {
- league: league,
- division: division,
- battle: battle,
- }
- }
- pub fn print_stats(&self) {
- let league_name = match self.league {
- League::Bronze => "Bronze",
- League::Silver => "Silver",
- League::Gold => "Gold",
- League::Diamond => "Diamond",
- };
- let division_name = match self.division {
- 1 => "I",
- 2 => "II",
- 3 => "III",
- 4 => "IV",
- 5 => "V",
- _ => unreachable!(),
- };
- println!(
- "{} {} {} / {}",
- league_name,
- division_name,
- self.battle,
- Arena::get_total_battles(&self.league, self.division)
- );
- }
- pub fn get_bps(&self) -> i32 {
- let mut bps = 0;
- let cuumulative_division_num =
- Arena::get_cumulative_division_num(&self.league, self.division);
- // Add BPs from complete divisions
- for div in 1..cuumulative_division_num {
- bps += 2 * div * (div + 3);
- }
- // Add BPs from complete battles in this division
- bps += (self.battle - 1) * cuumulative_division_num;
- bps
- }
- pub fn get_enemy(&self) -> Enemy {
- let all_enemy_healths =
- vec![vec![640.0, 988.0, 1270.0, 1600.0, 4500.0],
- vec![6000.0, 8500.0, 10500.0, 13000.0, 15000.0, 30000.0],
- vec![60000.0, 80000.0, 110000.0, 130000.0, 150000.0, 165000.0, 300000.0],
- vec![6e5, 1e6, 1.2e6, 1.3e6, 1.4e6, 1.6e6, 1.9e6, 4.2e6],
- vec![7.2e6, 9.2e6, 1.3e7, 1.4e7, 1.5e7, 1.6e7, 1.7e7, 1.9e7, 4.3e7],
- vec![1.2e8, 1.3e8, 1.5e8, 1.6e8, 1.8e8, 2.1e8, 2.3e8, 2.5e8, 3e8, 6.3e8],
- vec![1e9, 1.1e9, 1.2e9, 1.5e9, 1.7e9, 1.8e9, 2e9, 2.3e9, 2.8e9, 3e9, 6.2e9],
- vec![1e10, 1.1e10, 1.2e10, 1.5e10, 1.7e10, 1.8e10, 2e10, 2.3e10, 2.5e10, 2.7e10, 2.8e10, 6.8e10],
- vec![1e11, 1.1e11, 1.2e11, 1.3e11, 1.5e11, 1.7e11, 1.8e11, 2e11, 2.2e11, 2.3e11, 2.7e11, 3e11, 5e11],
- vec![6e11, 6.5e11, 7e11, 8.3e11, 9e11, 1e12, 1.1e12, 1.2e12, 1.4e12, 1.5e12, 1.6e12, 1.7e12, 1.9e12, 4e12],
- vec![5e12, 5.5e12, 6e12, 6.5e12, 7e12, 7.5e12, 8.5e12, 9e12, 1e13, 1.1e13, 1.3e13, 1.4e13, 1.5e13, 1.7e13, 3.7e13],
- vec![4e13, 4.5e13, 5e13, 5.5e13, 7e13, 7.5e13, 8e13, 8.5e13, 9e13, 9.5e14, 1e14, 1.05e14, 1.1e14, 1.12e14, 1.15e14, 2e14],
- vec![2.1e14, 2.2e14, 2.3e14, 2.4e14, 2.6e14, 2.8e14, 3e14, 3.5e14, 3.8e14, 4.4e14, 4.6e14, 4.8e14, 5.2e14, 5.4e14, 6.05e14, 6.9e14, 1.3e15],
- vec![1.7e15, 2.2e15, 2.3e15, 2.7e15, 3.6e15, 4e15, 4.5e15, 4.8e15, 4.9e15, 5e15, 5.1e15, 5.2e15, 5.3e15, 5.4e15, 5.5e15, 5.6e15, 6.1e15, 1.3e16],
- vec![2e16, 2.2e16, 2.3e16, 2.4e16, 2.5e16, 2.7e16, 2.8e16, 2.9e16, 3.1e16, 3.4e16, 3.6e16, 4.0e16, 4.3e16, 4.6e16, 4.8e16, 5.0e16, 5.5e16, 5.7e16, 1.4e17],
- vec![2e17, 2.2e17, 2.3e17, 2.4e17, 2.5e17, 2.6e17, 2.7e17, 2.8e17, 2.9e17, 3e17, 3.4e17, 3.6e17, 3.9e17, 4.5e17, 4.7e17, 5.4e17, 5.8e17, 6.4e17, 6.7e17, 1.2e18],
- vec![1.8e18, 1.9e18, 2e18, 2.2e18, 2.3e18, 2.4e18, 2.5e18, 2.6e18, 2.7e18, 2.8e18, 2.9e18, 3e18, 3.3e18, 3.4e18, 3.9e18, 4e18, 4.4e18, 4.8e18, 5.5e18, 6.6e18, 1.7e19],
- vec![2e19, 2.2e19, 2.4e19, 2.6e19, 2.8e19, 3e19, 3.3e19, 3.5e19, 3.9e19, 4.4e19, 4.6e19, 4.7e19, 5e19, 5.5e19, 6e19, 6.5e19, 7.5e19, 8e19, 8.5e19, 9e19, 9.5e19, 2e20],
- vec![2.1e20, 2.2e20, 2.3e20, 2.4e20, 2.5e20, 2.6e20, 2.7e20, 2.8e20, 2.9e20, 3e20, 3.1e20, 3.2e20, 3.3e20, 3.4e20, 3.5e20, 3.6e20, 3.7e20, 3.8e20, 3.9e20, 4e20, 4.1e20, 4.2e20, 6.1e20],
- vec![6.5e20, 6.8e20, 7.2e20, 7.4e20, 7.6e20, 7.8e20, 8e20, 8.2e20, 8.4e20, 8.6e20, 8.8e20, 9e20, 9.2e20, 9.4e20, 9.8e20, 1e21, 1.05e21, 1.1e21, 1.2e21, 1.3e21, 1.35e21, 1.4e21, 1.5e21, 2.4e21]];
- let cuumulative_division_num =
- Arena::get_cumulative_division_num(&self.league, self.division);
- let enemy_health =
- all_enemy_healths[(cuumulative_division_num - 1) as usize][(self.battle - 1) as usize];
- Enemy::build_enemy(self.battle, enemy_health)
- }
- fn get_cumulative_division_num(league: &League, division: i32) -> i32 {
- let league_num = match *league {
- League::Bronze => 0,
- League::Silver => 1,
- League::Gold => 2,
- League::Diamond => 3,
- };
- 5 * league_num + division
- }
- fn get_total_battles(league: &League, division: i32) -> i32 {
- Arena::get_cumulative_division_num(league, division) + 4
- }
- }
- // *** enemy.rs
- pub struct Enemy {
- pub name: String,
- pub health: f32,
- pub damage: f32,
- }
- impl Enemy {
- pub fn build_enemy(enemy_number: i32, health: f32) -> Enemy {
- Enemy {
- name: Enemy::get_name_for_number(enemy_number),
- health: health,
- damage: health / 8.0,
- }
- }
- pub fn print_stats(&self) {
- println!("{}", self.name);
- println!("Health : {}", print_midas_number(self.health));
- }
- fn get_name_for_number(enemy_number: i32) -> String {
- match enemy_number {
- 1 => "Cave Bug",
- 2 => "Sharpbeak",
- 3 => "Great Tarantula",
- 4 => "Tunnel Minion",
- 5 => "Goblin Gladiator",
- 6 => "Desert Scorpion",
- 7 => "Eyeball Terror",
- 8 => "Seashore Goblin",
- 9 => "Robotic Gatekeeper",
- 10 => "Swarm Beast",
- 11 => "Ancient Cyclops",
- 12 => "Valhalla Devourer",
- 13 => "Druid Hermit",
- 14 => "Alien Insect",
- 15 => "Fearless Zombie",
- 16 => "Mountain Troll King",
- 17 => "Undead Warrior",
- 18 => "Orc Overlord",
- 19 => "Lava Annihilator",
- 20 => "The Unbreakable",
- 21 => "Evil Shaman",
- 22 => "Soul Drainer",
- 23 => "Underworld Soulkeeper",
- 24 => "Shadow King",
- _ => panic!("Unknown enemy_number: {}", enemy_number),
- }.to_string()
- }
- }
- // *** pet_upgrader.rs
- pub struct PetUpgrader {}
- impl PetUpgrader {
- pub fn get_possible_upgraded_pets(pet: &Pet, battle_points: i32) -> Vec<Pet> {
- let upgrades = PetUpgradeGenerator::get_possible_upgrades(pet, battle_points);
- upgrades
- .iter()
- .map(|u| PetUpgrader::upgrade_pet(pet, u))
- .collect()
- }
- fn upgrade_pet(base_pet: &Pet, upgrade: &PetUpgrade) -> Pet {
- Pet {
- name: format!("{} - upgraded with {}", base_pet.name, upgrade),
- health: base_pet.health * (1.0 + 0.1 * upgrade.upgrades[0] as f32),
- attack: base_pet.attack * (1.0 + 0.1 * upgrade.upgrades[1] as f32),
- defence: base_pet.defence * (1.0 + 0.1 * upgrade.upgrades[2] as f32),
- lifesteal: base_pet.lifesteal * (1.0 + 0.1 * upgrade.upgrades[3] as f32),
- block: base_pet.block * (1.0 + 0.1 * upgrade.upgrades[4] as f32),
- reflect: base_pet.reflect * (1.0 + 0.1 * upgrade.upgrades[5] as f32),
- }
- }
- }
- #[derive(Debug, Clone)]
- struct PetUpgrade {
- upgrades: [i32; 6],
- }
- impl fmt::Display for PetUpgrade {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(
- f,
- "(H:{}, A:{}, D:{}, L:{}, B:{}, R:{})",
- self.upgrades[0],
- self.upgrades[1],
- self.upgrades[2],
- self.upgrades[3],
- self.upgrades[4],
- self.upgrades[5]
- )
- }
- }
- struct PetUpgradeGenerator {}
- impl PetUpgradeGenerator {
- fn get_possible_upgrades(pet: &Pet, battle_points: i32) -> Vec<PetUpgrade> {
- let mut max_depth = 5;
- if pet.reflect == 0.0 {
- max_depth = 4;
- }
- if pet.block == 0.0 {
- max_depth = 3;
- }
- if pet.lifesteal == 0.0 {
- max_depth = 2;
- }
- let (prespend_level, prespend_cost) = PetUpgradeGenerator::get_prespend(battle_points);
- let total_prespend_cost = 2 * prespend_cost;
- if total_prespend_cost > 0 {
- println!("Prespending {} BPs", total_prespend_cost);
- }
- let pet_upgrade = PetUpgrade {
- upgrades: [prespend_level, prespend_level, 0, 0, 0, 0],
- };
- PetUpgradeGenerator::generate_upgrades(
- &pet_upgrade,
- battle_points - total_prespend_cost,
- 0,
- max_depth,
- )
- }
- fn get_prespend(battle_points: i32) -> (i32, i32) {
- // No prespend for low BPs
- if battle_points < 300 {
- return (0, 0);
- }
- // Spend upto a quarter or a third of the BPs
- let max_prespend = battle_points / if battle_points < 1000 { 4 } else { 3 };
- let mut level = 0;
- let mut cost = 0;
- loop {
- let upgrade_cost = PetUpgradeGenerator::get_upgrade_cost(level);
- if cost + upgrade_cost > max_prespend {
- return (level, cost);
- }
- level += 1;
- cost += upgrade_cost;
- }
- }
- fn generate_upgrades(
- pet_upgrade: &PetUpgrade,
- battle_points: i32,
- depth: usize,
- max_depth: usize,
- ) -> Vec<PetUpgrade> {
- if depth == max_depth {
- // Just fill it up
- let mut pet_upgrade = pet_upgrade.clone();
- let mut battle_points = battle_points;
- loop {
- let cost = PetUpgradeGenerator::get_upgrade_cost(pet_upgrade.upgrades[depth]);
- if cost > battle_points {
- break;
- }
- pet_upgrade.upgrades[depth] += 1;
- battle_points -= cost;
- }
- // Need to check that we wouldn't have covered this case before
- for i in 0..max_depth {
- let cost = PetUpgradeGenerator::get_upgrade_cost(pet_upgrade.upgrades[i]);
- if cost <= battle_points {
- return vec![];
- }
- }
- return vec![pet_upgrade];
- }
- let mut pet_upgrades = vec![];
- let mut pet_upgrade = pet_upgrade.clone();
- let mut battle_points = battle_points;
- loop {
- for pu in PetUpgradeGenerator::generate_upgrades(
- &pet_upgrade,
- battle_points,
- depth + 1,
- max_depth,
- ) {
- pet_upgrades.push(pu);
- }
- let cost = PetUpgradeGenerator::get_upgrade_cost(pet_upgrade.upgrades[depth]);
- if cost > battle_points {
- break;
- }
- pet_upgrade.upgrades[depth] += 1;
- battle_points -= cost;
- }
- pet_upgrades
- }
- fn get_upgrade_cost(current_level: i32) -> i32 {
- if current_level < 10 {
- current_level + 1
- } else {
- current_level + 1 + PetUpgradeGenerator::get_upgrade_cost(current_level - 10)
- }
- }
- }
- // *** battle.rs
- pub struct Battle {
- pub use_attack_potion: bool,
- pub use_defence_potion: bool,
- }
- impl Battle {
- pub fn new(use_attack_potion: bool, use_defence_potion: bool) -> Battle {
- Battle {
- use_attack_potion: use_attack_potion,
- use_defence_potion: use_defence_potion,
- }
- }
- pub fn get_best_result<'a>(&self, pets: &'a [Pet], enemy: &Enemy) -> (f32, &'a Pet) {
- let results_by_pet = pets.iter().map(|p| (self.do_battle(p, enemy), p)).collect::<Vec<_>>();
- let best_result = results_by_pet.iter().min_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(Ordering::Equal)).unwrap();
- (if best_result.0 < 0.0 {0.0} else {best_result.0}, best_result.1)
- }
- fn do_battle(&self, pet: &Pet, enemy: &Enemy) -> f32 {
- let pet_hp = pet.health;
- let enemy_hp = enemy.health;
- let potion_hp = 0.25 * pet.health;
- let attack_adjust = if self.use_attack_potion { 1.5 } else { 1.0 };
- let defence_adjust = if self.use_defence_potion { 0.5 } else { 1.0 };
- // Apply ATTACK
- let mut pet_attack_per_round = attack_adjust * pet.attack;
- // Apply LIFESTEAL
- let mut enemy_attack_per_round = -0.25 * pet.lifesteal;
- // Apply DEFENCE
- enemy_attack_per_round += defence_adjust * (enemy.damage * 1.05 - pet.defence);
- // Apply BLOCK
- enemy_attack_per_round -= 0.3 * pet.block;
- // Apply REFLECT
- pet_attack_per_round += 0.3 * pet.reflect;
- // Compute end of battle stats
- let battle_rounds = (enemy_hp / pet_attack_per_round).ceil();
- let pet_hp_after_battle = pet_hp - battle_rounds * enemy_attack_per_round;
- -pet_hp_after_battle / potion_hp
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement