Думи на Фибоначи

Предадени решения

Краен срок:
31.10.2024 18:00
Точки:
20

Срокът за предаване на решения е отминал

use solution::*;
use std::panic::catch_unwind;
#[test]
fn fib_iter() {
let mut fib_iter = FibIter::new();
assert_eq!(fib_iter.next(), 1);
assert_eq!(fib_iter.next(), 1);
assert_eq!(fib_iter.next(), 2);
assert_eq!(fib_iter.next(), 3);
assert_eq!(fib_iter.next(), 5);
assert_eq!(fib_iter.next(), 8);
assert_eq!(fib_iter.next(), 13);
}
#[test]
fn rev_fib_iter() {
let mut fib_iter = FibIter::new();
for _ in 0..7 {
fib_iter.next();
}
let mut rev_fib_iter = fib_iter.rev();
assert_eq!(rev_fib_iter.next(), Some(13));
assert_eq!(rev_fib_iter.next(), Some(8));
assert_eq!(rev_fib_iter.next(), Some(5));
assert_eq!(rev_fib_iter.next(), Some(3));
assert_eq!(rev_fib_iter.next(), Some(2));
assert_eq!(rev_fib_iter.next(), Some(1));
assert_eq!(rev_fib_iter.next(), Some(1));
assert_eq!(rev_fib_iter.next(), None);
assert_eq!(rev_fib_iter.next(), None);
}
#[test]
fn rev_fib_iter_empty() {
let fib_iter = FibIter::new();
let mut rev_fib_iter = fib_iter.rev();
assert_eq!(rev_fib_iter.next(), None);
}
#[test]
fn fib_split_empty() {
let words = fib_split("");
assert!(words == Vec::<&str>::new() || words == &[""]);
}
#[test]
fn fib_split_ascii() {
let words = fib_split("abcd123456");
assert_eq!(words, &["a", "b", "cd", "123", "456"]);
}
#[test]
fn fib_split_cyrillic() {
let words = fib_split("манджа с грозде");
assert_eq!(words, &["м", "а", "нд", "жа ", "с гро", "зде"]);
}
#[test]
fn fib_split_n_zero() {
let (words, rest) = fib_split_n("", 0);
assert_eq!(words, Vec::<&str>::new());
assert_eq!(rest, "");
let (words, rest) = fib_split_n("abcdгрозде", 0);
assert_eq!(words, Vec::<&str>::new());
assert_eq!(rest, "abcdгрозде");
}
#[test]
fn fib_split_n_ascii() {
let (words, rest) = fib_split_n("abcd_123", 1);
assert_eq!(words, &["a"]);
assert_eq!(rest, "bcd_123");
let (words, rest) = fib_split_n("abcd_123", 4);
assert_eq!(words, &["a", "b", "cd", "_12"]);
assert_eq!(rest, "3");
}
#[test]
fn fib_split_n_ascii_exact() {
let (words, rest) = fib_split_n("abcd_12_3456", 5);
assert_eq!(words, &["a", "b", "cd", "_12", "_3456"]);
assert_eq!(rest, "");
}
#[test]
fn fib_split_n_ascii_panic() {
assert!(catch_unwind(|| fib_split_n("", 1)).is_err());
assert!(catch_unwind(|| fib_split_n("abcd_123", 5)).is_err());
}
#[test]
fn fib_split_n_cyrillic() {
let (words, rest) = fib_split_n("манджа_with_грозде", 1);
assert_eq!(words, &["м"]);
assert_eq!(rest, "анджа_with_грозде");
let (words, rest) = fib_split_n("манджа_with_грозде", 5);
assert_eq!(words, &["м", "а", "нд", "жа_", "with_"]);
assert_eq!(rest, "грозде");
}
#[test]
fn fib_split_n_cyrillic_exact() {
let (words, rest) = fib_split_n("манджа_with_", 5);
assert_eq!(words, &["м", "а", "нд", "жа_", "with_"]);
assert_eq!(rest, "");
}
#[test]
fn fib_split_n_cyrillic_panic() {
assert!(catch_unwind(|| fib_split_n("манджа_with_грозде", 6)).is_err());
}
#[test]
fn fib_split_n_symmetric_zero() {
let (words, rest) = fib_split_n_symmetric("", 0);
assert_eq!(words, Vec::<&str>::new());
assert_eq!(rest, "");
let (words, rest) = fib_split_n_symmetric("abcdгрозде", 0);
assert_eq!(words, Vec::<&str>::new());
assert_eq!(rest, "abcdгрозде");
}
#[test]
fn fib_split_n_symmetric_ascii() {
let (words, rest) = fib_split_n_symmetric("abcd1234", 1);
assert_eq!(words, &["a", "b"]);
assert_eq!(rest, "cd1234");
let (words, rest) = fib_split_n_symmetric("abcd1234", 2);
assert_eq!(words, &["a", "b", "c", "d"]);
assert_eq!(rest, "1234");
}
#[test]
fn fib_split_n_symmetric_ascii_exact() {
let (words, rest) = fib_split_n_symmetric("abcd1234", 3);
assert_eq!(words, &["a", "b", "cd", "12", "3", "4"]);
assert_eq!(rest, "");
}
#[test]
fn fib_split_n_symmetric_ascii_panic() {
assert!(catch_unwind(|| fib_split_n_symmetric("", 1)).is_err());
assert!(catch_unwind(|| fib_split_n_symmetric("abcd_1234", 4)).is_err());
}
#[test]
fn fib_split_n_symmetric_cyrillic() {
let (words, rest) = fib_split_n_symmetric("манджа_with_грозде", 1);
assert_eq!(words, &["м", "а"]);
assert_eq!(rest, "нджа_with_грозде");
let (words, rest) = fib_split_n_symmetric("манджа_with_грозде", 4);
assert_eq!(words, &["м", "а", "нд", "жа_", "wit", "h_", "г", "р"]);
assert_eq!(rest, "озде");
}
#[test]
fn fib_split_n_symmetric_cyrillic_exact() {
let (words, rest) = fib_split_n_symmetric("манджа_with_гр", 4);
assert_eq!(words, &["м", "а", "нд", "жа_", "wit", "h_", "г", "р"]);
assert_eq!(rest, "");
}
#[test]
fn fib_split_n_symmetric_cyrillic_panic() {
assert!(catch_unwind(|| fib_split_n_symmetric("манджа_with_грозде", 5)).is_err());
}

Напишете програма, която разделя низ на "думи" с дължини числата от редицата на Фибоначи.

Понеже няма много смисъл от думи с дължина 0, за нашите цели ще дефинираме редицата да започва от 1, 1, т.е.:

  • F0 = 1
  • F1 = 1
  • Fn = Fn-1 + Fn-2, за n > 1

За начало, ще ни е нужна помощна стуктура, която да ни генерира числата на Фибоначи. Напишете структура FibIter. Полетата не са публични, така че можете да си добавите каквото ви е удобно - няма да ги тестваме директно. Структурата трябва да има два публични метода:

  • new създава нова инстанция, която ще итерира по редицата, започвайки от F0
  • next връща следващото число от редицата. При първото извикване трябва да върне F0, после F1 и т.н.
pub struct FibIter {
    /* ... */
}

impl FibIter {
    pub fn new() -> FibIter {
        todo!()
    }

    pub fn next(&mut self) -> u32 {
        todo!()
    }
}

Напишете функция, която приема текст и го връща разделен на думи. Всяка дума трябва да съдържа брой символи, равен на съответното число на Фибоначи. За разделянето ни интересува само броя символи - няма значение дали те са букви, интервали или пунктуация. Всички символи се третират еднакво. Ако текста не може да се раздели точно на думи на Фибоначи, последната дума може да съдържа по-малко символи от необходимото.

pub fn fib_split(text: &str) -> Vec<String> {
    todo!()
}

Пример: fib_split("Fibonacci words!") == vec!["F", "i", "bo", "nac", "ci wo", "rds!"]

Оказва се, че разделянето на цели параграфи текст на думи не е толкова полезно. Затова, напишете още една функция, която отделя само определен брой думи от началото на текста. Функцията трябва да върне кортеж (tuple) с два елемента - вектор с n думи с дължини от F0 до Fn-1 и остатъка от текста. Ако текстът е твърде къс и не съдържа поне n думи, от вас се очаква да panic-нете. Извикайте макрото panic! с някакво съобщение за грешка. Самото съобщение няма значение - няма да го проверяваме.

pub fn fib_split_n(text: &str, n: u32) -> (Vec<String>, &str) {
    todo!()
}

// или

pub fn fib_split_n(text: &str, n: u32) -> (Vec<String>, String) {
    todo!()
}

Можете да използвате която и да е сигнатура на функцията - изберете си тази, която ви е по-удобна. Теста ще е направен така, че да приема и двете. Примиер: fib_split_n("Lorem ipsum dolor sit amet.", 6) == (vec!["L", "o", "re", "m i", "psum ", "dolor si"], "t amet.")

Нещата работят чудесно, докато не дойде ново оплакване, че думите не са достатъчно симетрични. Затова ще трябва да се напише нова функция, която по зададено число n връща думи с дължини F0, F1, ..., Fn, Fn, Fn-1, ... F0.

За целта ще ни трябва помощна структура, която итерира числата на Фибоначи наобратно. Напишете структура RevFibIter и добавете метод на FibIter, който да я конструира.

impl FibIter {
    /* ... */

    pub fn rev(self) -> RevFibIter {
        todo!()
    }
}

pub struct RevFibIter {
    /* ... */
}

impl RevFibIter {
    pub fn next(&mut self) -> Option<u32> {
        todo!()
    }
}

FibIter::rev трябва да върне "итератор", който започва от последното число, върнато от FibIter. Т.е., ако последноfib_iter.next() e върнало Fn, то fib_iter.rev().next() трябва също да върне Fn.

RevFibIter::next връща Option, защото итерирайки я наобратно, редицата не е безкрайна. Методът се очаква да върне подред всички числа до F0, след което да започне да връща None до безкрай. Т.е. Some(Fn), Some(Fn-1), ..., Some(F0), None, None, ...

Имайки тази помощна структура, вече можем да имплементираме функция, която отделя n на брой симетрични думи на Фибоначи от подаден текст.

pub fn fib_split_n_symmetric(text: &str, n: u32) -> (Vec<String>, &str) {
    todo!()
}

// или

pub fn fib_split_n_symmetric(text: &str, n: u32) -> (Vec<String>, String) {
    todo!()
}

Отново - можете да използвате която от двете сигнатури предпочитате. Функцията трябва да връща tupple от два елемента

  • вектор от думи с дължини F0, F1, ..., Fn-1, Fn-1, Fn-2, ... F0;
  • остатъка от текста.

Ако текста не е достатъчно дълъг да могат да се отделят необходимия брой думи, се очаква да извикате panic!() с произволно съобщение. Примиер: fib_split_n_symmetric("Lorem ipsum dolor sit amet.", 5) == (vec!["L", "o", "re", "m i", "psum ", "dolor", " si", "t ", "a", "m"], "et.")

Задължително прочетете (или си припомнете): Указания за предаване на домашни

Погрижете се решението ви да се компилира с базовия тест:

use solution::*;
#[test]
fn test_basic() {
let mut fib_iter = FibIter::new();
fib_iter.next();
let mut rev_fib_iter: RevFibIter = fib_iter.rev();
rev_fib_iter.next();
let words: Vec<String> = fib_split("Fibonacci words!");
assert_eq!(words, &["F", "i", "bo", "nac", "ci wo", "rds!"]);
let (words, rest) = fib_split_n("Lorem ipsum dolor sit amet.", 6);
assert_eq!(words, &["L", "o", "re", "m i", "psum ", "dolor si"]);
assert_eq!(rest, "t amet.");
let (words, rest) = fib_split_n_symmetric("Lorem ipsum dolor sit amet.", 5);
assert_eq!(words, &["L", "o", "re", "m i", "psum ", "dolor", " si", "t ", "a", "m"]);
assert_eq!(rest, "et.");
}