Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 65 additions & 11 deletions ocean/src/beach.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we remove the TODO: statements here if they are no longer needed?

crabs: Vec<Crab>,
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()
}

/**
Expand All @@ -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<Crab> {
unimplemented!();
self.crabs.iter()
}

/**
Expand All @@ -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()
}

/**
Expand All @@ -62,29 +68,77 @@ 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
}

/**
* Adds a crab that lives on the beach as a member to the clan system for the given clan id and the crab's name.
* 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);
}

/**
* Returns the id of the clan that wins the competition given two clan ids. The winner is decided based on the average speed of the clan members.
* 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<Option<String>, 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<u32, String> {
Copy link

@186shades 186shades Jan 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job of breaking a big function into smaller logical functions! Could we add comment over this function to explain what it does to increase readability?

let clan_system = self.get_clan_system(); // Assuming you have a method to get the clan system

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove this comment as we do have a method to get clan system in the code?


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<u32, String> {
Copy link

@186shades 186shades Jan 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job of breaking a big function into smaller logical functions! Could we add comment over this function to explain what it does to increase readability?

for crab in self.crabs() {
if crab.name() == crab_name {
return Ok(crab.speed());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove the keyword return here for consistency in coding style?

}
}
Err(format!("Crab with name '{}' not found", crab_name))
}
}
41 changes: 36 additions & 5 deletions ocean/src/clans.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,70 @@
#[derive(Debug)]
pub struct Clan {
pub id: String,
pub members: Vec<String>,
}

#[derive(Debug)]
pub struct ClanSystem {
// TODO: add necessary fields
pub clans: Vec<Clan>,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would using a std::collections::HashMap be better than Vec<Clan> here as clan ids are unique anyway?

}

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<String> {
unimplemented!();
if let Some(clan) = self.clans.iter().find(|c| c.id == clan_id) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could using the hashmap help increase efficiency here as we might not have to iter through the whole list explicitely?

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) {
Copy link

@186shades 186shades Jan 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hashmap could help improve brevity and efficiency here as well I think.

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<String> {
unimplemented!();
self.clans
.iter()
.max_by_key(|clan| clan.members.len())
.map(|clan| clan.id.clone())
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add comment over this function to explain what it does to increase readability?

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) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also maybe make this implemetation succint & efficient by use of hashmap and functions available for hashmap?

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);
}
}
}
6 changes: 5 additions & 1 deletion ocean/src/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
}
}
55 changes: 44 additions & 11 deletions ocean/src/crab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Rc<RefCell<Reef>>>,
}

// 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
Expand All @@ -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<RefCell<Reef>>) {
unimplemented!();
self.reefs.push(reef);
}

/**
Expand All @@ -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<dyn Prey>, 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<dyn Prey>, reef_index: usize) {
unimplemented!();
if let Some(reef) = self.reefs.get_mut(reef_index) {
reef.borrow_mut().add_prey(prey);
}
}

/**
Expand Down Expand Up @@ -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
}

/**
Expand All @@ -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)
}
}
Loading