use std::collections::HashMap; use std::rc::Rc; use rand::prelude::*; use crate::entity::Entity; use crate::person::Person; use crate::time::Time; use crate::world::{World, Terrain, Town, Tavern}; use crate::events::{FoundTown, WorldGenesis, PersonGenesis, TavernBuilt}; pub struct GameState { pub time: Time, pub world: World, pub people: HashMap, pub events: Vec>, pub tavern: Option>, } pub struct Event { pub time: Time, pub effect: Box, } pub trait Effect { fn apply(&self, state: &mut GameState); fn description(&self) -> String; } impl Event { pub fn description(&self) -> String { format!("{}: {}", self.time, self.effect.description()) } } impl GameState { pub fn new(world: World) -> GameState { let mut events = Vec::new(); events.push(Box::new(Event { time: Time { time: 0 }, effect: Box::new(WorldGenesis), })); GameState { time: Time { time: 0 }, people: HashMap::new(), world: world, events: events, tavern: None, } } pub fn set_tavern(&mut self, tavern: Rc) { self.tavern = Some(tavern); } pub fn add_event(&mut self, event: Event) { event.effect.apply(self); self.events.push(Box::new(event)); } pub fn step(&mut self) { let ids: Vec = self.people.keys().map(|id| *id).collect(); for id in ids { let mut person = self.people.get_mut(&id).unwrap().clone(); person.step(self); self.people.insert(id, person); } self.time.time += 1; } pub fn step_n(&mut self, n: u32) { for _ in 0..n { self.step(); } } pub fn step_year(&mut self) { for _ in 0..360 { self.step(); } } /** * Getters */ pub fn guests(&self) -> Vec { match &self.tavern { Some(tavern) => { let loc = self.world.get_tavern_location(tavern); self.people.values().filter(|person| { person.location == loc }).map(|p| p.clone()).collect() }, None => Vec::new(), } } pub fn get_person(&self, id: u32) -> Option<&Person> { self.people.get(&id) } /** * Function to populate the world at genesis */ pub fn found_town(&mut self) { let mut rng = rand::thread_rng(); loop { let x = rng.gen_range(0..self.world.size); let y = rng.gen_range(0..self.world.size); if self.world.map[x][y].terrain == Terrain::Flats || self.world.map[x][y].terrain == Terrain::Hills { let town = Rc::new(Town::new()); self.add_event(Event { time: self.time, effect: Box::new(FoundTown { x: x, y: y, town: town.clone(), }) }); let pop_size = rng.gen_range(20..200); for _ in 0..pop_size { self.add_event(Event { time: self.time, effect: Box::new(PersonGenesis { town: town.clone(), person: Person::new( self.time.substract_years(rng.gen_range(18..30)), town.clone(), self.world.get_town_location(&town) ), }) }); } break; } } } pub fn add_person(&mut self, person: &mut Person) { let id = (self.people.len() + 1) as u32; // avoid 0 id person.set_id(id); self.people.insert(id, person.clone()); } pub fn build_tavern(&mut self) { let mut rng = rand::thread_rng(); loop { let x = rng.gen_range(0..self.world.size); let y = rng.gen_range(0..self.world.size); if self.world.map[x][y].terrain == Terrain::Flats || self.world.map[x][y].terrain == Terrain::Hills { self.add_event(Event { time: self.time, effect: Box::new(TavernBuilt { x: x, y: y, tavern: Rc::new(Tavern::new()), }) }); break; } } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_step() { let mut state = GameState::new(World::new(100)); state.step(); assert_eq!(state.time.time, 1); } #[test] fn test_step_n() { let mut state = GameState::new(World::new(100)); state.step_n(10); assert_eq!(state.time.time, 10); } #[test] fn test_step_year() { let mut state = GameState::new(World::new(100)); state.step_year(); assert_eq!(state.time.time, 360); } #[test] fn test_found_town() { let mut state = GameState::new(World::new(1)); state.world.map[0][0].terrain = Terrain::Flats; state.time = Time { time: 1e6 as u32 }; state.found_town(); assert_ne!(state.people.len(), 0); } #[test] fn test_build_tavern() { let mut state = GameState::new(World::new(2)); state.world.map[0][0].terrain = Terrain::Flats; state.world.map[0][1].terrain = Terrain::Flats; state.world.map[1][0].terrain = Terrain::Hills; state.world.map[1][1].terrain = Terrain::Hills; state.build_tavern(); assert_eq!(state.tavern.is_some(), true); } }