Matrix 4
- Краен срок:
- 18.11.2021 17:00
- Точки:
- 20
Срокът за предаване на решения е отминал
Изненадващо, култовия филм "Матрицата" получава 4та версия скоро... Woah. Оригинала, който излезе (checks notes) преди някои от вас да са родени, е cyberpunk класика, и в негова чест ще си поиграем и ние с матрици с четири измерения елемента.
Започваме с конструиране и итериране на матрици (с четири елемента разделени на два реда) и на клетки от елементи:
#[derive(Debug)]
pub struct Matrix<T: Clone> {
// Каквито данни ви вършат работа
}
#[derive(Debug, Clone, PartialEq)]
pub struct Cell<T>(pub T);
impl<T: Clone> Matrix<T> {
/// Данните се очаква да бъдат подадени със статичен масив -- вижте по-долу за примери за
/// конструиране. Какви може да са елементите? Ще тестваме само с два типа: String и i32.
///
/// Очаква се да бъдат подадени по редове, от ляво надясно. Тоест, ако подадем като вход списък
/// с елементи: 1, 2, 3, 4, се очаква конструираната матрица:
///
/// | 1 2 |
/// | 3 4 |
///
/// Забележете, че подаваме като вход някакъв slice -- reference тип. Не очакваме матрицата да
/// държи reference, клонирайте си данните, за да имате ownership.
///
pub fn new(data: &[T; 4]) -> Matrix<T> {
todo!()
}
/// Връща вектор, който съдържа в себе си всички 4 елемента на матрицата, наредени по редове,
/// от ляво надясно и от горе надолу, обвити в `Cell`. Тоест, ако матрицата изглежда така:
///
/// | 1 2 |
/// | 3 4 |
///
/// Очакваме `.by_row` да върне елементите в ред: 1, 2, 3, 4
///
pub fn by_row(&self) -> Vec<Cell<T>> {
todo!()
}
/// Връща вектор, който съдържа в себе си всички 4 елемента на матрицата, наредени по колони,
/// от горе надолу и от ляво надясно, Обвити в `Cell`. Тоест, ако матрицата изглежда така:
///
/// | 1 2 |
/// | 3 4 |
///
/// Очакваме `.by_col` да върне елементите в ред: 1, 3, 2, 4
///
pub fn by_col(&self) -> Vec<Cell<T>> {
todo!()
}
}
Какви данни да съхранявате в матрицата? Можете да съхранявате елементите както са дадени и да конструирате Cell
-ове при итерация, или можете да си съхранявате Cell
-ове и да ги клонирате. Може да бъде вектор, а може и нещо по-просто. Може да ги държите по редове или по колони, или даже и двете. Ваш избор. Важното е да си имате ownership над тях, за да не се стига до lifetime анотации (тях ще ги упражним в бъдещи домашни и предизвикателства).
Забележете, че на двата struct-а сме сложили derive-нати типове: Debug
, Clone
, PartialEq
. Оставете ги както сме ги дали, макар че технически погледнато не ви пречи да ги имплементирате сами (няма нужда).
(Идея: дали не можете да си напишете собствена имплементация на PartialEq
, която просто казва, че всички клетки са равни една на друга и да минете хитро през тестовете 😈? Можете! И ако го направите, ще въздъхнем тежко, и ще копи-пейстнем примерно assert_ne!(Cell(0), Cell(1))
във всеки един от афектираните тестове, и ще ви смъкнем малко точки задето ни създавате допълнителна работа. Be smart, don't be clever.)
Събиране и умножение на клетки
Сега започваме с по-интересните неща. Матриците и клетките са generic, но за целите на задачата, ще работим само със String
и i32
. Нещо повече, събирането на числа и събирането на низове поотделно са сравнително скучни, така че ще имплементирате събиране само и единствено на i32
и String
в този ред -- число отляво, низ отдясно (не е трудно да имплементирате огледалната операция, не си заслужава да ви губим времето).
Как се събира число-клетка с низ-клетка? Ако числото е положително или нула, просто конкатенираме двете неща като низ с интервал между тях:
assert_eq!(Cell(22) + Cell(String::from("years ago")), Cell(String::from("22 years ago")))
assert_eq!(Cell(0) + Cell(String::from("expectation")), Cell(String::from("0 expectation")))
Ако числото е отрицателно, обръщаме текста на низа и го слагаме преди числото по абсолютна стойност:
assert_eq!(Cell(-4) + Cell(String::from("xirtam")), Cell(String::from("matrix 4")))
Очакваме да имплементирате само събиране на Cell<i32>
отляво със Cell<String>
отдясно, като резултата трябва да е Cell<String>
. Би трябвало това да ви е достатъчно информация, за имплементирате събирането с trait-а std::ops::Add
. Стига да се справите, горните примери (и базовия тест) ще ви се компилират.
Как се умножава число-клетка с низ-клетка? Ако числото е положително или нула, повтаряме толкова пъти низа:
assert_eq!(Cell(3) * Cell(String::from("woah!")), Cell(String::from("woah!woah!woah!")))
assert_eq!(Cell(0) * Cell(String::from("woah?")), Cell(String::from("")))
Ако числото е отрицателно, обръщаме текста на низа и го повтаряме толкова пъти
assert_eq!(Cell(-3) * Cell(String::from(",regdab")), Cell(String::from("badger,badger,badger,")))
Също както горния пример, умножението има Cell<i32>
от лявата страна и Cell<String>
от дясната, и резултата е Cell<String>
. Trait-а е std::ops::Mul
Събиране и умножение на матрици
Знаейки как се правят операции с клетки, може да дефинираме как стават нещата с матрици. Съществен разлика е, че събирането ни дава нова матрица, а умножението -- един-единствен низ. Събираме матрици поелементно -- всеки елемент на определен ред и колона в лявата матрица с елемента на същите координати в дясната:
| 1 2 | + | "one" "two" | = | "1 one" "2 two" |
| 3 4 | | "three" "four" | | "3 three" "4 four" |
Умножението на матрици става по правилото "редове по колони" -- елементите от първия ред на лявата матрица са умножени поелементно с първата колона на дясната, втория ред със втората колона, и са събрани в един низ с интервали:
| 1 2 | * | "one" "two" | = "one threethree twotwotwo you get it"
| 3 1 | | "three" "you get it" |
Тук "събиране" и "умножение" работят по правилата на клетките по-горе. Вижте базовия тест за примери, но типовете са:
-
Matrix<i32>
+Matrix<String>
=Matrix<String>
-
Matrix<i32>
*Matrix<String>
=String
Trait-овете както по-горе са std::ops::Add
и std::ops::Mul
.
Важно!
Погрижете се да имате версия на Rust компилатора и на cargo поне 1.56.0. Може да проверите като извикате rustc --version
и cargo --version
. Проверете и че в Cargo.toml
файла си имате следния ред:
edition = "2021"
В случай, че версиите ви са стари, може да използвате тази команда, за да си ги обновите:
rustup update stable
Задължително прочетете (или си припомнете): Указания за предаване на домашни
Погрижете се решението ви да се компилира с базовия тест: