Решение на FMI Buzz от Цветелин Цецков

Обратно към всички решения

Към профила на Цветелин Цецков

Резултати

  • 12 точки от тестове
  • 0 бонус точки
  • 12 точки общо
  • 8 успешни тест(а)
  • 2 неуспешни тест(а)

Код

const FIZZ: &str = "Fizz";
const BUZZ: &str = "Buzz";
const FIZZBUZZ: &str = "Fizzbuzz";
/// Generates a sequence from one to the inputted number
fn gen_sequence_one_to(n: usize) -> Vec<usize> {
(1..n + 1).collect()
}
/// Transorms the given num according to the rule
/// If it is devisible by k1 then lable_k1 is returned
/// If it is devisible by k2 then lable_k2 is returned
/// If it is devisible by both then label_both is returned
/// Also the type casting is taken care of in here so nowhere else do you need to do it
fn transform_for_keys(
num: usize,
k1: u8,
label_k1: String,
k2: u8,
label_k2: String,
label_both: String,
) -> String {
match num {
_ if num % (k1 as usize) == 0 && num % (k2 as usize) == 0 => label_both,
_ if num % (k1 as usize) == 0 => label_k1,
_ if num % (k2 as usize) == 0 => label_k2,
_ => num.to_string(),
}
}
/// A specialization of the transform_for_keys function to be appplicable to the normal game of FizzBuzz
fn fizz_buzz_transformer(num: usize) -> String {
transform_for_keys(
num,
3,
FIZZ.to_string(),
5,
BUZZ.to_string(),
FIZZBUZZ.to_string(),
)
}
/// A specialization of the transform_for_keys function to be appplicable to the normal game of FizzBuzz
fn custom_buzz_transformer(num: usize, k1: u8, k2: u8) -> String {
transform_for_keys(
num,
k1,
FIZZ.to_string(),
k2,
BUZZ.to_string(),
FIZZBUZZ.to_string(),
)
}
/// Generates elements according to the standard rules of the fizzbuzz game
pub fn fizzbuzz(n: usize) -> Vec<String> {
gen_sequence_one_to(n)
.iter()
.map(|&num| fizz_buzz_transformer(num))
.collect()
}

Вместо .iter(), което итерира по reference, можеш да използваш .into_iter(), което ще вземе ownership, ще консумира подадения вектор, и ще итерира по usize стойности. Така може да се получи:

gen_sequence_one_to(n)
    .into_iter()
    .map(fizz_buzz_transformer)
    .collect()
/// Genereates elements according to the rules of the fizzbuzz games, but with custom coefficients
pub fn custom_buzz(n: usize, k1: u8, k2: u8) -> Vec<String> {
gen_sequence_one_to(n)
.iter()
.map(|&num| custom_buzz_transformer(num, k1, k2))
.collect()
}
/// Defines a structure to geenrate elements
/// according to the rules of the game FizzBuzz,
/// but with custom constants and custom labels
pub struct FizzBuzzer {
pub k1: u8,
pub k2: u8,
pub labels: [String; 3],
}
impl FizzBuzzer {
/// Takes the first n elements which will be
/// generated according to the rules of the game fizzbuzz,
/// but specified in the structure
pub fn take(&self, n: usize) -> Vec<String> {
gen_sequence_one_to(n)
.iter()
.map(|&num| {
return transform_for_keys(
num,
self.k1,
self.labels[0].clone(),
self.k2,
self.labels[1].clone(),
self.labels[2].clone(),
);
})
.collect()
}
/// Changes the labels at the specified index
pub fn change_label(&mut self, index: usize, value: &String) {
self.labels[index] = value.clone();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn generator_test() {
let expected = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(gen_sequence_one_to(10), expected);
}
#[test]
fn fizz_buzz_transformer_test() {
assert_eq!(fizz_buzz_transformer(1), 1.to_string());
assert_eq!(fizz_buzz_transformer(2), 2.to_string());
assert_eq!(fizz_buzz_transformer(3), FIZZ.to_string());
assert_eq!(fizz_buzz_transformer(5), BUZZ.to_string());
assert_eq!(fizz_buzz_transformer(15), FIZZBUZZ.to_string());
}
#[test]
fn same_behaviour_test() {
fn custom_fizz(n: usize) -> Vec<String> {
custom_buzz(n, 3, 5)
}
let fizzbuzzer = FizzBuzzer {
k1: 3,
k2: 5,
labels: [
FIZZ.to_string(),
BUZZ.to_string(),
FIZZBUZZ.to_string(),
],
};
for i in 1..20 {
assert_eq!(fizzbuzz(i), custom_fizz(i));
assert_eq!(fizzbuzz(i), fizzbuzzer.take(i));
}
}
#[test]
fn empty_vector_test() {
let empty: Vec<String> = Vec::new();
let fizzbuzzer = FizzBuzzer {
k1: 3,
k2: 5,
labels: [
FIZZ.to_string(),
BUZZ.to_string(),
FIZZBUZZ.to_string(),
],
};
assert_eq!(fizzbuzz(0), empty);
assert_eq!(custom_buzz(0, 3, 5), empty);
assert_eq!(fizzbuzzer.take(0), empty);
}
}

Лог от изпълнението

Compiling solution v0.1.0 (/tmp/d20201028-2816268-g7puhb/solution)
    Finished test [unoptimized + debuginfo] target(s) in 3.08s
     Running target/debug/deps/solution-ebb42508826ef2b4

running 4 tests
test tests::empty_vector_test ... ok
test tests::fizz_buzz_transformer_test ... ok
test tests::generator_test ... ok
test tests::same_behaviour_test ... ok

test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

     Running target/debug/deps/solution_test-9e954a53ed808c89

running 10 tests
test solution_test::test_change_label_basic ... ok
test solution_test::test_change_label_invalid ... ok
test solution_test::test_classic1 ... ok
test solution_test::test_classic2 ... ok
test solution_test::test_coefficients1 ... ok
test solution_test::test_coefficients2 ... ok
test solution_test::test_coefficients_invalid ... FAILED
test solution_test::test_struct_basic ... ok
test solution_test::test_struct_invalid ... FAILED
test solution_test::test_zeroes ... ok

failures:

---- solution_test::test_coefficients_invalid stdout ----
thread 'main' panicked at 'attempt to calculate the remainder with a divisor of zero', src/lib.rs:26:14
thread 'main' panicked at 'attempt to calculate the remainder with a divisor of zero', src/lib.rs:24:14
thread 'main' panicked at 'assertion failed: catch_unwind(|| { custom_buzz(10, 3, 1); }).is_err()', tests/solution_test.rs:66:5

---- solution_test::test_struct_invalid stdout ----
thread 'main' panicked at 'attempt to calculate the remainder with a divisor of zero', src/lib.rs:26:14
thread 'main' panicked at 'attempt to calculate the remainder with a divisor of zero', src/lib.rs:24:14
thread 'main' panicked at 'assertion failed: catch_unwind(|| { fizzbuzzer!(3, 1); }).is_err()', tests/solution_test.rs:102:5


failures:
    solution_test::test_coefficients_invalid
    solution_test::test_struct_invalid

test result: FAILED. 8 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out

error: test failed, to rerun pass '--test solution_test'

История (2 версии и 4 коментара)

Цветелин качи първо решение на 21.10.2020 22:35 (преди почти 5 години)

Цветелин качи решение на 23.10.2020 10:45 (преди почти 5 години)

+const FIZZ: &str = "Fizz";
+const BUZZ: &str = "Buzz";
+const FIZZBUZZ: &str = "Fizzbuzz";
+
/// Generates a sequence from one to the inputted number
fn gen_sequence_one_to(n: usize) -> Vec<usize> {
(1..n + 1).collect()
}
/// Transorms the given num according to the rule
/// If it is devisible by k1 then lable_k1 is returned
/// If it is devisible by k2 then lable_k2 is returned
/// If it is devisible by both then label_both is returned
/// Also the type casting is taken care of in here so nowhere else do you need to do it
fn transform_for_keys(
num: usize,
k1: u8,
label_k1: String,
k2: u8,
label_k2: String,
label_both: String,
) -> String {
match num {
_ if num % (k1 as usize) == 0 && num % (k2 as usize) == 0 => label_both,
_ if num % (k1 as usize) == 0 => label_k1,
_ if num % (k2 as usize) == 0 => label_k2,
_ => num.to_string(),
}
}
/// A specialization of the transform_for_keys function to be appplicable to the normal game of FizzBuzz
fn fizz_buzz_transformer(num: usize) -> String {
transform_for_keys(
num,
3,
- "Fizz".to_string(),
+ FIZZ.to_string(),
5,
- "Buzz".to_string(),
- "FizzBuzz".to_string(),
+ BUZZ.to_string(),
+ FIZZBUZZ.to_string(),
)
}
/// A specialization of the transform_for_keys function to be appplicable to the normal game of FizzBuzz
fn custom_buzz_transformer(num: usize, k1: u8, k2: u8) -> String {
transform_for_keys(
num,
k1,
- "Fizz".to_string(),
+ FIZZ.to_string(),
k2,
- "Buzz".to_string(),
- "FizzBuzz".to_string(),
+ BUZZ.to_string(),
+ FIZZBUZZ.to_string(),
)
}
/// Generates elements according to the standard rules of the fizzbuzz game
pub fn fizzbuzz(n: usize) -> Vec<String> {
gen_sequence_one_to(n)
.iter()
.map(|&num| fizz_buzz_transformer(num))
.collect()
}

Вместо .iter(), което итерира по reference, можеш да използваш .into_iter(), което ще вземе ownership, ще консумира подадения вектор, и ще итерира по usize стойности. Така може да се получи:

gen_sequence_one_to(n)
    .into_iter()
    .map(fizz_buzz_transformer)
    .collect()
/// Genereates elements according to the rules of the fizzbuzz games, but with custom coefficients
pub fn custom_buzz(n: usize, k1: u8, k2: u8) -> Vec<String> {
gen_sequence_one_to(n)
.iter()
.map(|&num| custom_buzz_transformer(num, k1, k2))
.collect()
}
/// Defines a structure to geenrate elements
/// according to the rules of the game FizzBuzz,
/// but with custom constants and custom labels
pub struct FizzBuzzer {
pub k1: u8,
pub k2: u8,
pub labels: [String; 3],
}
impl FizzBuzzer {
/// Takes the first n elements which will be
/// generated according to the rules of the game fizzbuzz,
/// but specified in the structure
pub fn take(&self, n: usize) -> Vec<String> {
gen_sequence_one_to(n)
.iter()
.map(|&num| {
return transform_for_keys(
num,
self.k1,
self.labels[0].clone(),
self.k2,
self.labels[1].clone(),
self.labels[2].clone(),
);
})
.collect()
}
/// Changes the labels at the specified index
pub fn change_label(&mut self, index: usize, value: &String) {
self.labels[index] = value.clone();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn generator_test() {
let expected = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(gen_sequence_one_to(10), expected);
}
#[test]
fn fizz_buzz_transformer_test() {
assert_eq!(fizz_buzz_transformer(1), 1.to_string());
assert_eq!(fizz_buzz_transformer(2), 2.to_string());
- assert_eq!(fizz_buzz_transformer(3), "Fizz");
- assert_eq!(fizz_buzz_transformer(5), "Buzz");
- assert_eq!(fizz_buzz_transformer(15), "FizzBuzz");
+ assert_eq!(fizz_buzz_transformer(3), FIZZ.to_string());
+ assert_eq!(fizz_buzz_transformer(5), BUZZ.to_string());
+ assert_eq!(fizz_buzz_transformer(15), FIZZBUZZ.to_string());
}
#[test]
fn same_behaviour_test() {
fn custom_fizz(n: usize) -> Vec<String> {
custom_buzz(n, 3, 5)
}
let fizzbuzzer = FizzBuzzer {
k1: 3,
k2: 5,
labels: [
- "Fizz".to_string(),
- "Buzz".to_string(),
- "FizzBuzz".to_string(),
+ FIZZ.to_string(),
+ BUZZ.to_string(),
+ FIZZBUZZ.to_string(),
],
};
for i in 1..20 {
assert_eq!(fizzbuzz(i), custom_fizz(i));
assert_eq!(fizzbuzz(i), fizzbuzzer.take(i));
}
}
#[test]
fn empty_vector_test() {
let empty: Vec<String> = Vec::new();
let fizzbuzzer = FizzBuzzer {
k1: 3,
k2: 5,
labels: [
- "Fizz".to_string(),
- "Buzz".to_string(),
- "FizzBuzz".to_string(),
+ FIZZ.to_string(),
+ BUZZ.to_string(),
+ FIZZBUZZ.to_string(),
],
};
assert_eq!(fizzbuzz(0), empty);
assert_eq!(custom_buzz(0, 3, 5), empty);
assert_eq!(fizzbuzzer.take(0), empty);
}
-}
+}

Изпуснал си условието за коефициенти 0 и 1. Иначе оценявам тестовете и експериментирането с итератори -- keep it up. Откъм тестове, забелязвам, че не си пробвал поредицата нито с различни коефициенти от 3 и 5, нито с различни низове. Ако например на мястото, където се използва custom_buzz_transformer използваш fizz_buzz_transformer, твоите тестове продължават да минават, понеже тестват само за Fizz, Buzz, etc.

В случая Rust би ти дал warning, че имаш неизползвана функция, но за по-интересно (и по-голямо) парче код лесно можеш да допуснеш подобна грешка, която тестовете да не хванат. Проверката, че fizzbuzz и custom buzz-a са еквивалентни с тези коефициенти е добра -- но трябва и да тестваш къде са различни, за да си сигурен :)