use rand::Rng;
use crate::entity::{Enemy, Hero};
use crate::entity::{Entity, User};
use crate::get_user_input;
pub enum BattleOutcome {
Win,
Loss,
}
pub fn battle(
hero_party: &mut Vec<Box<&mut Hero>>,
enemy_party: &mut Vec<Box<&mut Enemy>>,
) -> BattleOutcome {
println!("The battle begins!");
loop {
for hero in hero_party.iter_mut() {
println!("{}: {}", hero.get_name(), hero.get_current_health());
}
for enemy in enemy_party.iter_mut() {
println!("{}: {}", enemy.get_name(), enemy.get_current_health());
}
for hero in hero_party.iter_mut() {
let mut user_input = String::new();
println!("Select an enemy for {} to focus on: ", hero.get_name());
for (index, enemy) in enemy_party.iter_mut().enumerate() {
println!("{}: {}", index, enemy.get_name());
}
let user_input = get_user_input("");
let mut user_input = user_input.trim().parse::<usize>().unwrap_or_default();
if user_input >= enemy_party.len() {
println!("Invalid input, targetting first enemy");
user_input = 0;
}
hero.get_action(&mut enemy_party[user_input as usize]);
}
check_for_deaths(enemy_party);
if enemy_party.is_empty() {
println!("All enemies have been defeated!");
return BattleOutcome::Win;
}
for enemy in enemy_party.iter_mut() {
let len = hero_party.len();
let rand_hero_index = rand::thread_rng().gen_range(0..len);
enemy.make_decision(&mut hero_party[rand_hero_index as usize]);
}
check_for_deaths(hero_party);
if hero_party.is_empty() {
println!("All heros have been defeated!");
return BattleOutcome::Loss;
}
println!("The battle rages on!");
}
}
fn check_for_deaths<T: Entity>(party: &mut Vec<Box<&mut T>>) {
let mut indices_to_remove = Vec::new();
for (index, member) in party.iter_mut().enumerate() {
if member.is_dead() {
println!("{} has died!", member.get_name());
indices_to_remove.push(index);
}
}
for index in indices_to_remove.into_iter().rev() {
party.remove(index);
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::{self, BufRead};
fn read_user_input<R: BufRead>(mut reader: R) -> String {
let mut input = String::new();
reader.read_line(&mut input).expect("Failed to read line");
input.trim().to_string()
}
mod user_input_functions {
use super::*;
use std::io::Cursor;
#[test]
fn test_read_user_input() {
let input_data = "test input\n";
let cursor = Cursor::new(input_data);
let result = read_user_input(cursor);
assert_eq!(result, "test input");
}
}
#[test]
#[ignore]
fn test_battle_ownership() {
let mut hero = Hero::default();
let mut enemy = Enemy::default();
let mut hero_party: Vec<Box<&mut Hero>> = Vec::new();
let mut enemy_party: Vec<Box<&mut Enemy>> = Vec::new();
hero_party.push(Box::new(&mut hero));
enemy_party.push(Box::new(&mut enemy));
battle(&mut hero_party, &mut enemy_party);
assert!(true);
}
}