From 52cd68d89f75f6b8dfa18c8e6ac17fb668b9b0a6 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Mon, 28 Jul 2025 05:10:13 +0100 Subject: [PATCH 1/2] fix(quest-08) --- solutions/blood_types/src/lib.rs | 405 ++++-------------- solutions/commits_stats/Cargo.toml | 4 +- solutions/commits_stats/src/lib.rs | 145 +------ solutions/easy_traits/src/lib.rs | 141 +----- solutions/easy_traits/src/main.rs | 1 - solutions/generics/src/lib.rs | 41 +- solutions/generics_list/src/lib.rs | 151 +------ solutions/lalgebra_scalar/src/lib.rs | 121 ++---- solutions/lalgebra_vector/src/lib.rs | 72 +--- solutions/minesweeper/src/lib.rs | 72 ++-- solutions/roman_numbers/src/iterator.rs | 107 ----- solutions/roman_numbers/src/lib.rs | 156 +++---- solutions/traits/src/lib.rs | 139 ++---- solutions/vector_operations/src/lib.rs | 57 +-- tests/blood_types_test/src/lib.rs | 126 ++++++ tests/blood_types_test/src/main.rs | 187 -------- tests/commits_stats_test/Cargo.toml | 4 +- tests/commits_stats_test/src/lib.rs | 46 ++ tests/commits_stats_test/src/main.rs | 98 ----- tests/easy_traits_test/src/lib.rs | 48 +++ tests/easy_traits_test/src/main.rs | 78 ---- .../src/{main.rs => lib.rs} | 15 - tests/generics_test/src/{main.rs => lib.rs} | 7 - .../src/{main.rs => lib.rs} | 24 +- tests/lalgebra_vector_test/Cargo.toml | 1 - tests/lalgebra_vector_test/src/lib.rs | 18 + tests/lalgebra_vector_test/src/main.rs | 71 --- tests/minesweeper_test/src/lib.rs | 93 ++++ tests/minesweeper_test/src/main.rs | 106 ----- tests/roman_numbers_test/src/lib.rs | 27 ++ tests/roman_numbers_test/src/main.rs | 49 --- tests/traits_test/src/lib.rs | 66 +++ tests/traits_test/src/main.rs | 97 ----- tests/vector_operations_test/src/lib.rs | 17 + tests/vector_operations_test/src/main.rs | 40 -- 35 files changed, 777 insertions(+), 2053 deletions(-) delete mode 100644 solutions/easy_traits/src/main.rs delete mode 100644 solutions/roman_numbers/src/iterator.rs create mode 100644 tests/blood_types_test/src/lib.rs delete mode 100644 tests/blood_types_test/src/main.rs create mode 100644 tests/commits_stats_test/src/lib.rs delete mode 100644 tests/commits_stats_test/src/main.rs create mode 100644 tests/easy_traits_test/src/lib.rs delete mode 100644 tests/easy_traits_test/src/main.rs rename tests/generics_list_test/src/{main.rs => lib.rs} (76%) rename tests/generics_test/src/{main.rs => lib.rs} (63%) rename tests/lalgebra_scalar_test/src/{main.rs => lib.rs} (55%) create mode 100644 tests/lalgebra_vector_test/src/lib.rs delete mode 100644 tests/lalgebra_vector_test/src/main.rs create mode 100644 tests/minesweeper_test/src/lib.rs delete mode 100644 tests/minesweeper_test/src/main.rs create mode 100644 tests/roman_numbers_test/src/lib.rs delete mode 100644 tests/roman_numbers_test/src/main.rs create mode 100644 tests/traits_test/src/lib.rs delete mode 100644 tests/traits_test/src/main.rs create mode 100644 tests/vector_operations_test/src/lib.rs delete mode 100644 tests/vector_operations_test/src/main.rs diff --git a/solutions/blood_types/src/lib.rs b/solutions/blood_types/src/lib.rs index 5df83b16..849b15c0 100644 --- a/solutions/blood_types/src/lib.rs +++ b/solutions/blood_types/src/lib.rs @@ -1,39 +1,6 @@ -// In this exercise you will create a model of and gives an API to -// deal with blood types +use std::{fmt, str::FromStr}; -// Start creating the data representation of the blood types -// Create the enumerator `Antigen` that has 4 possibilities: A, B, O and AB -// And the enumerator `RhFactor` that has two possible values: Positive -// and Negative - -// After, create the struct BloodType that contains two fields with the -// names antigen and rh_factor - -// To provide a simple way to create blood types implement the trait -// FromStr for BloodType (which will allow us to use the `parse` -// method and the associated function from_str, so we can do: -// ```rust -// let a_neg: BloodType = "A-".parse(); -// ``` -//) - -// Implement the std::cmp::Ord trait to make possible to sort a vector -// or array of BloodType's - -// Implement the trait std::Debug for BloodType allowing to print a -// vector such as [BloodType { antigen: A, rh_factor: Positive}, -// BloodType{ antigen: B, rh_factor: Negative}] as [ A+, A-] using the -// formatting {:?} - -// Write three methods for BloodType: -// - can_receive_from(&self, other: BloodType) -> bool {}: which -// returns true if self can receive blood from `other` blood type -// - donors(&self) -> Vec: which returns -// all the blood types that can give blood to self -// - recipients(&self) -> Vec: which returns all the blood -// types that can receive blood from self - -#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord)] +#[derive(PartialEq, Eq, Hash, Clone, Copy)] pub enum Antigen { A, AB, @@ -41,327 +8,137 @@ pub enum Antigen { O, } -use std::cmp::{Ord, Ordering}; - -use std::str::FromStr; - -impl FromStr for Antigen { - type Err = String; - fn from_str(s: &str) -> Result { - match s { - "A" => Ok(Antigen::A), - "AB" => Ok(Antigen::AB), - "B" => Ok(Antigen::B), - "O" => Ok(Antigen::O), - other => Err(format!("`{}` is not a valid antigen", other)), - } - } -} - -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] +#[derive(PartialEq, Eq, Hash, Clone, Copy)] pub enum RhFactor { Positive, Negative, } -impl FromStr for RhFactor { - type Err = String; - fn from_str(rhf: &str) -> Result { - match rhf { - "+" => Ok(RhFactor::Positive), - "-" => Ok(RhFactor::Negative), - o => Err(format!("`{}` is not a valid Rh Factor", o)), - } - } -} - -#[derive(PartialEq, Eq, PartialOrd)] +#[derive(PartialEq, Eq, Hash, Clone, Copy)] pub struct BloodType { - pub antigen: Antigen, pub rh_factor: RhFactor, + pub antigen: Antigen, } -impl Ord for BloodType { - fn cmp(&self, other: &Self) -> Ordering { - if self.rh_factor == other.rh_factor { - return self.antigen.cmp(&other.antigen); - } - self.antigen.cmp(&other.antigen) - } -} - -impl FromStr for BloodType { - type Err = String; - - fn from_str(bt: &str) -> Result { - if bt.len() > 3 || bt.len() < 2 { - return Err(format!( - "Invalid antigen: `{}` invalid length: {}", - bt, - bt.len() - )); - } - - let rh_fac_str = bt.get(bt.len() - 1..); - - if let None = rh_fac_str { - return Err(format!("Invalid suffix {:?}", rh_fac_str)); - } - - let rh_factor = rh_fac_str.unwrap().parse()?; - let antigen = bt.get(..bt.len() - 1).unwrap().parse()?; - - Ok(BloodType { antigen, rh_factor }) - } +impl Antigen { + pub const EVERY: &[Self] = &[Self::A, Self::AB, Self::B, Self::O]; } -use std::fmt::{self, Debug}; - -impl Debug for BloodType { +impl fmt::Debug for Antigen { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.antigen)?; - - if self.rh_factor == RhFactor::Positive { - return write!(f, "+"); - } - - write!(f, "-") + write!( + f, + "{}", + match self { + Self::A => "A", + Self::AB => "AB", + Self::B => "B", + Self::O => "O", + } + ) } } -impl BloodType { - pub fn can_receive_from(&self, other: &Self) -> bool { - // Positive can only receive from positive - // A can only give from A - // And B can only give to B - if self.rh_factor != other.rh_factor && self.rh_factor == RhFactor::Negative { - return false; - } +impl FromStr for Antigen { + type Err = (); - if other.antigen == Antigen::O { - return true; + #[inline] + fn from_str(s: &str) -> Result { + match s { + "A" => Ok(Self::A), + "AB" => Ok(Self::AB), + "B" => Ok(Self::B), + "O" => Ok(Self::O), + _ => Err(()), } - - // if self.rh_factor contains one of the antigens of other - // then it can receive from it - self.antigen == Antigen::AB || other.antigen == self.antigen } +} - // who are the donors of self - pub fn donors(&self) -> Vec { - // all blood types A, B, AB, O - let mut blood_types = Vec::new(); - let mut antigens = if self.antigen == Antigen::O { - vec![Antigen::O] - } else { - vec![Antigen::O, self.antigen.clone()] - }; - - let rh_factors = if self.rh_factor == RhFactor::Negative { - vec![RhFactor::Negative] - } else { - vec![RhFactor::Positive, RhFactor::Negative] - }; - - if self.antigen == Antigen::AB { - antigens.extend(vec![Antigen::A, Antigen::B]); - } +impl RhFactor { + pub const EVERY: &[Self] = &[Self::Positive, Self::Negative]; +} - for factor in rh_factors.iter() { - for ant in antigens.iter() { - blood_types.push(BloodType { - rh_factor: (*factor).clone(), - antigen: (*ant).clone(), - }) +impl fmt::Debug for RhFactor { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self { + Self::Positive => "+", + Self::Negative => "-", } - } - - blood_types + ) } +} - // who are the recipients of self - pub fn recipients(&self) -> Vec { - let mut blood_types = Vec::new(); - let mut antigens = if self.antigen != Antigen::AB { - vec![Antigen::AB, self.antigen.clone()] - } else { - vec![Antigen::AB] - }; - - let rh_factors = if self.rh_factor == RhFactor::Negative { - vec![RhFactor::Positive, RhFactor::Negative] - } else { - vec![RhFactor::Positive] - }; - - if self.antigen == Antigen::O { - antigens.extend(vec![Antigen::A, Antigen::B]); - } +impl FromStr for RhFactor { + type Err = (); - for factor in rh_factors.iter() { - for ant in antigens.iter() { - blood_types.push(BloodType { - rh_factor: (*factor).clone(), - antigen: (*ant).clone(), - }) - } + #[inline] + fn from_str(s: &str) -> Result { + match s { + "+" => Ok(Self::Positive), + "-" => Ok(Self::Negative), + _ => Err(()), } - - blood_types } } -// fn main() { -// let blood_type: BloodType = "O+".parse().unwrap(); -// println!("recipients of O+ {:?}", blood_type.recipients()); -// println!("donors of O+ {:?}", blood_type.donors()); -// let another_blood_type: BloodType = "A-".parse().unwrap(); -// println!( -// "donors of O+ can receive from {:?} {:?}", -// &another_blood_type, -// blood_type.can_receive_from(&another_blood_type) -// ); -// } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn compatible_ab_neg_with_a_pos() { - let blood_type: BloodType = "AB-".parse().unwrap(); - let other_bt: BloodType = "A+".parse().unwrap(); - assert!(!blood_type.can_receive_from(&other_bt)); - } - - #[test] - fn compatible_a_neg_with_a_pos() { - let blood_type: BloodType = "A-".parse().unwrap(); - let other_bt: BloodType = "A+".parse().unwrap(); - assert!(!blood_type.can_receive_from(&other_bt)); - } - - #[test] - fn compatible_a_neg_with_ab_neg() { - let blood_type: BloodType = "AB-".parse().unwrap(); - let other_bt: BloodType = "A-".parse().unwrap(); - assert!(blood_type.can_receive_from(&other_bt)); - } - - #[test] - fn compatible_ab_neg_with_o_pos() { - let blood_type: BloodType = "AB-".parse().unwrap(); - let other_bt: BloodType = "O+".parse().unwrap(); - assert!(!blood_type.can_receive_from(&other_bt)); - } - - #[test] - fn compatible_ab_pos_with_o_pos() { - let blood_type: BloodType = "AB+".parse().unwrap(); - let other_bt: BloodType = "O+".parse().unwrap(); - assert!(blood_type.can_receive_from(&other_bt)); - } - - #[test] - fn test_compatible_ab_neg_with_o_neg() { - let blood_type: BloodType = "AB-".parse().unwrap(); - let other_bt: BloodType = "O-".parse().unwrap(); - assert!(blood_type.can_receive_from(&other_bt)); - } +impl FromStr for BloodType { + type Err = (); - #[test] - fn test_antigen_ab_from_str() { - let blood = "AB+"; - let blood_type: BloodType = blood.parse().unwrap(); - assert_eq!(blood_type.antigen, Antigen::AB); - assert_eq!(blood_type.rh_factor, RhFactor::Positive); - } + fn from_str(s: &str) -> Result { + let (antigen, rh) = s.split_at_checked(s.len() - 1).ok_or(())?; - #[test] - fn test_antigen_a_from_str() { - let blood = "A-"; - let blood_type = blood.parse::().unwrap(); - assert_eq!(blood_type.antigen, Antigen::A); - assert_eq!(blood_type.rh_factor, RhFactor::Negative); + Ok(Self { + antigen: antigen.parse()?, + rh_factor: rh.parse()?, + }) } +} - #[test] - #[should_panic] - fn test_unexistent_blood_type() { - let _blood_type: BloodType = "AO-".parse().unwrap(); +impl fmt::Debug for BloodType { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}{:?}", self.antigen, self.rh_factor) } +} - #[test] - fn test_donors() { - let mut givers = "AB+".parse::().unwrap().donors(); - println!("Before sorting {:?}", &givers); - givers.sort(); - println!("{:?}", &givers); - let mut expected = vec![ - "AB-".parse::().unwrap(), - "A-".parse().unwrap(), - "B-".parse().unwrap(), - "O-".parse().unwrap(), - "AB+".parse().unwrap(), - "A+".parse().unwrap(), - "B+".parse().unwrap(), - "O+".parse().unwrap(), - ]; - expected.sort(); - assert_eq!(givers, expected); +impl BloodType { + #[inline] + pub fn every() -> impl Iterator { + Antigen::EVERY.iter().copied().flat_map(|a| { + RhFactor::EVERY.iter().copied().map(move |r| Self { + antigen: a, + rh_factor: r, + }) + }) } - #[test] - fn test_a_neg_donors() { - let mut givers = "A-".parse::().unwrap().donors(); - givers.sort(); - let mut expected: Vec = vec!["A-".parse().unwrap(), "O-".parse().unwrap()]; - expected.sort(); - assert_eq!(givers, expected); + #[inline] + fn can_donate_to(self, other: Self) -> bool { + other.can_receive_from(self) } - #[test] - fn test_o_neg_donors() { - let mut givers = "O-".parse::().unwrap().donors(); - givers.sort(); - let mut expected: Vec = vec!["O-".parse().unwrap()]; - expected.sort(); - assert_eq!(givers, expected); - } + pub fn can_receive_from(self, other: Self) -> bool { + if !(self.rh_factor == other.rh_factor || self.rh_factor == RhFactor::Positive) { + return false; + } - #[test] - fn test_ab_pos_recipients() { - let mut recipients: Vec = "AB+".parse::().unwrap().recipients(); - recipients.sort(); - let mut expected: Vec = vec!["AB+".parse().unwrap()]; - expected.sort(); - assert_eq!(recipients, expected); + other.antigen == Antigen::O || self.antigen == Antigen::AB || other.antigen == self.antigen } - #[test] - fn test_a_neg_recipients() { - let mut recipients = "A-".parse::().unwrap().recipients(); - recipients.sort(); - let mut expected: Vec = vec![ - "A-".parse().unwrap(), - "AB+".parse().unwrap(), - "A+".parse().unwrap(), - "AB-".parse().unwrap(), - ]; - expected.sort(); - assert_eq!(recipients, expected); + #[inline] + pub fn donors(self) -> Vec { + Self::every() + .filter(|&b| self.can_receive_from(b)) + .collect() } - #[test] - fn test_output() { - let blood_type: BloodType = "O+".parse().unwrap(); - println!("recipients of O+ {:?}", blood_type.recipients()); - println!("donors of O+ {:?}", blood_type.donors()); - let another_blood_type: BloodType = "A-".parse().unwrap(); - println!( - "donors of O+ can receive from {:?} {:?}", - &another_blood_type, - blood_type.can_receive_from(&another_blood_type) - ); + #[inline] + pub fn recipients(self) -> Vec { + Self::every().filter(|&b| self.can_donate_to(b)).collect() } } diff --git a/solutions/commits_stats/Cargo.toml b/solutions/commits_stats/Cargo.toml index 896cb0ca..5557801a 100644 --- a/solutions/commits_stats/Cargo.toml +++ b/solutions/commits_stats/Cargo.toml @@ -7,5 +7,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -json = "0.12" -chrono = "0.4" \ No newline at end of file +json = "0.12.4" +chrono = "0.4.41" diff --git a/solutions/commits_stats/src/lib.rs b/solutions/commits_stats/src/lib.rs index 8429b7f2..23fac41f 100644 --- a/solutions/commits_stats/src/lib.rs +++ b/solutions/commits_stats/src/lib.rs @@ -1,133 +1,28 @@ -// # Instructions: - -// In this exercise you will be provided with a json file with data -// corresponding to git commits in github (extracted using the github -// rest api) your job is to extract the relevant data and place it in -// a struct called `CommitData` to get the following information: - -// 1. Number of commits per author (identified by the github login) -// 2. And the number of commits per author - -// Create two functions: -// fn commits_per_author(data: &Vec) -> HashMap<&str, u32> -// fn commits_per_date(data: &Vec) -> HashMap -// A week is represented by the a year followed by the number of the -// week for example January 1, 2020 is in week 1 of 2020 an will be -// represented by a String with the form "2020-W1" - -// # Notions: -// https://docs.rs/chrono/0.4.19/chrono/#modules -// https://serde.rs/ - -use chrono::prelude::*; -use chrono::IsoWeek; - -#[derive(Debug)] -struct Week(IsoWeek); - -use std::fmt; - -impl fmt::Display for Week { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.0) - } -} - use std::collections::HashMap; -pub fn commits_per_author(data: &json::JsonValue) -> HashMap { - let mut commits_per_author: HashMap = HashMap::new(); - for commit in data.members() { - let count = commits_per_author - .entry(commit["author"]["login"].to_string()) - .or_insert(0); - *count += 1; - } - commits_per_author -} +use chrono::{DateTime, Datelike}; pub fn commits_per_week(data: &json::JsonValue) -> HashMap { - let mut commits_per_week: HashMap = HashMap::new(); - for commit in data.members() { - let count = commits_per_week - .entry( - Week( - DateTime::parse_from_rfc3339(&commit["commit"]["author"]["date"].to_string()) - .unwrap() - .iso_week(), - ) - .to_string(), - ) - .or_insert(0); - *count += 1; - } - commits_per_week + data.members() + .map(|l| l["commit"]["author"]["date"].to_string()) + .fold(HashMap::new(), |mut acc, x| { + acc.entry(format!( + "{:?}", + DateTime::parse_from_rfc3339(x.as_str()).unwrap().iso_week() + )) + .and_modify(|v| *v += 1) + .or_insert(1); + + acc + }) } -#[cfg(test)] -mod tests { - use super::*; - use std::fs; - - fn test_setup() -> json::JsonValue { - let contents = fs::read_to_string("commits.json").unwrap(); - let serialized = json::parse(&contents).unwrap(); - serialized - } - - #[test] - fn test_commits_per_week() { - let serialized = test_setup(); - let commits_per_week = commits_per_week(&serialized); - println!("{:#?}", &commits_per_week); - let date = [ - "2020-W47".to_string(), - "2020-W43".to_string(), - "2020-W36".to_string(), - "2020-W50".to_string(), - "2020-W40".to_string(), - "2020-W44".to_string(), - "2020-W46".to_string(), - "2020-W31".to_string(), - "2020-W45".to_string(), - "2020-W49".to_string(), - ]; - - let mut com_per_week = HashMap::new(); - let commits = [3, 1, 1, 2, 2, 5, 4, 1, 4, 7]; - - for i in 0..date.len() { - com_per_week.insert(date[i].clone(), commits[i].clone()); - } - - assert_eq!(com_per_week, commits_per_week); - } - - #[test] - fn test_commits_per_author() { - let serialized = test_setup(); - let logins = [ - "RPigott", - "RedSoxFan", - "Xyene", - "paul-ri", - "JayceFayne", - "mwenzkowski", - "psnszsn", - "emersion", - "tamirzb", - "ifreund", - "homembaixinho", - ]; - let commits = [1, 1, 7, 2, 1, 3, 1, 10, 1, 1, 2]; - let mut expected = HashMap::new(); - - for i in 0..logins.len() { - expected.insert(logins[i].to_owned(), commits[i].to_owned()); - } +pub fn commits_per_author(data: &json::JsonValue) -> HashMap { + data.members() + .map(|l| l["author"]["login"].to_string()) + .fold(HashMap::new(), |mut acc, x| { + acc.entry(x).and_modify(|v| *v += 1).or_insert(1); - let commits_per_author = commits_per_author(&serialized); - println!("{:#?}", &commits_per_author); - assert_eq!(expected, commits_per_author); - } + acc + }) } diff --git a/solutions/easy_traits/src/lib.rs b/solutions/easy_traits/src/lib.rs index 0b101278..b41451ac 100644 --- a/solutions/easy_traits/src/lib.rs +++ b/solutions/easy_traits/src/lib.rs @@ -1,137 +1,30 @@ -/* -## easy_traits +pub trait AppendStrExt { + fn append_str(&mut self, str_to_append: &str) -> &mut Self; -### Instructions + fn append_number(&mut self, nb_to_append: f64) -> &mut Self; -Your task is to implement the trait `AppendStr` for the type StringValue. - -The trait `AppendStr` has the following functions: - -- `append_str`, that appends to the value of the structure a new_str of type String -- `append_number`, that appends to the value of the structure a nb_to_append of type f64 -- `remove_punctuation_marks`, that removes from the value of the structure the following punctuation marks `. , ? !` - - -### Expected Function - -```rust -#[derive(Clone)] -struct StringValue { - value: String, -} - -trait AppendStr { - fn append_str(self, str_to_append: String) -> Self; - - fn append_number(self, nb_to_append: f64) -> Self; - - fn remove_punctuation_marks(self) -> Self; + fn remove_punctuation_marks(&mut self) -> &mut Self; } -impl AppendStr for StringValue { - } -``` -*/ +impl AppendStrExt for String { + #[inline] + fn append_str(&mut self, str_to_append: &str) -> &mut Self { + self.push_str(str_to_append); -#[derive(Clone, Debug, PartialEq)] -pub struct StringValue { - pub value: String, -} - -pub trait AppendStr { - fn append_str(&mut self, str_to_append: String) -> Self; - - fn append_number(&mut self, nb_to_append: f64) -> Self; - - fn remove_punctuation_marks(&mut self) -> Self; -} - -impl AppendStr for StringValue { - fn append_str(&mut self, str_to_append: String) -> Self { - self.value.push_str(&str_to_append); - self.clone() + self } - fn append_number(&mut self, nb_to_append: f64) -> Self { - self.value = format!("{}{nb_to_append}", self.value); + #[inline] + fn append_number(&mut self, nb_to_append: f64) -> &mut Self { + self.push_str(nb_to_append.to_string().as_str()); - self.clone() + self } - fn remove_punctuation_marks(&mut self) -> Self { - let mut str_to_append = String::from(""); - let chars: Vec = self.value.chars().collect(); - for i in chars { - if i != '!' && i != '.' && i != ',' && i != '?' { - str_to_append.push(i); - } - } - - self.value = str_to_append; - - self.clone() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_append_str() { - let mut str_aux = StringValue { - value: String::from("hello"), - }; - - assert_eq!( - String::from("hello there!"), - str_aux.append_str(String::from(" there!")).value - ); - - assert_eq!( - String::from("hello there! How are You?"), - str_aux.append_str(String::from(" How are You?")).value - ); - - assert_eq!( - String::from("hello there How are You"), - str_aux.remove_punctuation_marks().value - ); - } - - #[test] - fn test_remove_punctuation() { - let mut str_aux = StringValue { - value: String::from("!?.,!?.,"), - }; - - assert_eq!(String::from(""), str_aux.remove_punctuation_marks().value); - - assert_eq!( - String::from("h!e!l?lo. the,.re!"), - str_aux.append_str(String::from("h!e!l?lo. the,.re!")).value - ); - assert_eq!( - String::from("hello there"), - str_aux.remove_punctuation_marks().value - ); - } - - #[test] - fn test_append_number() { - let mut str_aux = StringValue { - value: String::from(""), - }; - - assert_eq!(String::from("-1"), str_aux.append_number(-1.0).value); - - assert_eq!(String::from("-15"), str_aux.append_number(5.0).value); - - assert_eq!(String::from("-155.5"), str_aux.append_number(5.5).value); + #[inline] + fn remove_punctuation_marks(&mut self) -> &mut Self { + self.retain(|c| !matches!(c, '.' | ',' | '?' | '!')); - assert_eq!( - String::from("-1555"), - str_aux.remove_punctuation_marks().value - ); + self } } diff --git a/solutions/easy_traits/src/main.rs b/solutions/easy_traits/src/main.rs deleted file mode 100644 index 8b137891..00000000 --- a/solutions/easy_traits/src/main.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/solutions/generics/src/lib.rs b/solutions/generics/src/lib.rs index eae87532..91e0bbe8 100644 --- a/solutions/generics/src/lib.rs +++ b/solutions/generics/src/lib.rs @@ -1,43 +1,4 @@ -// Write a functions called identity that calculates the identity of a -// value (receives any data type and returns the same value) - -// fn main() { -// println!("Hello, world!"); -// println!("{}", identity(3)); -// } - +#[inline] pub fn identity(v: T) -> T { v } - -#[cfg(test)] -mod test { - use super::*; - - #[derive(PartialEq, Debug)] - struct Point { - x: i32, - y: i32, - } - - #[test] - fn test_with_int() { - assert_eq!(identity(3), 3); - } - - #[test] - fn test_with_float() { - assert_eq!(identity(1.0), 1.0); - } - - #[test] - fn test_with_str() { - assert_eq!(identity("you"), "you"); - } - - #[test] - fn test_with_struct() { - let s = Point { x: 1, y: 2 }; - assert_eq!(identity(&s), &s); - } -} diff --git a/solutions/generics_list/src/lib.rs b/solutions/generics_list/src/lib.rs index 8fb5bec1..ed896fbd 100644 --- a/solutions/generics_list/src/lib.rs +++ b/solutions/generics_list/src/lib.rs @@ -1,51 +1,3 @@ -/* -## generics_list - -### Instructions - -Create a linked list of generic values with the following methods. - -- `new` which returns a new empty list. - -- `push` which adds at the begining of the list a new element. - -- `pop` which deletes the last added element to the list. - -- `len` which returns size of the list. - - - -### Expected Functions - -```rust -#[derive(Clone)] -pub struct List { - pub head: Option>, -} - -#[derive(Clone)] -pub struct Node { - pub value: T, - pub next: Option>>, -} - -impl List { - pub fn new() -> List { - } - - pub fn push(&mut self, value: T) { - } - - pub fn pop(&mut self) { - } - - pub fn len(&self) -> usize { - } -} -``` - -*/ - #[derive(Clone, Debug)] pub struct List { pub head: Option>, @@ -58,110 +10,37 @@ pub struct Node { } impl List { - pub fn new() -> List { - List { head: None } + #[inline] + pub fn new() -> Self { + Self { + head: Default::default(), + } } pub fn push(&mut self, value: T) { - let mut new_node = Node { next: None, value }; + let mut new_node = Node { + next: Default::default(), + value, + }; - match self.head { + match self.head.take() { None => self.head = Some(new_node), - Some(_) => { - let current_head = self.head.take().unwrap(); + Some(current_head) => { new_node.next = Some(Box::new(current_head)); self.head = Some(new_node); } } } + #[inline] pub fn pop(&mut self) { self.head .take() - .map(|head| self.head = head.next.map(|node| *node)); + .map(|head| self.head = head.next.map(|h| *h)); } + #[inline] pub fn len(&self) -> usize { - let mut count = 0; - let mut current_node = self.head.as_ref(); - while let Some(node) = current_node { - count = count + 1; - current_node = node.next.as_ref().map(|node| &**node) - } - count - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn new_list_test() { - let mut new_list_str = List::new(); - new_list_str.push("String Test"); - - let mut new_list_num = List::new(); - new_list_num.push(5); - - assert_eq!(new_list_str.head.unwrap().value, "String Test"); - assert_eq!(new_list_num.head.unwrap().value, 5); - } - - #[test] - fn big_list_test() { - let mut new_list_nbr = List::new(); - - for i in 0..10 { - new_list_nbr.push(i); - } - - let mut aux = new_list_nbr.head.unwrap(); - for i in (1..10).collect::>().iter().rev() { - assert_eq!(aux.value, *i); - aux = *aux.next.unwrap(); - } - } - - #[test] - fn remove_test() { - let mut new_list_nbr = List::new(); - - for i in 0..10 { - new_list_nbr.push(i); - } - - assert_eq!(new_list_nbr.len(), 10); - - for _ in 0..5 { - new_list_nbr.pop(); - } - - assert_eq!(new_list_nbr.len(), 5); - - let mut aux = new_list_nbr.clone().head.unwrap(); - for i in (1..5).collect::>().iter().rev() { - assert_eq!(aux.value, *i); - aux = *aux.next.unwrap(); - } - - for _ in 0..5 { - assert_eq!(new_list_nbr.head.as_ref().is_none(), false); - new_list_nbr.pop(); - } - - assert_eq!(new_list_nbr.head.as_ref().is_none(), true); - } - - #[test] - fn len_test() { - let mut new_list_nbr = List::new(); - - assert_eq!(new_list_nbr.len(), 0); - - for i in 0..10 { - new_list_nbr.push(i); - assert_eq!(new_list_nbr.len(), i + 1); - } + std::iter::successors(self.head.as_ref(), |node| node.next.as_deref()).count() } } diff --git a/solutions/lalgebra_scalar/src/lib.rs b/solutions/lalgebra_scalar/src/lib.rs index 199be495..635c4243 100644 --- a/solutions/lalgebra_scalar/src/lib.rs +++ b/solutions/lalgebra_scalar/src/lib.rs @@ -1,137 +1,92 @@ -// # Instructions -// A scalar type must implement the operations -// Addition, Subtraction, Multiplication and Division (you might -// also have to use more restrictions). For this use a trait -// inheritance (supertraits) - -// Another condition for a number to be a scalar is to have a zero -// (neutral element in the addition) and a one (neutral element in the -// multiplication). Therefore the Scalar trait will require 2 -// functions zero() and one() - -// After finishing implement the Scalar trait for u32, u64, i32, i64, -// f32, f64 - use std::ops::{Add, Div, Mul, Sub}; -pub trait Scalar: Add + Div + Mul + Sub + std::marker::Sized + Clone { +pub trait Scalar: Sized + Add + Sub + Mul + Div { type Item; + fn zero() -> Self::Item; fn one() -> Self::Item; } impl Scalar for u32 { type Item = u32; + + #[inline] fn zero() -> Self::Item { - 0 as u32 + 0 } + + #[inline] fn one() -> Self::Item { - 1 as u32 + 1 } } impl Scalar for u64 { type Item = u64; + + #[inline] fn zero() -> Self::Item { - 0 as u64 + 0 } + + #[inline] fn one() -> Self::Item { - 1 as u64 + 1 } } impl Scalar for i32 { type Item = i32; + + #[inline] fn zero() -> Self::Item { - 0 as i32 + 0 } + + #[inline] fn one() -> Self::Item { - 1 as i32 + 1 } } impl Scalar for i64 { type Item = i64; + + #[inline] fn zero() -> Self::Item { - 0 as i64 + 0 } + + #[inline] fn one() -> Self::Item { - 1 as i64 + 1 } } impl Scalar for f32 { type Item = f32; + + #[inline] fn zero() -> Self::Item { - 0.0 + 0. } + + #[inline] fn one() -> Self::Item { - 1.0 + 1. } } impl Scalar for f64 { type Item = f64; - fn zero() -> Self::Item { - 0.0 - } - fn one() -> Self::Item { - 1.0 - } -} -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn scalar_u32() { - let a: u32 = u32::zero(); - assert_eq!(a, 0 as u32); - - let b = u32::one(); - assert_eq!(b, 1 as u32); - } - - #[test] - fn scalar_u64() { - let a = u64::zero(); - assert_eq!(a, 0 as u64); - - let b = u64::one(); - assert_eq!(b, 1 as u64); - } - #[test] - fn scalar_i32() { - let a: i32 = i32::zero(); - assert_eq!(a, 0 as i32); - - let b = i32::one(); - assert_eq!(b, 1 as i32); - } - - #[test] - fn scalar_i64() { - let a: i64 = i64::zero(); - assert_eq!(a, 0 as i64); - - let b = i64::one(); - assert_eq!(b, 1 as i64); - } - - #[test] - fn scalar_f32() { - let zero = f32::zero(); - assert_eq!(zero, 0.0); - let one = f32::one(); - assert_eq!(one, 1.0); + #[inline] + fn zero() -> Self::Item { + 0. } - #[test] - fn scalar_f64() { - let zero = f64::zero(); - assert_eq!(zero, 0.0); - let one = f64::one(); - assert_eq!(one, 1.0); + #[inline] + fn one() -> Self::Item { + 1. } } diff --git a/solutions/lalgebra_vector/src/lib.rs b/solutions/lalgebra_vector/src/lib.rs index 0f0e1b33..12ba2b6c 100644 --- a/solutions/lalgebra_vector/src/lib.rs +++ b/solutions/lalgebra_vector/src/lib.rs @@ -1,71 +1,35 @@ -// A vector in linear algebra is define as "anything that can be added -// and that can be multiplied by a scalar" -// And the associated function dot that calculates the dot product -// between two vectors -// let vector = Vector(vec![0,3, 4]); -// let vector_1 = Vector(vec![0,3,3]); -// vector.dot(&vector_1) == Some(23); - -// The dot product between two vectors of different length it's not defined +use std::{ + iter::Sum, + ops::{Add, Mul}, +}; use lalgebra_scalar::Scalar; -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Vector>(pub Vec); - -use std::ops::Add; +#[derive(Debug, PartialEq)] +pub struct Vector(pub Vec); -impl + Add> Add for Vector { +impl> Add for Vector { type Output = Option; - fn add(self, other: Self) -> Self::Output { - if self.0.len() != other.0.len() { + + fn add(self, rhs: Self) -> Self::Output { + if self.0.len() != rhs.0.len() { return None; } - let result: Vector = Vector( - self.0 - .iter() - .zip(other.0.iter()) - .map(|(x, y)| x.clone() + y.clone()) - .collect(), - ); - Some(result) + Some(Vector( + self.0.into_iter().zip(rhs.0).map(|(l, r)| l + r).collect(), + )) } } -impl + std::iter::Sum<::Output>> Vector { - pub fn new() -> Self { - Vector(Vec::new()) - } - - pub fn dot(&self, other: &Self) -> Option { - if self.0.len() != other.0.len() { +impl::Output>> Vector { + pub fn dot(self, rhs: Self) -> Option { + if self.0.len() != rhs.0.len() { return None; } - let result = self - .0 - .iter() - .zip(other.0.iter()) - .map(|(x, y)| x.clone() * y.clone()) - .sum(); - Some(result) - } -} + let result = self.0.into_iter().zip(rhs.0).map(|(x, y)| x * y).sum(); -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn dot_product() { - let vector_1: Vector = Vector(vec![1, 3, -5]); - let vector_2: Vector = Vector(vec![4, -2, -1]); - let expected: i64 = 3; - assert_eq!(vector_1.dot(&vector_2), Some(expected)); - - let vector_1: Vector = Vector(vec![1, 3, -5]); - let vector_2: Vector = Vector(vec![4, -2]); - assert_eq!(vector_1.dot(&vector_2), None); + Some(result) } } diff --git a/solutions/minesweeper/src/lib.rs b/solutions/minesweeper/src/lib.rs index 2a49e2c2..b38f65b5 100644 --- a/solutions/minesweeper/src/lib.rs +++ b/solutions/minesweeper/src/lib.rs @@ -1,56 +1,48 @@ -const OFFSET: [(i32, i32); 8] = [ +const VECTORS: [(isize, isize); 8] = [ (-1, -1), - (0, -1), - (1, -1), (-1, 0), - (1, 0), (-1, 1), + (0, -1), (0, 1), + (1, -1), + (1, 0), (1, 1), ]; pub fn solve_board(minefield: &[&str]) -> Vec { - let mut field: Vec> = minefield + let mut copy = minefield .iter() - .map(|line| line.as_bytes().to_owned()) - .collect(); - - let x_max = field.first().unwrap_or(&vec![]).len(); - let y_max = field.len(); + .map(|c| c.as_bytes().to_owned()) + .collect::>(); - minefield.iter().enumerate().for_each(|(y, line)| { - line.as_bytes() - .iter() - .enumerate() - .filter(|(_, &c)| c == b'*') - .for_each(|(x, _)| { - OFFSET - .iter() - .filter(|(x_off, y_off)| { - !(*x_off == -1 && x == 0) - && *x_off + (x as i32) < x_max as i32 - && !(*y_off == -1 && y == 0) - && *y_off + (y as i32) < y_max as i32 - }) - .map(|&(x_off, y_off)| { - (((x as i32) + x_off) as usize, ((y as i32) + y_off) as usize) - }) - .for_each(|(x, y)| { - let curr_val = field[y][x]; - - if curr_val != b'*' { - if curr_val == b' ' { - field[y][x] = b'1'; + minefield + .iter() + .enumerate() + .flat_map(|(y, l)| l.chars().enumerate().map(move |(x, c)| ((y, x), c))) + .filter(|&(_, c)| c == '*') + .for_each(|(p, _)| { + VECTORS + .into_iter() + .filter_map(|v| { + Some(( + usize::try_from(p.0 as isize + v.0).ok()?, + usize::try_from(p.1 as isize + v.1).ok()?, + )) + }) + .for_each(|(y, x)| { + if let Some(c) = copy.get_mut(y).and_then(|y| y.get_mut(x)) { + if *c != b'*' { + if *c == b' ' { + *c = b'1'; } else { - field[y][x] = curr_val + 1; + *c += 1; } } - }) - }) - }); + } + }) + }); - field - .into_iter() - .map(|line| unsafe { String::from_utf8_unchecked(line) }) + copy.into_iter() + .map(|v| String::from_utf8(v).unwrap()) .collect() } diff --git a/solutions/roman_numbers/src/iterator.rs b/solutions/roman_numbers/src/iterator.rs deleted file mode 100644 index e43effce..00000000 --- a/solutions/roman_numbers/src/iterator.rs +++ /dev/null @@ -1,107 +0,0 @@ -// # Instructions -// Implement the IntoIterator trait for the `RomanNumber` type to -// enable using a for loop notation. -// This implementation must allow taking ownership, -// borrowing and borrowing mutably - -// I.e. this three constructions must be possible -// ```rust -// let number = RomanNumber::from(23); - -// 1. Taking ownership (this consumes the RomanNumber) -// for digit in number { -// ... -// } - -// 2. Borrowing immutably (this preserves the RomanNumber) -// for digit in &number { - -// } - -// 3. Borrowing mutably (this allow you to modify the RomanNumber -// without having to return the ownership) -// for digit in &mut number { - -// } - -// Start with your research See https://doc.rust-lang.org/std/iter/trait.IntoIterator.html -// https://doc.rust-lang.org/std/iter/index.html - -use crate::{RomanDigit, RomanNumber}; - -impl<'a> IntoIterator for &'a RomanNumber { - type Item = &'a RomanDigit; - type IntoIter = std::slice::Iter<'a, RomanDigit>; - - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } -} - -impl<'a> IntoIterator for &'a mut RomanNumber { - type Item = &'a mut RomanDigit; - type IntoIter = std::slice::IterMut<'a, RomanDigit>; - - fn into_iter(self) -> Self::IntoIter { - self.0.iter_mut() - } -} - -impl IntoIterator for RomanNumber { - type Item = RomanDigit; - type IntoIter = std::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -#[cfg(test)] -mod test { - use super::*; - - fn into_u32(n: RomanDigit) -> u32 { - use RomanDigit::*; - match n { - Nulla => 0, - I => 1, - V => 5, - X => 10, - L => 50, - C => 100, - D => 500, - M => 1000, - } - } - - #[test] - fn test_iter() { - let number = RomanNumber::from(15); - - for digit in &number { - println!("{:?}", digit); - } - println!("{:?}", number); - } - - #[test] - fn test_into_iter() { - let number = RomanNumber::from(37); - let value: u32 = number.into_iter().map(|digit| into_u32(digit)).sum(); - println!("value: {}", value); - } - - #[test] - fn test_iter_mut() { - let mut number = RomanNumber::from(22); - - for digit in &mut number { - let value = into_u32(*digit); - *digit = dbg!(RomanNumber::from(value - 1)).0[0]; - } - println!( - "Roman Number after increasing the each digit by 1 = {:?}", - number - ); - } -} diff --git a/solutions/roman_numbers/src/lib.rs b/solutions/roman_numbers/src/lib.rs index 0e94ad8c..0ad8014a 100644 --- a/solutions/roman_numbers/src/lib.rs +++ b/solutions/roman_numbers/src/lib.rs @@ -1,113 +1,79 @@ -// # Instructions -// Implement the From Trait to create a roman number from a u32 -// the roman number should be in subtractive notation (the common way to write roman -// number I, II, II, IV, V, VI, VII, VIII, IX, X ...) - -// For this start by defining the digits as `RomanDigit` with the values -// I, V, X, L, C, D, M and Nulla for 0 - -// Next define RomanNumber as a wrapper to a vector of RomanDigit's -// And implement the Trait From - -// Examples: -// RomanNumber::from(32) = [X,X,X,I,I] -// RomanNumber::from(9) = [I,X] -// RomanNumber::from(45) = [X,L,V] -// RomanNumber:;from(0) = [Nulla] - -mod iterator; -use crate::RomanDigit::*; +use std::iter; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum RomanDigit { - Nulla, - I, - V, - X, - L, - C, - D, - M, + Nulla = 0, + I = 1, + V = 5, + X = 10, + L = 50, + C = 100, + D = 500, + M = 1000, } -impl From for RomanDigit { - fn from(n: u32) -> Self { - match n { - 1..=4 => I, - 5..=9 => V, - 10..=49 => X, - 50..=99 => L, - 100..=499 => C, - 500..=999 => D, - 1000..=5000 => M, - _ => Nulla, - } - } -} - -#[derive(Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct RomanNumber(pub Vec); -impl From for RomanNumber { - fn from(n: u32) -> Self { - if n == 0 { - return RomanNumber(vec![Nulla]); +impl RomanDigit { + const fn base(value: u32) -> Self { + use RomanDigit::*; + + if value >= M as u32 { + M + } else if value >= D as u32 { + D + } else if value >= C as u32 { + C + } else if value >= L as u32 { + L + } else if value >= X as u32 { + X + } else if value >= V as u32 { + V + } else if value >= I as u32 { + I + } else { + Nulla } + } - let mut quotient = n; - let mut p = 0; - let mut reverse_roman = Vec::new(); + fn take(value: &mut u32) -> Vec { + let digits = value.checked_ilog10().unwrap_or_default() + 1; - while quotient != 0 { - let rest = quotient % 10; - quotient /= 10; - p += 1; - if rest == 9 { - reverse_roman.push(RomanDigit::from(10_u32.pow(p))); - reverse_roman.push(RomanDigit::from(10_u32.pow(p - 1))); - } else if rest == 4 { - reverse_roman.push(RomanDigit::from(10_u32.pow(p) / 2)); - reverse_roman.push(RomanDigit::from(10_u32.pow(p - 1))); - } else if rest >= 5 { - let repetitions = rest - 5; - for _ in 0..repetitions { - reverse_roman.push(RomanDigit::from(10_u32.pow(p - 1))); - } - reverse_roman.push(RomanDigit::from(10_u32.pow(p) / 2)); - } else { - for _ in 0..rest { - reverse_roman.push(RomanDigit::from(10_u32.pow(p - 1))) - } - } - } + let d = *value / 10u32.pow(digits - 1); - reverse_roman.reverse(); - RomanNumber(reverse_roman) + let ret = if (d + 1) % 5 == 0 { + let v = Self::base(((d + 1) / 5) * 10u32.pow(digits - 1)); + *value -= d * 10u32.pow(digits - 1); + vec![v, Self::base((d + 1) * 10u32.pow(digits - 1))] + } else { + let v = Self::base(*value); + *value -= v as u32; + vec![v] + }; + + ret } } -#[cfg(test)] -mod tests { - use super::*; +impl From for RomanNumber { + fn from(value: u32) -> Self { + if value == 0 { + return Self(vec![RomanDigit::Nulla]); + } + + let mut acc = value; - #[test] - fn it_works() { - assert_eq!(RomanNumber::from(3).0, [I, I, I]); - assert_eq!(RomanNumber::from(6).0, [V, I]); - assert_eq!(RomanNumber::from(15).0, [X, V]); - assert_eq!(RomanNumber::from(30).0, [X, X, X]); - assert_eq!(RomanNumber::from(150).0, [C, L]); - assert_eq!(RomanNumber::from(200).0, [C, C]); - assert_eq!(RomanNumber::from(600).0, [D, C]); - assert_eq!(RomanNumber::from(1500).0, [M, D]); - } + let it = iter::from_fn(|| { + if acc == 0 { + None + } else { + Some(RomanDigit::take(&mut acc)) + } + }) + .flatten(); - #[test] - fn substractive_notation() { - assert_eq!(RomanNumber::from(4).0, [I, V]); - assert_eq!(RomanNumber::from(44).0, [X, L, I, V]); - assert_eq!(RomanNumber::from(3446).0, [M, M, M, C, D, X, L, V, I]); - assert_eq!(RomanNumber::from(9).0, [I, X]); - assert_eq!(RomanNumber::from(94).0, [X, C, I, V]); + Self(it.collect()) } } diff --git a/solutions/traits/src/lib.rs b/solutions/traits/src/lib.rs index 9c98ae24..6cf1134a 100644 --- a/solutions/traits/src/lib.rs +++ b/solutions/traits/src/lib.rs @@ -1,63 +1,21 @@ -// Imagine you are designing a new video game and you have to create -// food that they players can take to gain strength there are two -// types of food for now fruits and meet: fruits increases the -// strengths by 1 unit and meat increases it by 3 unit. +use std::fmt; -// Define both structures fruits and meat -// Define the std::fmt::Display trait of the Player structure so using -// the template {} inside a println! macro will print in the first -// line the name of the player -// in the second line the strength, score and the money -// and in the third line the weapons #[derive(Debug)] -pub struct Player { - pub name: String, +pub struct Player<'a> { + pub name: &'a str, pub strength: f64, - pub score: i32, - pub money: i32, - pub weapons: Vec, -} - -pub struct Fruit { - pub weight_in_kg: f64, -} - -pub struct Meat { - pub weight_in_kg: f64, - pub fat_content: f64, + pub score: u32, + pub money: u32, + pub weapons: Vec<&'a str>, } -// fn main() { -// let apple = Fruit { weight_in_kg: 1.0 }; -// assert_eq!(apple.gives(), 4); -// let steak = Meat { -// weight_in_kg: 1.0, -// fat_content: 1.0, -// }; - -// let mut player1 = Player { -// name: String::from("player1"), -// strength: 1, -// score: 0, -// money: 0, -// weapons: vec![String::from("knife")], -// }; -// println!("Before eating {:?}", player1); -// player1.eat(apple); -// println!("After eating an apple\n{:?}", player1); -// player1.eat(steak); -// println!("After eating a steak\n{:?}", player1); -// } - -impl Player { - pub fn eat(&mut self, food: T) { +impl Player<'_> { + pub fn eat(&mut self, food: impl Food) { self.strength += food.gives(); } } -use std::fmt; - -impl fmt::Display for Player { +impl fmt::Display for Player<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "{}", self.name)?; writeln!( @@ -75,78 +33,31 @@ pub trait Food { impl Food for Fruit { fn gives(&self) -> f64 { - self.weight_in_kg * 4.0 + self.weight_in_kg * Self::STRENGTH_PER_KG } } impl Food for Meat { fn gives(&self) -> f64 { - self.weight_in_kg * 4.0 + self.weight_in_kg * self.fat_content * 5.0 + (((1. - self.fat_content) * self.weight_in_kg) * Self::STRENGTH_PER_PROTEIN_KG) + + ((self.fat_content * self.weight_in_kg) * Self::STRENGTH_PER_FAT_KG) } } -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_gives() { - let apple = Fruit { weight_in_kg: 1.0 }; - assert_eq!(apple.gives(), 4.0); - let steak = Meat { - weight_in_kg: 1.0, - fat_content: 1.0, - }; - assert_eq!(steak.gives(), 9.0); - - let steak = Meat { - weight_in_kg: 1.0, - fat_content: 0.0, - }; - assert_eq!(steak.gives(), 4.0); - - let steak = Meat { - weight_in_kg: 1.5, - fat_content: 0.3, - }; - assert_eq!(steak.gives(), 8.25); - } +pub struct Fruit { + pub weight_in_kg: f64, +} - #[test] - fn test_eat() { - let apple = Fruit { weight_in_kg: 1.0 }; - assert_eq!(apple.gives(), 4.0); - let steak = Meat { - weight_in_kg: 1.0, - fat_content: 1.0, - }; +impl Fruit { + const STRENGTH_PER_KG: f64 = 4.; +} - let mut player1 = Player { - name: String::from("player1"), - strength: 1.0, - score: 0, - money: 0, - weapons: vec![String::from("knife"), String::from("shotgun")], - }; - player1.eat(apple); - assert_eq!(player1.strength, 5.0); - player1.eat(steak); - assert_eq!(player1.strength, 14.0); - } +pub struct Meat { + pub weight_in_kg: f64, + pub fat_content: f64, +} - #[test] - fn test_display() { - let player1 = Player { - name: String::from("player1"), - strength: 1.0, - score: 0, - money: 0, - weapons: vec![String::from("knife"), String::from("shotgun")], - }; - println!("{}", player1); - assert_eq!( - player1.to_string(), - "player1\nStrength: 1, Score: 0, Money: 0\nWeapons: [\"knife\", \"shotgun\"]" - ) - } +impl Meat { + const STRENGTH_PER_PROTEIN_KG: f64 = 4.; + const STRENGTH_PER_FAT_KG: f64 = 9.; } diff --git a/solutions/vector_operations/src/lib.rs b/solutions/vector_operations/src/lib.rs index e42995e7..91b89bc1 100644 --- a/solutions/vector_operations/src/lib.rs +++ b/solutions/vector_operations/src/lib.rs @@ -1,13 +1,4 @@ -// Define the structures ThreeDvector that represents a 3 dimensional -// vector in (for convention in physics the vector are represented as -// ai + bj + ck where a, b, and c are real numbers and i, j and k -// represent the direction x,y and z respectively in the Cartesian plane -// there for we use the names i, j and k for the fields in the -// ThreeDVector structure - -// Look how the operations Addition and Subtraction work for a 3 -// dimensional vector and implement them by implementing the -// std::ops::Add and std::ops::Sub traits +use std::ops::{Add, Sub}; #[derive(Debug, Copy, Clone, PartialEq)] pub struct ThreeDVector { @@ -16,16 +7,15 @@ pub struct ThreeDVector { pub k: T, } -use std::ops::{Add, Sub}; - impl> Add for ThreeDVector { type Output = Self; - fn add(self, other: Self) -> Self { + #[inline] + fn add(self, rhs: Self) -> Self::Output { Self { - i: self.i + other.i, - j: self.j + other.j, - k: self.k + other.k, + i: self.i + rhs.i, + j: self.j + rhs.j, + k: self.k + rhs.k, } } } @@ -33,37 +23,12 @@ impl> Add for ThreeDVector { impl> Sub for ThreeDVector { type Output = Self; - fn sub(self, other: Self) -> Self { + #[inline] + fn sub(self, rhs: Self) -> Self::Output { Self { - i: self.i - other.i, - j: self.j - other.j, - k: self.k - other.k, + i: self.i - rhs.i, + j: self.j - rhs.j, + k: self.k - rhs.k, } } } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } - - #[test] - fn test_addition() { - let a = ThreeDVector { i: 3, j: 5, k: 2 }; - let b = ThreeDVector { i: 2, j: 7, k: 4 }; - let a_plus_b = ThreeDVector { i: 5, j: 12, k: 6 }; - assert_eq!(a + b, a_plus_b); - } - - #[test] - fn test_subtraction() { - let a = ThreeDVector { i: 3, j: 5, k: 2 }; - let b = ThreeDVector { i: 2, j: 7, k: 4 }; - let a_minus_b = ThreeDVector { i: 1, j: -2, k: -2 }; - assert_eq!(a - b, a_minus_b); - } -} diff --git a/tests/blood_types_test/src/lib.rs b/tests/blood_types_test/src/lib.rs new file mode 100644 index 00000000..faebac10 --- /dev/null +++ b/tests/blood_types_test/src/lib.rs @@ -0,0 +1,126 @@ +use blood_types::*; + +use std::{collections::HashMap, hash::Hash}; + +fn slices_eq_unordered(a: &[T], b: &[T]) -> bool { + let count_elems = |arr| { + let mut map = HashMap::new(); + for item in arr { + *map.entry(item).or_insert(0) += 1; + } + map + }; + + count_elems(a) == count_elems(b) +} + +#[test] +fn test_unexistent_blood_type() { + assert!("AO-".parse::().is_err()); +} + +#[test] +fn check_blood_type_relationships() { + let relationships = [ + ("AB-", "A+", false), + ("A-", "A+", false), + ("AB-", "A-", true), + ("AB-", "O+", false), + ("AB+", "O+", true), + ("AB-", "O-", true), + ]; + + relationships + .into_iter() + .map(|(t1, t2, e)| { + ( + t1.parse::().unwrap(), + t2.parse::().unwrap(), + e, + ) + }) + .for_each(|(t1, t2, e)| assert_eq!(t1.can_receive_from(t2), e)); +} + +#[test] +fn test_ab_plus_from_str() { + assert!(matches!( + "AB+".parse().unwrap(), + BloodType { + antigen: Antigen::AB, + rh_factor: RhFactor::Positive + } + )); +} + +#[test] +fn test_a_negative_from_str() { + assert!(matches!( + "A-".parse().unwrap(), + BloodType { + antigen: Antigen::A, + rh_factor: RhFactor::Negative + } + )); +} + +#[test] +fn test_ab_plus_donors() { + let donors = "AB+".parse::().unwrap().donors(); + let expected = + ["AB-", "A-", "B-", "O-", "AB+", "A+", "B+", "O+"].map(|s| s.parse::().unwrap()); + assert!(slices_eq_unordered(&donors, &expected)); +} + +#[test] +fn test_a_neg_donors() { + let donors = "A-".parse::().unwrap().donors(); + let expected = ["A-", "O-"].map(|s| s.parse::().unwrap()); + assert!(slices_eq_unordered(&donors, &expected)); +} + +#[test] +fn test_o_neg_donors() { + let donors = "O-".parse::().unwrap().donors(); + let expected = ["O-"].map(|s| s.parse::().unwrap()); + assert!(slices_eq_unordered(&donors, &expected)); +} + +#[test] +fn test_ab_pos_recipients() { + let recipients = "AB+".parse::().unwrap().recipients(); + let expected = ["AB+"].map(|s| s.parse::().unwrap()); + assert!(slices_eq_unordered(&recipients, &expected)); +} + +#[test] +fn test_a_neg_recipients() { + let recipients = "A-".parse::().unwrap().recipients(); + let expected = ["A-", "AB+", "A+", "AB-"].map(|s| s.parse::().unwrap()); + assert!(slices_eq_unordered(&recipients, &expected)); +} + +#[test] +fn test_debug_impl() { + assert_eq!( + format!( + "{:?}", + BloodType { + antigen: Antigen::AB, + rh_factor: RhFactor::Positive, + } + ), + "AB+" + ); + + assert_eq!( + format!( + "{:?}", + BloodType { + antigen: Antigen::A, + rh_factor: RhFactor::Negative, + } + ), + "A-" + ); +} diff --git a/tests/blood_types_test/src/main.rs b/tests/blood_types_test/src/main.rs deleted file mode 100644 index f86d594e..00000000 --- a/tests/blood_types_test/src/main.rs +++ /dev/null @@ -1,187 +0,0 @@ -// In this exercise you will create a model of and gives an API to -// deal with blood types - -// Start creating the data representation of the blood types -// Create the enumerator `Antigen` that has 4 possibilities: A, B, O and AB -// And the enumerator `RhFactor` that has two possible values: Positive -// and Negative - -// After, create the struct BloodType that contains two fields with the -// names antigen and rh_factor - -// To provide a simple way to create blood types implement the trait -// FromStr for BloodType (which will allow us to use the `parse` -// method and the associated function from_str, so we can do: -// ```rust -// let a_neg: BloodType = "A-".parse(); -// ``` -//) - -// Implement the std::cmp::Ord trait to make possible to sort a vector -// or array of BloodType's - -// Implement the trait std::Debug for BloodType allowing to print a -// vector such as [BloodType { antigen: A, rh_factor: Positive}, -// BloodType{ antigen: B, rh_factor: Negative}] as [ A+, A-] using the -// formatting {:?} - -// Write three methods for BloodType: -// - can_receive_from(&self, other: BloodType) -> bool {}: which -// returns true if self can receive blood from `other` blood type -// - donors(&self) -> Vec: which returns -// all the blood types that can give blood to self -// - recipients(&self) -> Vec: which returns all the blood -// types that can receive blood from self - -#[allow(unused_imports)] -use blood_types::{Antigen, BloodType, RhFactor}; - -fn main() { - let blood_type: BloodType = "O+".parse().unwrap(); - println!("recipients of O+ {:?}", blood_type.recipients()); - println!("donors of O+ {:?}", blood_type.donors()); - let another_blood_type: BloodType = "A-".parse().unwrap(); - println!( - "donors of O+ can receive from {:?} {:?}", - &another_blood_type, - blood_type.can_receive_from(&another_blood_type) - ); -} - -#[test] -fn compatible_ab_neg_with_a_pos() { - let blood_type: BloodType = "AB-".parse().unwrap(); - let other_bt: BloodType = "A+".parse().unwrap(); - assert!(!blood_type.can_receive_from(&other_bt)); -} - -#[test] -fn compatible_a_neg_with_a_pos() { - let blood_type: BloodType = "A-".parse().unwrap(); - let other_bt: BloodType = "A+".parse().unwrap(); - assert!(!blood_type.can_receive_from(&other_bt)); -} - -#[test] -fn compatible_a_neg_with_ab_neg() { - let blood_type: BloodType = "AB-".parse().unwrap(); - let other_bt: BloodType = "A-".parse().unwrap(); - assert!(blood_type.can_receive_from(&other_bt)); -} - -#[test] -fn compatible_ab_neg_with_o_pos() { - let blood_type: BloodType = "AB-".parse().unwrap(); - let other_bt: BloodType = "O+".parse().unwrap(); - assert!(!blood_type.can_receive_from(&other_bt)); -} - -#[test] -fn compatible_ab_pos_with_o_pos() { - let blood_type: BloodType = "AB+".parse().unwrap(); - let other_bt: BloodType = "O+".parse().unwrap(); - assert!(blood_type.can_receive_from(&other_bt)); -} - -#[test] -fn test_compatible_ab_neg_with_o_neg() { - let blood_type: BloodType = "AB-".parse().unwrap(); - let other_bt: BloodType = "O-".parse().unwrap(); - assert!(blood_type.can_receive_from(&other_bt)); -} - -#[test] -fn test_antigen_ab_from_str() { - let blood = "AB+"; - let blood_type: BloodType = blood.parse().unwrap(); - assert_eq!(blood_type.antigen, Antigen::AB); - assert_eq!(blood_type.rh_factor, RhFactor::Positive); -} - -#[test] -fn test_antigen_a_from_str() { - let blood = "A-"; - let blood_type = blood.parse::().unwrap(); - assert_eq!(blood_type.antigen, Antigen::A); - assert_eq!(blood_type.rh_factor, RhFactor::Negative); -} - -#[test] -#[should_panic] -fn test_unexistent_blood_type() { - let _blood_type: BloodType = "AO-".parse().unwrap(); -} - -#[test] -fn test_donors() { - let mut givers = "AB+".parse::().unwrap().donors(); - println!("Before sorting {:?}", &givers); - givers.sort(); - println!("{:?}", &givers); - let mut expected = vec![ - "AB-".parse::().unwrap(), - "A-".parse().unwrap(), - "B-".parse().unwrap(), - "O-".parse().unwrap(), - "AB+".parse().unwrap(), - "A+".parse().unwrap(), - "B+".parse().unwrap(), - "O+".parse().unwrap(), - ]; - expected.sort(); - assert_eq!(givers, expected); -} - -#[test] -fn test_a_neg_donors() { - let mut givers = "A-".parse::().unwrap().donors(); - givers.sort(); - let mut expected: Vec = vec!["A-".parse().unwrap(), "O-".parse().unwrap()]; - expected.sort(); - assert_eq!(givers, expected); -} - -#[test] -fn test_o_neg_donors() { - let mut givers = "O-".parse::().unwrap().donors(); - givers.sort(); - let mut expected: Vec = vec!["O-".parse().unwrap()]; - expected.sort(); - assert_eq!(givers, expected); -} - -#[test] -fn test_ab_pos_recipients() { - let mut recipients: Vec = "AB+".parse::().unwrap().recipients(); - recipients.sort(); - let mut expected: Vec = vec!["AB+".parse().unwrap()]; - expected.sort(); - assert_eq!(recipients, expected); -} - -#[test] -fn test_a_neg_recipients() { - let mut recipients = "A-".parse::().unwrap().recipients(); - recipients.sort(); - let mut expected: Vec = vec![ - "A-".parse().unwrap(), - "AB+".parse().unwrap(), - "A+".parse().unwrap(), - "AB-".parse().unwrap(), - ]; - expected.sort(); - assert_eq!(recipients, expected); -} - -#[test] -fn test_output() { - let blood_type: BloodType = "O+".parse().unwrap(); - println!("recipients of O+ {:?}", blood_type.recipients()); - println!("donors of O+ {:?}", blood_type.donors()); - let another_blood_type: BloodType = "A-".parse().unwrap(); - println!( - "donors of O+ can receive from {:?} {:?}", - &another_blood_type, - blood_type.can_receive_from(&another_blood_type) - ); -} diff --git a/tests/commits_stats_test/Cargo.toml b/tests/commits_stats_test/Cargo.toml index e3769f1c..b007b653 100644 --- a/tests/commits_stats_test/Cargo.toml +++ b/tests/commits_stats_test/Cargo.toml @@ -7,5 +7,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -json = "0.12" -commits_stats = { path = "../../solutions/commits_stats"} +json = "0.12.4" +commits_stats = { path = "../../solutions/commits_stats" } diff --git a/tests/commits_stats_test/src/lib.rs b/tests/commits_stats_test/src/lib.rs new file mode 100644 index 00000000..b9ba6b96 --- /dev/null +++ b/tests/commits_stats_test/src/lib.rs @@ -0,0 +1,46 @@ +use commits_stats::*; +use std::collections::HashMap; + +#[inline] +fn data() -> json::JsonValue { + json::parse(include_str!("../commits.json")).unwrap() +} + +#[test] +fn test_commits_per_week() { + assert_eq!( + commits_per_week(&data()), + HashMap::from([ + ("2020-W47".to_string(), 3), + ("2020-W43".to_string(), 1), + ("2020-W36".to_string(), 1), + ("2020-W50".to_string(), 2), + ("2020-W40".to_string(), 2), + ("2020-W44".to_string(), 5), + ("2020-W46".to_string(), 4), + ("2020-W31".to_string(), 1), + ("2020-W45".to_string(), 4), + ("2020-W49".to_string(), 7), + ]) + ); +} + +#[test] +fn test_commits_per_author() { + assert_eq!( + commits_per_author(&data()), + HashMap::from([ + ("RPigott".to_string(), 1), + ("RedSoxFan".to_string(), 1), + ("Xyene".to_string(), 7), + ("paul-ri".to_string(), 2), + ("JayceFayne".to_string(), 1), + ("mwenzkowski".to_string(), 3), + ("psnszsn".to_string(), 1), + ("emersion".to_string(), 10), + ("tamirzb".to_string(), 1), + ("ifreund".to_string(), 1), + ("homembaixinho".to_string(), 2), + ]) + ) +} diff --git a/tests/commits_stats_test/src/main.rs b/tests/commits_stats_test/src/main.rs deleted file mode 100644 index 3ea0649a..00000000 --- a/tests/commits_stats_test/src/main.rs +++ /dev/null @@ -1,98 +0,0 @@ -// # Instructions: - -// In this exercise you will be provided with a json file with data -// corresponding to git commits in github (extracted using the github -// rest api) your job is to extract the relevant data and place it in -// a struct called `CommitData` to get the following information: - -// 1. Number of commits per author (identified by the github login) -// 2. And the number of commits per author - -// Create two functions: -// fn commits_per_author(data: &Vec) -> HashMap<&str, u32> -// fn commits_per_date(data: &Vec) -> HashMap -// A week is represented by the a year followed by the number of the -// week for example January 1, 2020 is in week 1 of 2020 an will be -// represented by a String with the form "2020-W1" - -// # Notions: -// https://docs.rs/chrono/0.4.19/chrono/#modules -// https://serde.rs/ - -use commits_stats::{commits_per_author, commits_per_week}; -#[allow(unused_imports)] -use std::fs; - -fn main() { - let contents = fs::read_to_string("commits.json").unwrap(); - let serialized = json::parse(&contents).unwrap(); - println!("{:?}", commits_per_week(&serialized)); - println!("{:?}", commits_per_author(&serialized)); -} - -#[cfg(test)] -mod tests { - use super::*; - use std::collections::HashMap; - - fn test_setup() -> json::JsonValue { - let contents = fs::read_to_string("commits.json").unwrap(); - json::parse(&contents).unwrap() - } - - #[test] - fn test_commits_per_week() { - let serialized = test_setup(); - let commits_per_week = commits_per_week(&serialized); - println!("{:#?}", &commits_per_week); - let date = [ - "2020-W47".to_string(), - "2020-W43".to_string(), - "2020-W36".to_string(), - "2020-W50".to_string(), - "2020-W40".to_string(), - "2020-W44".to_string(), - "2020-W46".to_string(), - "2020-W31".to_string(), - "2020-W45".to_string(), - "2020-W49".to_string(), - ]; - - let mut com_per_week = HashMap::new(); - let commits = [3, 1, 1, 2, 2, 5, 4, 1, 4, 7]; - - for i in 0..date.len() { - com_per_week.insert(date[i].clone(), commits[i].clone()); - } - - assert_eq!(com_per_week, commits_per_week); - } - - #[test] - fn test_commits_per_author() { - let serialized = test_setup(); - let logins = [ - "RPigott", - "RedSoxFan", - "Xyene", - "paul-ri", - "JayceFayne", - "mwenzkowski", - "psnszsn", - "emersion", - "tamirzb", - "ifreund", - "homembaixinho", - ]; - let commits = [1, 1, 7, 2, 1, 3, 1, 10, 1, 1, 2]; - let mut expected = HashMap::new(); - - for i in 0..logins.len() { - expected.insert(logins[i].to_owned(), commits[i].to_owned()); - } - - let commits_per_author = commits_per_author(&serialized); - println!("{:#?}", &commits_per_author); - assert_eq!(expected, commits_per_author); - } -} diff --git a/tests/easy_traits_test/src/lib.rs b/tests/easy_traits_test/src/lib.rs new file mode 100644 index 00000000..e623757d --- /dev/null +++ b/tests/easy_traits_test/src/lib.rs @@ -0,0 +1,48 @@ +use easy_traits::*; + +#[test] +fn test_append_str() { + assert_eq!("hello there!", "hello".to_owned().append_str(" there!")); + + assert_eq!( + "hello, how are you?", + "hello".to_owned().append_str(", how are you?") + ); + + assert_eq!("hello!", "hello!".to_owned().append_str("")); + + assert_eq!("hello! ", "hello!".to_owned().append_str(" ")); + + assert_eq!( + "h!e!l?lo. the,.re!", + String::new().append_str("h!e!l?lo. the,.re!") + ); +} + +#[test] +fn test_remove_punctuation() { + assert_eq!("", "!?.,!?.,".to_owned().remove_punctuation_marks()); + + assert_eq!( + "hello there", + "hello there".to_owned().remove_punctuation_marks() + ); + + assert_eq!( + "hello there how are you", + ".hello there, how are you?!" + .to_owned() + .remove_punctuation_marks() + ); + + assert_eq!("-1555", "-1555".to_owned().remove_punctuation_marks()); +} + +#[test] +fn test_append_number() { + assert_eq!("-1", String::new().append_number(-1.)); + + assert_eq!("-1-5", "-1".to_owned().append_number(-5.)); + + assert_eq!("405.5", "40".to_owned().append_number(5.5)); +} diff --git a/tests/easy_traits_test/src/main.rs b/tests/easy_traits_test/src/main.rs deleted file mode 100644 index 4b86fc5b..00000000 --- a/tests/easy_traits_test/src/main.rs +++ /dev/null @@ -1,78 +0,0 @@ -use easy_traits::*; - -fn main() { - let mut str_aux = StringValue { - value: String::from("hello"), - }; - - println!("Before append: {}", str_aux.value); - - str_aux.append_str(String::from(" there!")); - println!("After append: {}", str_aux.value); - - str_aux.remove_punctuation_marks(); - println!("After removing punctuation: {}", str_aux.value); -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_append_str() { - let mut str_aux = StringValue { - value: String::from("hello"), - }; - - assert_eq!( - String::from("hello there!"), - str_aux.append_str(String::from(" there!")).value - ); - - assert_eq!( - String::from("hello there! How are You?"), - str_aux.append_str(String::from(" How are You?")).value - ); - - assert_eq!( - String::from("hello there How are You"), - str_aux.remove_punctuation_marks().value - ); - } - - #[test] - fn test_remove_punctuation() { - let mut str_aux = StringValue { - value: String::from("!?.,!?.,"), - }; - - assert_eq!(String::from(""), str_aux.remove_punctuation_marks().value); - - assert_eq!( - String::from("h!e!l?lo. the,.re!"), - str_aux.append_str(String::from("h!e!l?lo. the,.re!")).value - ); - assert_eq!( - String::from("hello there"), - str_aux.remove_punctuation_marks().value - ); - } - - #[test] - fn test_append_number() { - let mut str_aux = StringValue { - value: String::from(""), - }; - - assert_eq!(String::from("-1"), str_aux.append_number(-1.0).value); - - assert_eq!(String::from("-15"), str_aux.append_number(5.0).value); - - assert_eq!(String::from("-155.5"), str_aux.append_number(5.5).value); - - assert_eq!( - String::from("-1555"), - str_aux.remove_punctuation_marks().value - ); - } -} diff --git a/tests/generics_list_test/src/main.rs b/tests/generics_list_test/src/lib.rs similarity index 76% rename from tests/generics_list_test/src/main.rs rename to tests/generics_list_test/src/lib.rs index e9d5a91b..9e0b956b 100644 --- a/tests/generics_list_test/src/main.rs +++ b/tests/generics_list_test/src/lib.rs @@ -1,20 +1,5 @@ use generics_list::*; -fn main() { - let mut new_list_str = List::new(); - new_list_str.push("String Test 1"); - println!("The size of the list is {}", new_list_str.len()); - - new_list_str.push("String Test 2"); - println!("The size of the list is {}", new_list_str.len()); - - new_list_str.push("String Test 3"); - println!("The size of the list is {}", new_list_str.len()); - - new_list_str.pop(); - println!("The size of the list is {}", new_list_str.len()); -} - #[test] fn new_list_test() { let mut new_list_str = List::new(); diff --git a/tests/generics_test/src/main.rs b/tests/generics_test/src/lib.rs similarity index 63% rename from tests/generics_test/src/main.rs rename to tests/generics_test/src/lib.rs index b6f943e6..211ff86f 100644 --- a/tests/generics_test/src/main.rs +++ b/tests/generics_test/src/lib.rs @@ -1,12 +1,5 @@ -// Write a functions called identity that calculates the identity of a -// value (receives any data type and returns the same value) use generics::*; -fn main() { - println!("{}", identity("Hello, world!")); - println!("{}", identity(3)); -} - #[derive(PartialEq, Debug)] struct Point { x: i32, diff --git a/tests/lalgebra_scalar_test/src/main.rs b/tests/lalgebra_scalar_test/src/lib.rs similarity index 55% rename from tests/lalgebra_scalar_test/src/main.rs rename to tests/lalgebra_scalar_test/src/lib.rs index 0be2307f..3baff86c 100644 --- a/tests/lalgebra_scalar_test/src/main.rs +++ b/tests/lalgebra_scalar_test/src/lib.rs @@ -1,24 +1,4 @@ -// # Instructions -// A scalar type must implement the operations -// Addition, Subtraction, Multiplication and Division (you might -// also have to use more restrictions). For this use a trait -// inheritance (supertraits) - -// Another condition for a number to be a scalar is to have a zero -// (neutral element in the addition) and a one (neutral element in the -// multiplication). Therefore the Scalar trait will require 2 -// functions zero() and one() - -// After finishing implement the Scalar trait for u32, u64, i32, i64, -// f32, f64 - -use lalgebra_scalar::Scalar; - -#[allow(dead_code)] -fn main() { - println!("{:?}", f64::zero()); - println!("{:?}", i32::zero()); -} +use lalgebra_scalar::*; #[test] fn scalar_u32() { @@ -60,6 +40,7 @@ fn scalar_i64() { fn scalar_f32() { let zero = f32::zero(); assert_eq!(zero, 0.0); + let one = f32::one(); assert_eq!(one, 1.0); } @@ -68,6 +49,7 @@ fn scalar_f32() { fn scalar_f64() { let zero = f64::zero(); assert_eq!(zero, 0.0); + let one = f64::one(); assert_eq!(one, 1.0); } diff --git a/tests/lalgebra_vector_test/Cargo.toml b/tests/lalgebra_vector_test/Cargo.toml index 17b9131c..8f3eebdc 100644 --- a/tests/lalgebra_vector_test/Cargo.toml +++ b/tests/lalgebra_vector_test/Cargo.toml @@ -8,4 +8,3 @@ edition = "2021" [dependencies] lalgebra_vector = { path = "../../solutions/lalgebra_vector"} -lib = { path = "../lib" } diff --git a/tests/lalgebra_vector_test/src/lib.rs b/tests/lalgebra_vector_test/src/lib.rs new file mode 100644 index 00000000..328f2ae6 --- /dev/null +++ b/tests/lalgebra_vector_test/src/lib.rs @@ -0,0 +1,18 @@ +use lalgebra_vector::*; + +#[test] +fn dot_product() { + assert_eq!(Vector(vec![1, 3, -5]).dot(Vector(vec![4, -2, -1])), Some(3)); + + assert_eq!(Vector(vec![1, 3, -5]).dot(Vector(vec![4, -2])), None); +} + +#[test] +fn addition() { + assert_eq!( + Vector(vec![1, 3, -5]) + Vector(vec![4, -2, -1]), + Some(Vector(vec![5, 1, -6])) + ); + + assert_eq!(Vector(vec![1, 3, -5]) + Vector(vec![2, 4, -2, -1]), None); +} diff --git a/tests/lalgebra_vector_test/src/main.rs b/tests/lalgebra_vector_test/src/main.rs deleted file mode 100644 index 23673228..00000000 --- a/tests/lalgebra_vector_test/src/main.rs +++ /dev/null @@ -1,71 +0,0 @@ -// A vector in linear algebra is define as "anything that can be added -// and that can be multiplied by a scalar" -// And the associated function dot that calculates the dot product -// between two vectors -// let vector = Vector(vec![0,3, 4]); -// let vector_1 = Vector(vec![0,3,3]); -// vector.dot(&vector_1) == Some(23); - -// The dot product between two vectors of different length it's not defined - -use lalgebra_vector::Vector; - -fn main() { - let vector_1: Vector = Vector(vec![1, 3, -5]); - let vector_2: Vector = Vector(vec![4, -2, -1]); - println!("{:?}", vector_1.dot(&vector_2)); - println!("{:?}", vector_1 + vector_2); -} - -#[cfg(test)] -mod tests { - use super::*; - use lib::{Kind, TestProperties}; - - #[test] - fn dot_product() { - let vector_1: Vector = Vector(vec![1, 3, -5]); - let vector_2: Vector = Vector(vec![4, -2, -1]); - let meta_test = TestProperties { - name: "dot", - kind: Kind::Method, - }; - let expected: i64 = 3; - meta_test.assert_with_message( - &[Box::new(vector_1.clone()), Box::new(vector_2.clone())], - vector_1.dot(&vector_2), - Some(expected), - ); - - let vector_1: Vector = Vector(vec![1, 3, -5]); - let vector_2: Vector = Vector(vec![4, -2]); - meta_test.assert_with_message( - &[Box::new(vector_1.clone()), Box::new(vector_2.clone())], - vector_1.dot(&vector_2), - None, - ); - } - - #[test] - fn addition() { - let vector_1: Vector = Vector(vec![1, 3, -5]); - let vector_2: Vector = Vector(vec![4, -2, -1]); - let test_meta = TestProperties { - name: "+", - kind: Kind::Operator, - }; - test_meta.assert_with_message( - &[Box::new(vector_1.clone()), Box::new(vector_2.clone())], - vector_1 + vector_2, - Some(Vector(vec![5i64, 1, -6])), - ); - - let vector_1: Vector = Vector(vec![1, 3, -5]); - let vector_2: Vector = Vector(vec![2, 4, -2, -1]); - test_meta.assert_with_message( - &[Box::new(vector_1.clone()), Box::new(vector_2.clone())], - vector_1 + vector_2, - None, - ); - } -} diff --git a/tests/minesweeper_test/src/lib.rs b/tests/minesweeper_test/src/lib.rs new file mode 100644 index 00000000..bf56b8ce --- /dev/null +++ b/tests/minesweeper_test/src/lib.rs @@ -0,0 +1,93 @@ +use minesweeper::*; + +fn reset_solved(expected: &[&str]) -> Vec { + expected + .iter() + .map(|row| { + row.chars() + .map(|c| if c == '*' { c } else { ' ' }) + .collect() + }) + .collect() +} + +fn run_test(expected: &[&str]) { + let to_solve = reset_solved(expected); + let to_solve = to_solve.iter().map(|s| s.as_str()).collect::>(); + + assert_eq!(expected, solve_board(&to_solve)) +} + +#[test] +fn test_subject_example() { + #[rustfmt::skip] + run_test(&[ + "111", + "1*1", + "111", + ]); +} + +#[test] +fn test_no_rows() { + #[rustfmt::skip] + run_test(&[ + ]); +} + +#[test] +fn test_one_char() { + #[rustfmt::skip] + run_test(&[ + "*", + ]); +} + +#[test] +fn test_only_mines() { + #[rustfmt::skip] + run_test(&[ + "***", + "***", + "***", + ]); +} + +#[test] +fn test_no_mines() { + #[rustfmt::skip] + run_test(&[ + " ", + " ", + " ", + ]); +} + +#[test] +fn test_no_columns() { + #[rustfmt::skip] + run_test(&[ + "", + ]); +} + +#[test] +fn test_space_in_middle() { + #[rustfmt::skip] + run_test(&[ + "***", + "*8*", + "***", + ]); +} + +#[test] +fn test_complex_case() { + #[rustfmt::skip] + run_test(&[ + " 2**211", + "13*43*1", + "*334*32", + "12**22*", + ]); +} diff --git a/tests/minesweeper_test/src/main.rs b/tests/minesweeper_test/src/main.rs deleted file mode 100644 index fcfdbe5c..00000000 --- a/tests/minesweeper_test/src/main.rs +++ /dev/null @@ -1,106 +0,0 @@ -use minesweeper::*; - -fn main() { - println!("{:?}", solve_board(&[])); - println!("{:?}", solve_board(&[""])); - println!("{:?}", solve_board(&["***"])); - println!("{:#?}", solve_board(&[" ", " * ", " ",])); - println!("{:#?}", solve_board(&["* ", " ", " *",])); -} - -#[cfg(test)] -mod tests { - use super::*; - - fn run_test(expected: &[&str]) { - let expected: Vec = expected.iter().map(|row| row.chars().collect()).collect(); - let to_solve = get_to_solve(&expected); - let to_solve_strs = to_solve.iter().map(|row| row.as_str()).collect::>(); - assert_eq!(expected, solve_board(&to_solve_strs)) - } - - fn get_to_solve(expected: &[String]) -> Vec { - expected - .iter() - .map(|row| { - row.chars() - .map(|c| if c == '*' { c } else { ' ' }) - .collect() - }) - .collect() - } - - #[test] - fn test_subject_example() { - #[rustfmt::skip] - run_test(&[ - "111", - "1*1", - "111", - ]); - } - - #[test] - fn test_no_rows() { - #[rustfmt::skip] - run_test(&[ - ]); - } - - #[test] - fn test_one_char() { - #[rustfmt::skip] - run_test(&[ - "*", - ]); - } - - #[test] - fn test_only_mines() { - #[rustfmt::skip] - run_test(&[ - "***", - "***", - "***", - ]); - } - - #[test] - fn test_no_mines() { - #[rustfmt::skip] - run_test(&[ - " ", - " ", - " ", - ]); - } - - #[test] - fn test_no_columns() { - #[rustfmt::skip] - run_test(&[ - "", - ]); - } - - #[test] - fn test_space_in_middle() { - #[rustfmt::skip] - run_test(&[ - "***", - "*8*", - "***", - ]); - } - - #[test] - fn test_complex_case() { - #[rustfmt::skip] - run_test(&[ - " 2**211", - "13*43*1", - "*334*32", - "12**22*", - ]); - } -} diff --git a/tests/roman_numbers_test/src/lib.rs b/tests/roman_numbers_test/src/lib.rs new file mode 100644 index 00000000..e19405a0 --- /dev/null +++ b/tests/roman_numbers_test/src/lib.rs @@ -0,0 +1,27 @@ +use roman_numbers::*; + +#[test] +fn it_works() { + use roman_numbers::RomanDigit::*; + + assert_eq!(RomanNumber::from(0).0, [Nulla]); + assert_eq!(RomanNumber::from(3).0, [I, I, I]); + assert_eq!(RomanNumber::from(6).0, [V, I]); + assert_eq!(RomanNumber::from(15).0, [X, V]); + assert_eq!(RomanNumber::from(30).0, [X, X, X]); + assert_eq!(RomanNumber::from(150).0, [C, L]); + assert_eq!(RomanNumber::from(200).0, [C, C]); + assert_eq!(RomanNumber::from(600).0, [D, C]); + assert_eq!(RomanNumber::from(1500).0, [M, D]); +} + +#[test] +fn substractive_notation() { + use roman_numbers::RomanDigit::*; + + assert_eq!(RomanNumber::from(4).0, [I, V]); + assert_eq!(RomanNumber::from(44).0, [X, L, I, V]); + assert_eq!(RomanNumber::from(3446).0, [M, M, M, C, D, X, L, V, I]); + assert_eq!(RomanNumber::from(9).0, [I, X]); + assert_eq!(RomanNumber::from(94).0, [X, C, I, V]); +} diff --git a/tests/roman_numbers_test/src/main.rs b/tests/roman_numbers_test/src/main.rs deleted file mode 100644 index 2b42e3e5..00000000 --- a/tests/roman_numbers_test/src/main.rs +++ /dev/null @@ -1,49 +0,0 @@ -// # Instructions -// Implement the From Trait to create a roman number from a u32 -// the roman number should be in subtractive notation (the common way to write roman -// number I, II, II, IV, V, VI, VII, VIII, IX, X ...) - -// For this start by defining the digits as `RomanDigit` with the values -// I, V, X, L, C, D, M and Nulla for 0 - -// Next define RomanNumber as a wrapper to a vector of RomanDigit's -// And implement the Trait From - -// Examples: -// RomanNumber::from(32) = [X,X,X,I,I] -// RomanNumber::from(9) = [I,X] -// RomanNumber::from(45) = [X,L,V] -// RomanNumber:;from(0) = [Nulla] - -#[allow(unused_imports)] -use roman_numbers::RomanDigit::*; -#[allow(unused_imports)] -use roman_numbers::RomanNumber; - -#[allow(dead_code)] -fn main() { - println!("{:?}", RomanNumber::from(32)); - println!("{:?}", RomanNumber::from(9)); - println!("{:?}", RomanNumber::from(45)); - println!("{:?}", RomanNumber::from(0)); -} -#[test] -fn it_works() { - assert_eq!(RomanNumber::from(3).0, [I, I, I]); - assert_eq!(RomanNumber::from(6).0, [V, I]); - assert_eq!(RomanNumber::from(15).0, [X, V]); - assert_eq!(RomanNumber::from(30).0, [X, X, X]); - assert_eq!(RomanNumber::from(150).0, [C, L]); - assert_eq!(RomanNumber::from(200).0, [C, C]); - assert_eq!(RomanNumber::from(600).0, [D, C]); - assert_eq!(RomanNumber::from(1500).0, [M, D]); -} - -#[test] -fn substractive_notation() { - assert_eq!(RomanNumber::from(4).0, [I, V]); - assert_eq!(RomanNumber::from(44).0, [X, L, I, V]); - assert_eq!(RomanNumber::from(3446).0, [M, M, M, C, D, X, L, V, I]); - assert_eq!(RomanNumber::from(9).0, [I, X]); - assert_eq!(RomanNumber::from(94).0, [X, C, I, V]); -} diff --git a/tests/traits_test/src/lib.rs b/tests/traits_test/src/lib.rs new file mode 100644 index 00000000..7ad5e15d --- /dev/null +++ b/tests/traits_test/src/lib.rs @@ -0,0 +1,66 @@ +use traits::*; + +#[test] +fn test_gives() { + let apple = Fruit { weight_in_kg: 1.0 }; + assert_eq!(apple.gives(), 4.0); + + let steak = Meat { + weight_in_kg: 1.0, + fat_content: 1.0, + }; + assert_eq!(steak.gives(), 9.0); + + let steak = Meat { + weight_in_kg: 1.0, + fat_content: 0.0, + }; + assert_eq!(steak.gives(), 4.0); + + let steak = Meat { + weight_in_kg: 1.5, + fat_content: 0.3, + }; + assert_eq!(steak.gives(), 8.25); +} + +#[test] +fn test_eat() { + let apple = Fruit { weight_in_kg: 1.0 }; + assert_eq!(apple.gives(), 4.0); + + let steak = Meat { + weight_in_kg: 1.0, + fat_content: 1.0, + }; + + let mut player1 = Player { + name: "player1", + strength: 1.0, + score: 0, + money: 0, + weapons: vec!["knife"], + }; + + player1.eat(apple); + assert_eq!(player1.strength, 5.0); + + player1.eat(steak); + assert_eq!(player1.strength, 14.0); +} + +#[test] +fn test_display() { + let player1 = Player { + name: "player1", + strength: 1.0, + score: 0, + money: 0, + weapons: vec!["knife", "shotgun"], + }; + + assert_eq!( + player1.to_string(), + "player1\nStrength: 1, Score: 0, Money: 0\nWeapons: [\"knife\", \"shotgun\"]" + ) +} diff --git a/tests/traits_test/src/main.rs b/tests/traits_test/src/main.rs deleted file mode 100644 index 2639160b..00000000 --- a/tests/traits_test/src/main.rs +++ /dev/null @@ -1,97 +0,0 @@ -// Imagine you are designing a new video game and you have to create -// food that they players can take to gain strength there are two -// types of food for now fruits and meet: fruits increases the -// strengths by 1 unit and meat increases it by 3 unit. - -// Define both structures fruits and meat -// Define the std::fmt::Display trait of the Player structure so using -// the template {} inside a println! macro will print in the first -// line the name of the player -// in the second line the strength, score and the money -// and in the third line the weapons -use traits::{Food, Fruit, Meat, Player}; - -fn main() { - let apple = Fruit { weight_in_kg: 1.0 }; - - println!("this apple gives {} units of strength", apple.gives()); - - let steak = Meat { - weight_in_kg: 1.0, - fat_content: 1.0, - }; - - let mut player1 = Player { - name: String::from("player1"), - strength: 1.0, - score: 0, - money: 0, - weapons: vec![String::from("knife")], - }; - println!("Before eating {:?}", player1); - player1.eat(apple); - println!("After eating an apple\n{}", player1); - player1.eat(steak); - println!("After eating a steak\n{}", player1); -} - -#[test] -fn test_gives() { - let apple = Fruit { weight_in_kg: 1.0 }; - assert_eq!(apple.gives(), 4.0); - let steak = Meat { - weight_in_kg: 1.0, - fat_content: 1.0, - }; - assert_eq!(steak.gives(), 9.0); - - let steak = Meat { - weight_in_kg: 1.0, - fat_content: 0.0, - }; - assert_eq!(steak.gives(), 4.0); - - let steak = Meat { - weight_in_kg: 1.5, - fat_content: 0.3, - }; - assert_eq!(steak.gives(), 8.25); -} - -#[test] -fn test_eat() { - let apple = Fruit { weight_in_kg: 1.0 }; - assert_eq!(apple.gives(), 4.0); - let steak = Meat { - weight_in_kg: 1.0, - fat_content: 1.0, - }; - - let mut player1 = Player { - name: String::from("player1"), - strength: 1.0, - score: 0, - money: 0, - weapons: vec![String::from("knife")], - }; - player1.eat(apple); - assert_eq!(player1.strength, 5.0); - player1.eat(steak); - assert_eq!(player1.strength, 14.0); -} - -#[test] -fn test_display() { - let player1 = Player { - name: String::from("player1"), - strength: 1.0, - score: 0, - money: 0, - weapons: vec![String::from("knife"), String::from("shotgun")], - }; - println!("{}", player1); - assert_eq!( - player1.to_string(), - "player1\nStrength: 1, Score: 0, Money: 0\nWeapons: [\"knife\", \"shotgun\"]" - ) -} diff --git a/tests/vector_operations_test/src/lib.rs b/tests/vector_operations_test/src/lib.rs new file mode 100644 index 00000000..db577c4c --- /dev/null +++ b/tests/vector_operations_test/src/lib.rs @@ -0,0 +1,17 @@ +use vector_operations::*; + +#[test] +fn test_addition() { + let a = ThreeDVector { i: 3, j: 5, k: 2 }; + let b = ThreeDVector { i: 2, j: 7, k: 4 }; + let a_plus_b = ThreeDVector { i: 5, j: 12, k: 6 }; + assert_eq!(a + b, a_plus_b); +} + +#[test] +fn test_subtraction() { + let a = ThreeDVector { i: 3, j: 5, k: 2 }; + let b = ThreeDVector { i: 2, j: 7, k: 4 }; + let a_minus_b = ThreeDVector { i: 1, j: -2, k: -2 }; + assert_eq!(a - b, a_minus_b); +} diff --git a/tests/vector_operations_test/src/main.rs b/tests/vector_operations_test/src/main.rs deleted file mode 100644 index 4909b127..00000000 --- a/tests/vector_operations_test/src/main.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Define the structures ThreeDvector that represents a 3 dimensional -// vector in (for convention in physics the vector are represented as -// ai + bj + ck where a, b, and c are real numbers and i, j and k -// represent the direction x,y and z respectively in the Cartesian plane -// there for we use the names i, j and k for the fields in the -// ThreeDVector structure - -// Look how the operations Addition and Subtraction work for a 3 -// dimensional vector and implement them by implementing the -// std::ops::Add and std::ops::Sub traits - -use vector_operations::ThreeDVector; - -#[allow(dead_code)] -fn main() { - let a = ThreeDVector { i: 3, j: 5, k: 2 }; - let b = ThreeDVector { i: 2, j: 7, k: 4 }; - println!("{:?}", a + b); -} - -#[test] -fn it_works() { - assert_eq!(2 + 2, 4); -} - -#[test] -fn test_addition() { - let a = ThreeDVector { i: 3, j: 5, k: 2 }; - let b = ThreeDVector { i: 2, j: 7, k: 4 }; - let a_plus_b = ThreeDVector { i: 5, j: 12, k: 6 }; - assert_eq!(a + b, a_plus_b); -} - -#[test] -fn test_subtraction() { - let a = ThreeDVector { i: 3, j: 5, k: 2 }; - let b = ThreeDVector { i: 2, j: 7, k: 4 }; - let a_minus_b = ThreeDVector { i: 1, j: -2, k: -2 }; - assert_eq!(a - b, a_minus_b); -} From c863369d1674808e61431a6af1cd7b864c23bcbc Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 19 Sep 2025 02:23:45 +0100 Subject: [PATCH 2/2] fix(lalgebra_scalar): add clone (for compat) (& copy [for perf measures]) --- solutions/lalgebra_scalar/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/lalgebra_scalar/src/lib.rs b/solutions/lalgebra_scalar/src/lib.rs index 635c4243..1de2792a 100644 --- a/solutions/lalgebra_scalar/src/lib.rs +++ b/solutions/lalgebra_scalar/src/lib.rs @@ -1,6 +1,6 @@ use std::ops::{Add, Div, Mul, Sub}; -pub trait Scalar: Sized + Add + Sub + Mul + Div { +pub trait Scalar: Sized + Add + Sub + Mul + Div + Clone + Copy { type Item; fn zero() -> Self::Item;