Guest User

Untitled

a guest
Apr 26th, 2018
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 25.45 KB | None | 0 0
  1. // *** main.rs
  2. use std::fmt;
  3. use std::cmp::Ordering;
  4.  
  5. fn main() {
  6. // ONLY CHANGE THINGS BELOW THIS LINE
  7. let champion_number = 13; // e.g. 5 for Kenny, 10 for Felice
  8. let pet_number = 16; // e.g. 4 for Lake Lizard, 7 for Elephant Fighter
  9. let pet_level = 5;
  10. let arena_league = League::Diamond; // e.g. Bronze, Silver, Gold, Diamond
  11. let arena_division = 2;
  12. let arena_battle = 1;
  13. // ONLY CHANGE THINGS ABOVE THIS LINE
  14.  
  15. let champion = Champion::build_champion(champion_number);
  16. println!("\n*** Champion stats:");
  17. champion.print_stats();
  18.  
  19. let base_pet = Pet::build_pet(champion.multiplier, pet_number, pet_level);
  20. println!("\n*** Base pet stats:");
  21. base_pet.print_stats();
  22.  
  23. let arena = Arena::new(arena_league, arena_division, arena_battle);
  24. println!("\n*** Arena:");
  25. arena.print_stats();
  26.  
  27. let enemy = arena.get_enemy();
  28. println!("\n*** Enemy stats:");
  29. enemy.print_stats();
  30.  
  31. println!("\n*** Optimising pets:");
  32. let bps = arena.get_bps();
  33. println!("{} BPs available to spend", bps);
  34. let upgraded_pets = PetUpgrader::get_possible_upgraded_pets(&base_pet, bps);
  35. println!(
  36. "Found {} possible upgraded pets to check",
  37. upgraded_pets.len()
  38. );
  39.  
  40. println!("\n*** Optimising battles...");
  41. optimise_battles(&upgraded_pets, &enemy);
  42. }
  43.  
  44. fn optimise_battles(pets: &[Pet], enemy: &Enemy) {
  45. // Try with different combinations of potions in order: ATK & DEF, DEF only, ATK only, neither
  46. let potion_configs = vec![(true, true), (false, true), (true, false), (false, false)];
  47.  
  48. // Try with the first potion config (majority of cases)
  49. let battle = Battle::build(potion_configs[0].0, potion_configs[0].1);
  50. let result = battle.get_best_result(pets, enemy);
  51. if result.0 > 0.25 {
  52. // We are done
  53. display_result(potion_configs[0].0, potion_configs[0].1, result);
  54. return;
  55. }
  56.  
  57. // Now we need to loop through the other potion configs
  58. let mut prev_result = result;
  59. for x in 1..4 {
  60. // Try this potion configuration
  61. let battle = Battle::build(potion_configs[x].0, potion_configs[x].1);
  62. let result = battle.get_best_result(pets, enemy);
  63. if result.0 > 0.25 {
  64. // We are done - show the previous result
  65. display_result(
  66. potion_configs[x - 1].0,
  67. potion_configs[x - 1].1,
  68. prev_result,
  69. );
  70. return;
  71. }
  72.  
  73. // This is the best yet
  74. prev_result = result;
  75. }
  76.  
  77. // Display the last result
  78. display_result(potion_configs[3].0, potion_configs[3].1, prev_result);
  79. }
  80.  
  81. fn display_result(use_atk_potion: bool, use_def_potion: bool, result: (f32, &Pet)) {
  82. println!("Use ATK potion : {}", use_atk_potion);
  83. println!("Use DEF potion : {}", use_def_potion);
  84. println!("HP potions reqd : {:.1}", result.0);
  85. println!("Optimal pet : {}", result.1.name);
  86. }
  87.  
  88. // *** lib.rs
  89. fn print_midas_number(number: f32) -> String {
  90. if number <= 0.0 {
  91. number.to_string()
  92. } else {
  93. let multiplier = number.log(1000.0).floor() as i32;
  94. let fraction = number / 1000.0_f32.powi(multiplier);
  95.  
  96. let suffix = match multiplier {
  97. 0 => "",
  98. 1 => " K",
  99. 2 => " M",
  100. 3 => " B",
  101. 4 => " T",
  102. 5 => " Qa",
  103. 6 => " Qi",
  104. 7 => " Sx",
  105. 8 => " Sp",
  106. 9 => " Oc",
  107. 10 => " No",
  108. _ => panic!("Number too big {}", number),
  109. };
  110.  
  111. format!("{:6.2}{}", fraction, suffix)
  112. }
  113. }
  114.  
  115. // *** champion.rs
  116. pub struct Champion {
  117. pub name: String,
  118. pub multiplier: f32,
  119. }
  120.  
  121. impl Champion {
  122. pub fn build_champion(champion_number: i32) -> Champion {
  123. Champion {
  124. name: Champion::get_name_for_number(champion_number),
  125. multiplier: Champion::get_multiplier_for_number(champion_number),
  126. }
  127. }
  128.  
  129. pub fn print_stats(&self) {
  130. println!("{}", self.name);
  131. println!(
  132. "Multiplier : {} (+{}%)",
  133. self.multiplier,
  134. (self.multiplier - 1.0) * 100.0
  135. );
  136. }
  137.  
  138. fn get_name_for_number(champion_number: i32) -> String {
  139. match champion_number {
  140. 1 => "Gilligan",
  141. 2 => "Audrey",
  142. 3 => "Scarlet",
  143. 4 => "Irwin",
  144. 5 => "Kenny",
  145. 6 => "Adeline",
  146. 7 => "Valeria",
  147. 8 => "Aurelius",
  148. 9 => "Felix",
  149. 10 => "Felice",
  150. 11 => "Tempestus",
  151. 12 => "Sylvar",
  152. 13 => "Benedict",
  153. 14 => "Lin",
  154. 15 => "Volv",
  155. _ => panic!("Unknown champion_number: {}", champion_number),
  156. }.to_string()
  157. }
  158.  
  159. fn get_multiplier_for_number(champion_number: i32) -> f32 {
  160. match champion_number {
  161. 1 | 2 => 1.0,
  162. 3 => 1.5,
  163. 4 => 3.1,
  164. 5 => 4.6,
  165. 6 => 6.3,
  166. 7 => 8.7,
  167. 8 => 12.2,
  168. 9 => 18.0,
  169. 10 => 27.0,
  170. 11 => 40.8,
  171. 12 => 59.2,
  172. 13 => 90.4,
  173. 14 => 541.0,
  174. 15 => 3201.0,
  175. _ => panic!("Unknown champion_number: {}", champion_number),
  176. }
  177. }
  178. }
  179.  
  180. // *** pet.rs
  181. pub struct Pet {
  182. pub name: String,
  183. pub health: f32,
  184. pub attack: f32,
  185. pub defence: f32,
  186. pub lifesteal: f32,
  187. pub block: f32,
  188. pub reflect: f32,
  189. }
  190.  
  191. impl Pet {
  192. pub fn build_pet(champion_multiplier: f32, pet_number: i32, pet_level: i32) -> Pet {
  193. let pet_multiplier = 6_f32.powi(pet_number - 1) * (1.0 + 0.2 * (pet_level as f32 - 1.0));
  194. let total_multiplier = champion_multiplier * pet_multiplier;
  195.  
  196. Pet {
  197. name: format!(
  198. "{} (level {})",
  199. Pet::get_name_for_number(pet_number),
  200. pet_level
  201. ),
  202. health: 720_f32 * total_multiplier,
  203. attack: 62_f32 * total_multiplier,
  204. defence: 24_f32 * total_multiplier,
  205. lifesteal: if pet_number > 1 {
  206. 51_f32 * total_multiplier
  207. } else {
  208. 0.0
  209. },
  210. block: if pet_number > 3 {
  211. 42_f32 * total_multiplier
  212. } else {
  213. 0.0
  214. },
  215. reflect: if pet_number > 6 {
  216. 54_f32 * total_multiplier
  217. } else {
  218. 0.0
  219. },
  220. }
  221. }
  222.  
  223. pub fn print_stats(&self) {
  224. println!("{}", self.name);
  225. println!("Health : {}", print_midas_number(self.health));
  226. println!("Attack : {}", print_midas_number(self.attack));
  227. println!("Defence : {}", print_midas_number(self.defence));
  228. println!("Lifesteal : {}", print_midas_number(self.lifesteal));
  229. println!("Block : {}", print_midas_number(self.block));
  230. println!("Reflect : {}", print_midas_number(self.reflect));
  231. }
  232.  
  233. fn get_name_for_number(pet_number: i32) -> String {
  234. match pet_number {
  235. 1 => "Midaeum Gardens Parrot",
  236. 2 => "Wild Mountain Boar",
  237. 3 => "Bonebreaker Python",
  238. 4 => "Lake Lizard",
  239. 5 => "Royal Eagle",
  240. 6 => "Gastonia Defender",
  241. 7 => "Elephant Fighter",
  242. 8 => "Fullmoon Werewolf",
  243. 9 => "Bloodthirsty Tiger",
  244. 10 => "Rhino of the Valley",
  245. 11 => "Flameguard Goblin",
  246. 12 => "Poisonous Hydra",
  247. 13 => "Snowmountain Yeti",
  248. 14 => "Astral Pegasus",
  249. 15 => "Swarm Soldier",
  250. 16 => "Lava Hound",
  251. 17 => "Forest Keeper",
  252. 18 => "Armored Nightmare",
  253. 19 => "Crystal Golem",
  254. 20 => "Dragon of the Void",
  255. _ => panic!("Unknown pet_number: {}", pet_number),
  256. }.to_string()
  257. }
  258. }
  259.  
  260. // *** arena.rs
  261. pub enum League {
  262. Bronze,
  263. Silver,
  264. Gold,
  265. Diamond,
  266. }
  267.  
  268. pub struct Arena {
  269. league: League,
  270. division: i32,
  271. battle: i32,
  272. }
  273.  
  274. impl Arena {
  275. pub fn new(league: League, division: i32, battle: i32) -> Arena {
  276. if division < 1 || division > 5 {
  277. panic!("Division {} not allowed", division);
  278. }
  279.  
  280. if battle < 1 || battle > Arena::get_total_battles(&league, division) {
  281. panic!("Battle {} not allowed", battle);
  282. }
  283.  
  284. Arena {
  285. league: league,
  286. division: division,
  287. battle: battle,
  288. }
  289. }
  290.  
  291. pub fn print_stats(&self) {
  292. let league_name = match self.league {
  293. League::Bronze => "Bronze",
  294. League::Silver => "Silver",
  295. League::Gold => "Gold",
  296. League::Diamond => "Diamond",
  297. };
  298. let division_name = match self.division {
  299. 1 => "I",
  300. 2 => "II",
  301. 3 => "III",
  302. 4 => "IV",
  303. 5 => "V",
  304. _ => unreachable!(),
  305. };
  306.  
  307. println!(
  308. "{} {} {} / {}",
  309. league_name,
  310. division_name,
  311. self.battle,
  312. Arena::get_total_battles(&self.league, self.division)
  313. );
  314. }
  315.  
  316. pub fn get_bps(&self) -> i32 {
  317. let mut bps = 0;
  318.  
  319. let cuumulative_division_num =
  320. Arena::get_cumulative_division_num(&self.league, self.division);
  321.  
  322. // Add BPs from complete divisions
  323. for div in 1..cuumulative_division_num {
  324. bps += 2 * div * (div + 3);
  325. }
  326.  
  327. // Add BPs from complete battles in this division
  328. bps += (self.battle - 1) * cuumulative_division_num;
  329.  
  330. bps
  331. }
  332.  
  333. pub fn get_enemy(&self) -> Enemy {
  334. let all_enemy_healths = vec![
  335. vec![640.0, 988.0, 1270.0, 1600.0, 4500.0],
  336. vec![6000.0, 8500.0, 10500.0, 13000.0, 15000.0, 30000.0],
  337. vec![
  338. 60000.0,
  339. 80000.0,
  340. 110000.0,
  341. 130000.0,
  342. 150000.0,
  343. 165000.0,
  344. 300000.0,
  345. ],
  346. vec![6e5, 1e6, 1.2e6, 1.3e6, 1.4e6, 1.6e6, 1.9e6, 4.2e6],
  347. vec![
  348. 7.2e6,
  349. 9.2e6,
  350. 1.3e7,
  351. 1.4e7,
  352. 1.5e7,
  353. 1.6e7,
  354. 1.7e7,
  355. 1.9e7,
  356. 4.3e7,
  357. ],
  358. vec![
  359. 1.2e8,
  360. 1.3e8,
  361. 1.5e8,
  362. 1.6e8,
  363. 1.8e8,
  364. 2.1e8,
  365. 2.3e8,
  366. 2.5e8,
  367. 3e8,
  368. 6.3e8,
  369. ],
  370. vec![
  371. 1e9,
  372. 1.1e9,
  373. 1.2e9,
  374. 1.5e9,
  375. 1.7e9,
  376. 1.8e9,
  377. 2e9,
  378. 2.3e9,
  379. 2.8e9,
  380. 3e9,
  381. 6.2e9,
  382. ],
  383. vec![
  384. 1e10,
  385. 1.1e10,
  386. 1.2e10,
  387. 1.5e10,
  388. 1.7e10,
  389. 1.8e10,
  390. 2e10,
  391. 2.3e10,
  392. 2.5e10,
  393. 2.7e10,
  394. 2.8e10,
  395. 6.8e10,
  396. ],
  397. vec![
  398. 1e11,
  399. 1.1e11,
  400. 1.2e11,
  401. 1.3e11,
  402. 1.5e11,
  403. 1.7e11,
  404. 1.8e11,
  405. 2e11,
  406. 2.2e11,
  407. 2.3e11,
  408. 2.7e11,
  409. 3e11,
  410. 5e11,
  411. ],
  412. vec![
  413. 6e11,
  414. 6.5e11,
  415. 7e11,
  416. 8.3e11,
  417. 9e11,
  418. 1e12,
  419. 1.1e12,
  420. 1.2e12,
  421. 1.4e12,
  422. 1.5e12,
  423. 1.6e12,
  424. 1.7e12,
  425. 1.9e12,
  426. 4e12,
  427. ],
  428. vec![
  429. 5e12,
  430. 5.5e12,
  431. 6e12,
  432. 6.5e12,
  433. 7e12,
  434. 7.5e12,
  435. 8.5e12,
  436. 9e12,
  437. 1e13,
  438. 1.1e13,
  439. 1.3e13,
  440. 1.4e13,
  441. 1.5e13,
  442. 1.7e13,
  443. 3.7e13,
  444. ],
  445. vec![
  446. 4e13,
  447. 4.5e13,
  448. 5e13,
  449. 5.5e13,
  450. 7e13,
  451. 7.5e13,
  452. 8e13,
  453. 8.5e13,
  454. 9e13,
  455. 9.5e14,
  456. 1e14,
  457. 1.05e14,
  458. 1.1e14,
  459. 1.12e14,
  460. 1.15e14,
  461. 2e14,
  462. ],
  463. vec![
  464. 2.1e14,
  465. 2.2e14,
  466. 2.3e14,
  467. 2.4e14,
  468. 2.6e14,
  469. 2.8e14,
  470. 3e14,
  471. 3.5e14,
  472. 3.8e14,
  473. 4.4e14,
  474. 4.6e14,
  475. 4.8e14,
  476. 5.2e14,
  477. 5.4e14,
  478. 6.05e14,
  479. 6.9e14,
  480. 1.3e15,
  481. ],
  482. vec![
  483. 1.7e15,
  484. 2.2e15,
  485. 2.3e15,
  486. 2.7e15,
  487. 3.6e15,
  488. 4e15,
  489. 4.5e15,
  490. 4.8e15,
  491. 4.9e15,
  492. 5e15,
  493. 5.1e15,
  494. 5.2e15,
  495. 5.3e15,
  496. 5.4e15,
  497. 5.5e15,
  498. 5.6e15,
  499. 6.1e15,
  500. 1.3e16,
  501. ],
  502. vec![
  503. 2e16,
  504. 2.2e16,
  505. 2.3e16,
  506. 2.4e16,
  507. 2.5e16,
  508. 2.7e16,
  509. 2.8e16,
  510. 2.9e16,
  511. 3.1e16,
  512. 3.4e16,
  513. 3.6e16,
  514. 4.0e16,
  515. 4.3e16,
  516. 4.6e16,
  517. 4.8e16,
  518. 5.0e16,
  519. 5.5e16,
  520. 5.7e16,
  521. 1.4e17,
  522. ],
  523. vec![
  524. 2e17,
  525. 2.2e17,
  526. 2.3e17,
  527. 2.4e17,
  528. 2.5e17,
  529. 2.6e17,
  530. 2.7e17,
  531. 2.8e17,
  532. 2.9e17,
  533. 3e17,
  534. 3.4e17,
  535. 3.6e17,
  536. 3.9e17,
  537. 4.5e17,
  538. 4.7e17,
  539. 5.4e17,
  540. 5.8e17,
  541. 6.4e17,
  542. 6.7e17,
  543. 1.2e18,
  544. ],
  545. vec![
  546. 1.8e18,
  547. 1.9e18,
  548. 2e18,
  549. 2.2e18,
  550. 2.3e18,
  551. 2.4e18,
  552. 2.5e18,
  553. 2.6e18,
  554. 2.7e18,
  555. 2.8e18,
  556. 2.9e18,
  557. 3e18,
  558. 3.3e18,
  559. 3.4e18,
  560. 3.9e18,
  561. 4e18,
  562. 4.4e18,
  563. 4.8e18,
  564. 5.5e18,
  565. 6.6e18,
  566. 1.7e19,
  567. ],
  568. vec![
  569. 2e19,
  570. 2.2e19,
  571. 2.4e19,
  572. 2.6e19,
  573. 2.8e19,
  574. 3e19,
  575. 3.3e19,
  576. 3.5e19,
  577. 3.9e19,
  578. 4.4e19,
  579. 4.6e19,
  580. 4.7e19,
  581. 5e19,
  582. 5.5e19,
  583. 6e19,
  584. 6.5e19,
  585. 7.5e19,
  586. 8e19,
  587. 8.5e19,
  588. 9e19,
  589. 9.5e19,
  590. 2e20,
  591. ],
  592. vec![
  593. 2.1e20,
  594. 2.2e20,
  595. 2.3e20,
  596. 2.4e20,
  597. 2.5e20,
  598. 2.6e20,
  599. 2.7e20,
  600. 2.8e20,
  601. 2.9e20,
  602. 3e20,
  603. 3.1e20,
  604. 3.2e20,
  605. 3.3e20,
  606. 3.4e20,
  607. 3.5e20,
  608. 3.6e20,
  609. 3.7e20,
  610. 3.8e20,
  611. 3.9e20,
  612. 4e20,
  613. 4.1e20,
  614. 4.2e20,
  615. 6.1e20,
  616. ],
  617. vec![
  618. 6.5e20,
  619. 6.8e20,
  620. 7.2e20,
  621. 7.4e20,
  622. 7.6e20,
  623. 7.8e20,
  624. 8e20,
  625. 8.2e20,
  626. 8.4e20,
  627. 8.6e20,
  628. 8.8e20,
  629. 9e20,
  630. 9.2e20,
  631. 9.4e20,
  632. 9.8e20,
  633. 1e21,
  634. 1.05e21,
  635. 1.1e21,
  636. 1.2e21,
  637. 1.3e21,
  638. 1.35e21,
  639. 1.4e21,
  640. 1.5e21,
  641. 2.4e21,
  642. ],
  643. ];
  644.  
  645. let cuumulative_division_num =
  646. Arena::get_cumulative_division_num(&self.league, self.division);
  647. let enemy_health =
  648. all_enemy_healths[(cuumulative_division_num - 1) as usize][(self.battle - 1) as usize];
  649.  
  650. Enemy::build_enemy(self.battle, enemy_health)
  651. }
  652.  
  653. fn get_cumulative_division_num(league: &League, division: i32) -> i32 {
  654. let league_num = match *league {
  655. League::Bronze => 0,
  656. League::Silver => 1,
  657. League::Gold => 2,
  658. League::Diamond => 3,
  659. };
  660. 5 * league_num + division
  661. }
  662.  
  663. fn get_total_battles(league: &League, division: i32) -> i32 {
  664. Arena::get_cumulative_division_num(league, division) + 4
  665. }
  666. }
  667.  
  668. // *** enemy.rs
  669. pub struct Enemy {
  670. pub name: String,
  671. pub health: f32,
  672. pub damage: f32,
  673. }
  674.  
  675. impl Enemy {
  676. pub fn build_enemy(enemy_number: i32, health: f32) -> Enemy {
  677. Enemy {
  678. name: Enemy::get_name_for_number(enemy_number),
  679. health: health,
  680. damage: health / 8.0,
  681. }
  682. }
  683.  
  684. pub fn print_stats(&self) {
  685. println!("{}", self.name);
  686. println!("Health : {}", print_midas_number(self.health));
  687. }
  688.  
  689. fn get_name_for_number(enemy_number: i32) -> String {
  690. match enemy_number {
  691. 1 => "Cave Bug",
  692. 2 => "Sharpbeak",
  693. 3 => "Great Tarantula",
  694. 4 => "Tunnel Minion",
  695. 5 => "Goblin Gladiator",
  696. 6 => "Desert Scorpion",
  697. 7 => "Eyeball Terror",
  698. 8 => "Seashore Goblin",
  699. 9 => "Robotic Gatekeeper",
  700. 10 => "Swarm Beast",
  701. 11 => "Ancient Cyclops",
  702. 12 => "Valhalla Devourer",
  703. 13 => "Druid Hermit",
  704. 14 => "Alien Insect",
  705. 15 => "Fearless Zombie",
  706. 16 => "Mountain Troll King",
  707. 17 => "Undead Warrior",
  708. 18 => "Orc Overlord",
  709. 19 => "Lava Annihilator",
  710. 20 => "The Unbreakable",
  711. 21 => "Evil Shaman",
  712. 22 => "Soul Drainer",
  713. 23 => "Underworld Soulkeeper",
  714. 24 => "Shadow King",
  715. _ => panic!("Unknown enemy_number: {}", enemy_number),
  716. }.to_string()
  717. }
  718. }
  719.  
  720. // *** pet_upgrader.rs
  721. pub struct PetUpgrader {}
  722.  
  723. impl PetUpgrader {
  724. pub fn get_possible_upgraded_pets(pet: &Pet, battle_points: i32) -> Vec<Pet> {
  725. let upgrades = PetUpgradeGenerator::get_possible_upgrades(pet, battle_points);
  726. upgrades
  727. .iter()
  728. .map(|u| PetUpgrader::upgrade_pet(pet, u))
  729. .collect()
  730. }
  731.  
  732. fn upgrade_pet(base_pet: &Pet, upgrade: &PetUpgrade) -> Pet {
  733. Pet {
  734. name: format!("{} - upgraded with {}", base_pet.name, upgrade),
  735. health: base_pet.health * (1.0 + 0.1 * upgrade.upgrades[0] as f32),
  736. attack: base_pet.attack * (1.0 + 0.1 * upgrade.upgrades[1] as f32),
  737. defence: base_pet.defence * (1.0 + 0.1 * upgrade.upgrades[2] as f32),
  738. lifesteal: base_pet.lifesteal * (1.0 + 0.1 * upgrade.upgrades[3] as f32),
  739. block: base_pet.block * (1.0 + 0.1 * upgrade.upgrades[4] as f32),
  740. reflect: base_pet.reflect * (1.0 + 0.1 * upgrade.upgrades[5] as f32),
  741. }
  742. }
  743. }
  744. #[derive(Debug, Clone)]
  745. struct PetUpgrade {
  746. upgrades: [i32; 6],
  747. }
  748.  
  749. impl fmt::Display for PetUpgrade {
  750. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  751. write!(
  752. f,
  753. "(H:{}, A:{}, D:{}, L:{}, B:{}, R:{})",
  754. self.upgrades[0],
  755. self.upgrades[1],
  756. self.upgrades[2],
  757. self.upgrades[3],
  758. self.upgrades[4],
  759. self.upgrades[5]
  760. )
  761. }
  762. }
  763.  
  764. struct PetUpgradeGenerator {}
  765.  
  766. impl PetUpgradeGenerator {
  767. fn get_possible_upgrades(pet: &Pet, battle_points: i32) -> Vec<PetUpgrade> {
  768. let mut max_depth = 5;
  769. if pet.reflect == 0.0 {
  770. max_depth = 4;
  771. }
  772. if pet.block == 0.0 {
  773. max_depth = 3;
  774. }
  775. if pet.lifesteal == 0.0 {
  776. max_depth = 2;
  777. }
  778. let (prespend_level, prespend_cost) = PetUpgradeGenerator::get_prespend(battle_points);
  779. let total_prespend_cost = 2 * prespend_cost;
  780. if total_prespend_cost > 0 {
  781. println!("Prespending {} BPs", total_prespend_cost);
  782. }
  783. let pet_upgrade = PetUpgrade {
  784. upgrades: [prespend_level, prespend_level, 0, 0, 0, 0],
  785. };
  786. PetUpgradeGenerator::generate_upgrades(
  787. &pet_upgrade,
  788. battle_points - total_prespend_cost,
  789. 0,
  790. max_depth,
  791. )
  792. }
  793.  
  794. fn get_prespend(battle_points: i32) -> (i32, i32) {
  795. // No prespend for low BPs
  796. if battle_points < 300 {
  797. return (0, 0);
  798. }
  799.  
  800. // Spend upto a quarter or a third of the BPs
  801. let max_prespend = battle_points / if battle_points < 1000 { 4 } else { 3 };
  802. let mut level = 0;
  803. let mut cost = 0;
  804. loop {
  805. let upgrade_cost = PetUpgradeGenerator::get_upgrade_cost(level);
  806. if cost + upgrade_cost > max_prespend {
  807. return (level, cost);
  808. }
  809. level += 1;
  810. cost += upgrade_cost;
  811. }
  812. }
  813.  
  814. fn generate_upgrades(
  815. pet_upgrade: &PetUpgrade,
  816. battle_points: i32,
  817. depth: usize,
  818. max_depth: usize,
  819. ) -> Vec<PetUpgrade> {
  820. if depth == max_depth {
  821. // Just fill it up
  822. let mut pet_upgrade = pet_upgrade.clone();
  823. let mut battle_points = battle_points;
  824. loop {
  825. let cost = PetUpgradeGenerator::get_upgrade_cost(pet_upgrade.upgrades[depth]);
  826. if cost > battle_points {
  827. break;
  828. }
  829. pet_upgrade.upgrades[depth] += 1;
  830. battle_points -= cost;
  831. }
  832.  
  833. // Need to check that we wouldn't have covered this case before
  834. for i in 0..max_depth {
  835. let cost = PetUpgradeGenerator::get_upgrade_cost(pet_upgrade.upgrades[i]);
  836. if cost <= battle_points {
  837. return vec![];
  838. }
  839. }
  840.  
  841. return vec![pet_upgrade];
  842. }
  843.  
  844. let mut pet_upgrades = vec![];
  845. let mut pet_upgrade = pet_upgrade.clone();
  846. let mut battle_points = battle_points;
  847. loop {
  848. for pu in PetUpgradeGenerator::generate_upgrades(
  849. &pet_upgrade,
  850. battle_points,
  851. depth + 1,
  852. max_depth,
  853. ) {
  854. pet_upgrades.push(pu);
  855. }
  856.  
  857. let cost = PetUpgradeGenerator::get_upgrade_cost(pet_upgrade.upgrades[depth]);
  858. if cost > battle_points {
  859. break;
  860. }
  861. pet_upgrade.upgrades[depth] += 1;
  862. battle_points -= cost;
  863. }
  864. pet_upgrades
  865. }
  866.  
  867. fn get_upgrade_cost(current_level: i32) -> i32 {
  868. if current_level < 10 {
  869. current_level + 1
  870. } else {
  871. current_level + 1 + PetUpgradeGenerator::get_upgrade_cost(current_level - 10)
  872. }
  873. }
  874. }
  875.  
  876. // *** battle.rs
  877. pub struct Battle {
  878. pub use_attack_potion: bool,
  879. pub use_defence_potion: bool,
  880. }
  881.  
  882. impl Battle {
  883. pub fn build(use_attack_potion: bool, use_defence_potion: bool) -> Battle {
  884. Battle {
  885. use_attack_potion: use_attack_potion,
  886. use_defence_potion: use_defence_potion,
  887. }
  888. }
  889.  
  890. pub fn get_best_result<'a>(&self, pets: &'a [Pet], enemy: &Enemy) -> (f32, &'a Pet) {
  891. let results_by_pet = pets.iter()
  892. .map(|p| (self.do_battle(p, enemy), p))
  893. .collect::<Vec<_>>();
  894. let best_result = results_by_pet
  895. .iter()
  896. .min_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(Ordering::Equal))
  897. .unwrap(); //& maybe
  898.  
  899. (
  900. if best_result.0 < 0.0 {
  901. 0.0
  902. } else {
  903. best_result.0
  904. },
  905. best_result.1,
  906. )
  907. }
  908.  
  909. fn do_battle(&self, pet: &Pet, enemy: &Enemy) -> f32 {
  910. let pet_hp = pet.health;
  911. let enemy_hp = enemy.health;
  912. let potion_hp = 0.25 * pet.health;
  913.  
  914. let attack_adjust = if self.use_attack_potion { 1.5 } else { 1.0 };
  915. let defence_adjust = if self.use_defence_potion { 0.5 } else { 1.0 };
  916.  
  917. // Apply ATTACK
  918. let mut pet_attack_per_round = attack_adjust * pet.attack;
  919.  
  920. // Apply LIFESTEAL
  921. let mut enemy_attack_per_round = -0.25 * pet.lifesteal;
  922.  
  923. // Apply DEFENCE
  924. enemy_attack_per_round += defence_adjust * (enemy.damage * 1.05 - pet.defence);
  925.  
  926. // Apply BLOCK
  927. enemy_attack_per_round -= 0.3 * pet.block;
  928.  
  929. // Apply REFLECT
  930. pet_attack_per_round += 0.3 * pet.reflect;
  931.  
  932. // Compute end of battle stats
  933. let battle_rounds = (enemy_hp / pet_attack_per_round).ceil();
  934. let pet_hp_after_battle = pet_hp - battle_rounds * enemy_attack_per_round;
  935.  
  936. -pet_hp_after_battle / potion_hp
  937. }
  938. }
Add Comment
Please, Sign In to add comment