diff --git a/ocean/src/beach.rs b/ocean/src/beach.rs index 7c8912c..0472381 100644 --- a/ocean/src/beach.rs +++ b/ocean/src/beach.rs @@ -3,22 +3,28 @@ use crate::crab::Crab; use crate::diet::Diet; use crate::clans::ClanSystem; use std::slice::Iter; +use std::cmp::Ordering; #[derive(Debug)] pub struct Beach { // TODO: Declare the fields of the Beach struct here. + crabs: Vec, + clan_system: ClanSystem, } impl Beach { pub fn new() -> Beach { - unimplemented!(); + Beach { + crabs: Vec::new(), + clan_system: ClanSystem::new(), + } } /** * Returns the number of crabs on the beach. */ pub fn size(&self) -> usize { - unimplemented!(); + self.crabs.len() } /** @@ -29,15 +35,15 @@ impl Beach { * - The newly added crab should be at the END of the collection. */ pub fn add_crab(&mut self, crab: Crab) { - unimplemented!(); + self.crabs.push(crab); } pub fn get_crab(&self, index: usize) -> &Crab { - unimplemented!(); + &self.crabs[index] } pub fn crabs(&self) -> Iter { - unimplemented!(); + self.crabs.iter() } /** @@ -46,14 +52,14 @@ impl Beach { * - Some of a reference to the Crab with the highest speed. */ pub fn get_fastest_crab(&self) -> Option<&Crab> { - unimplemented!(); + self.crabs.iter().max_by_key(|crab| crab.speed()) } /** * Returns a vector of references to the crabs with a given name. */ pub fn find_crabs_by_name(&self, name: &str) -> Vec<&Crab> { - unimplemented!(); + self.crabs.iter().filter(|crab| crab.name() == name).collect() } /** @@ -62,14 +68,20 @@ impl Beach { * the method should panic. */ pub fn breed_crabs(&mut self, i: usize, j: usize, name: String) { - unimplemented!(); + let crab_i = self.crabs.get(i).expect("Index out of bounds"); + let crab_j = self.crabs.get(j).expect("Index out of bounds"); + let diet = Diet::random_diet(); + let color = Color::cross(crab_i.color(), crab_j.color()); + let new_crab = Crab::new(name, 1, color, diet); + + self.add_crab(new_crab); } /** * Returns a reference to the clan system associated with the beach. */ pub fn get_clan_system(&self) -> &ClanSystem { - unimplemented!(); + &self.clan_system } /** @@ -77,7 +89,7 @@ impl Beach { * A crab can only belong to one clan. */ pub fn add_member_to_clan(&mut self, clan_id: &str, crab_name: &str) { - unimplemented!(); + self.clan_system.add_member_to_clan(clan_id, crab_name); } /** @@ -85,6 +97,48 @@ impl Beach { * Return `None` if there are no clear winners between two different existing clans. If the inputs are invalid, return an Err string. */ pub fn get_winner_clan(&self, id1: &str, id2: &str) -> Result, String> { - unimplemented!(); + let clan1_speed = self.calculate_average_speed(id1)?; + let clan2_speed = self.calculate_average_speed(id2)?; + + match clan1_speed.cmp(&clan2_speed) { + Ordering::Greater => Ok(Some(id1.to_string())), + Ordering::Less => Ok(Some(id2.to_string())), + Ordering::Equal => Ok(None), + + } + } + + fn calculate_average_speed(&self, clan_id: &str) -> Result { + let clan_system = self.get_clan_system(); // Assuming you have a method to get the clan system + + let clan = clan_system.clans.iter().find(|c| c.id == clan_id); + + if let Some(clan) = clan { + let total_speed: u32 = clan + .members + .iter() + .filter_map(|member_name| { + self.get_crab_speed_by_name(member_name).ok() + }) + .sum(); + + let member_count = clan.members.len() as u32; + if member_count > 0 { + Ok(total_speed / member_count) + } else { + Err("Clan has no members".to_string()) + } + } else { + Err("Clan not found".to_string()) + } + } + + fn get_crab_speed_by_name(&self, crab_name: &str) -> Result { + for crab in self.crabs() { + if crab.name() == crab_name { + return Ok(crab.speed()); + } + } + Err(format!("Crab with name '{}' not found", crab_name)) } } diff --git a/ocean/src/clans.rs b/ocean/src/clans.rs index c138922..10682db 100644 --- a/ocean/src/clans.rs +++ b/ocean/src/clans.rs @@ -1,39 +1,70 @@ +#[derive(Debug)] +pub struct Clan { + pub id: String, + pub members: Vec, +} #[derive(Debug)] pub struct ClanSystem { // TODO: add necessary fields + pub clans: Vec, } impl ClanSystem { pub fn new() -> ClanSystem { - unimplemented!(); + ClanSystem { + clans: Vec::new(), + } } /** * Returns a list of the names of the clan members for the given clan id. */ pub fn get_clan_member_names(&self, clan_id: &str) -> Vec { - unimplemented!(); + if let Some(clan) = self.clans.iter().find(|c| c.id == clan_id) { + clan.members.clone() + } else { + Vec::new() + } } /** * Returns the number of clans currently in existence. */ pub fn get_clan_count(&self) -> usize { - unimplemented!(); + self.clans.len() } /** * Returns the number of clan members for the given clan id. */ pub fn get_clan_member_count(&self, clan_id: &str) -> usize { - unimplemented!(); + if let Some(clan) = self.clans.iter().find(|c| c.id == clan_id) { + clan.members.len() + } else { + 0 + } } /** * Returns the id of the clan with the most number of members, or None if such a clan does not exist. */ pub fn get_largest_clan_id(&self) -> Option { - unimplemented!(); + self.clans + .iter() + .max_by_key(|clan| clan.members.len()) + .map(|clan| clan.id.clone()) + } + + pub fn add_member_to_clan(&mut self, clan_id: &str, crab_name: &str) { + if let Some(clan) = self.clans.iter_mut().find(|c| c.id == clan_id) { + clan.members.push(crab_name.to_string()); + } else { + let new_clan = Clan { + id: clan_id.to_string(), + members: vec![crab_name.to_string()], + }; + self.clans.push(new_clan); + } } } \ No newline at end of file diff --git a/ocean/src/color.rs b/ocean/src/color.rs index bea5d9b..5c56c9e 100644 --- a/ocean/src/color.rs +++ b/ocean/src/color.rs @@ -34,6 +34,10 @@ impl Color { * https://doc.rust-lang.org/std/primitive.u8.html */ pub fn cross(c1: &Color, c2: &Color) -> Color { - unimplemented!(); + Color { + r: c1.r.wrapping_add(c2.r), + g: c1.g.wrapping_add(c2.g), + b: c1.b.wrapping_add(c2.b), + } } } diff --git a/ocean/src/crab.rs b/ocean/src/crab.rs index f3bf105..ff1eab5 100644 --- a/ocean/src/crab.rs +++ b/ocean/src/crab.rs @@ -9,28 +9,39 @@ use std::rc::Rc; #[derive(Debug)] pub struct Crab { // TODO: Add fields here (some in part 1, some in part 2) + name: String, + speed: u32, + color: Color, + diet: Diet, + reefs: Vec>>, } // Do NOT implement Copy for Crab. impl Crab { pub fn new(name: String, speed: u32, color: Color, diet: Diet) -> Crab { - unimplemented!(); + Crab { + name, + speed, + color, + diet, + reefs: Vec::new(), + } } pub fn name(&self) -> &str { - unimplemented!(); + &self.name } pub fn speed(&self) -> u32 { - unimplemented!(); + self.speed } pub fn color(&self) -> &Color { - unimplemented!(); + &self.color } pub fn diet(&self) -> Diet { - unimplemented!(); + self.diet } // PART 2 BELOW @@ -40,7 +51,7 @@ impl Crab { * Have this crab discover a new reef, adding it to its list of reefs. */ pub fn discover_reef(&mut self, reef: Rc>) { - unimplemented!(); + self.reefs.push(reef); } /** @@ -53,14 +64,21 @@ impl Crab { * If all reefs are empty, or this crab has no reefs, return None. */ fn catch_prey(&mut self) -> Option<(Box, usize)> { - unimplemented!(); + for (index, reef) in self.reefs.iter_mut().enumerate() { + if let Some(prey) = reef.borrow_mut().take_prey() { + return Some((prey, index)); + } + } + None } /** * Releases the given prey back into the reef at the given index. */ fn release_prey(&mut self, prey: Box, reef_index: usize) { - unimplemented!(); + if let Some(reef) = self.reefs.get_mut(reef_index) { + reef.borrow_mut().add_prey(prey); + } } /** @@ -100,7 +118,22 @@ impl Crab { * Note: this pseudocode reads like a terrible poem. */ pub fn hunt(&mut self) -> bool { - unimplemented!(); + let mut escaped_prey = Vec::new(); + let mut prey_caught = false; + + while let Some((mut prey, reef_index)) = self.catch_prey() { + if !prey.try_escape(self) && prey.diet() == self.diet { + prey_caught = true; + } else { + escaped_prey.push((prey, reef_index)); + } + } + + for (prey, reef_index) in escaped_prey { + self.release_prey(prey, reef_index); + } + + prey_caught } /** @@ -111,7 +144,7 @@ impl Crab { * up to you to figure out which ones and where. Do not make any other changes * to the signature. */ - pub fn choose_recipe(&self, cookbook: &Cookbook) -> Option<&Recipe> { - unimplemented!(); + pub fn choose_recipe<'a>(&self, cookbook: &'a Cookbook) -> Option<&'a Recipe> { + cookbook.recipes().find(|recipe| recipe.diet() == self.diet) } } diff --git a/ocean/src/ocean.rs b/ocean/src/ocean.rs index f8a83b9..a70a1cf 100644 --- a/ocean/src/ocean.rs +++ b/ocean/src/ocean.rs @@ -8,23 +8,28 @@ use std::slice::Iter; #[derive(Debug)] pub struct Ocean { // TODO: Fill in fields here. + beaches: Vec, + reefs: Vec>>, } impl Ocean { pub fn new() -> Ocean { - unimplemented!(); + Ocean { + beaches: Vec::new(), + reefs: Vec::new(), + } } pub fn add_beach(&mut self, beach: Beach) { - unimplemented!(); + self.beaches.push(beach); } pub fn beaches(&self) -> Iter { - unimplemented!(); + self.beaches.iter() } pub fn reefs(&self) -> Iter>> { - unimplemented!(); + self.reefs.iter() } /** @@ -41,6 +46,28 @@ impl Ocean { n_clams: u32, n_algae: u32, ) -> Rc> { - unimplemented!(); + let mut reef = Reef::new(); + let mut _rng = rand::thread_rng(); + + for _ in 0..n_minnows { + reef.add_prey(Box::new(Minnow::new(25))); + } + + for _ in 0..n_shrimp { + reef.add_prey(Box::new(Shrimp::new(1))); + } + + for _ in 0..n_clams { + reef.add_prey(Box::new(Clam::new())); + } + + for _ in 0..n_algae { + reef.add_prey(Box::new(Algae::new())); + } + + let reef_rc = Rc::new(RefCell::new(reef)); + self.reefs.push(reef_rc.clone()); + + reef_rc } } diff --git a/ocean/src/reef.rs b/ocean/src/reef.rs index dc421de..e8dc993 100644 --- a/ocean/src/reef.rs +++ b/ocean/src/reef.rs @@ -11,15 +11,17 @@ pub struct Reef { impl Reef { pub fn new() -> Self { - unimplemented!(); + Reef { + prey: VecDeque::new(), + } } pub fn prey(&self) -> Iter> { - unimplemented!(); + self.prey.iter() } pub fn population(&self) -> usize { - unimplemented!(); + self.prey.len() } /** @@ -28,7 +30,7 @@ impl Reef { * This function takes ownership of the boxed prey. */ pub fn add_prey(&mut self, prey: Box) { - unimplemented!(); + self.prey.push_back(prey); } /** @@ -37,6 +39,6 @@ impl Reef { * The callee of this function receives ownership of the boxed prey. */ pub fn take_prey(&mut self) -> Option> { - unimplemented!(); + self.prey.pop_front() } }