mirror of
https://github.com/kmc7468/cs220.git
synced 2025-12-15 22:48:45 +00:00
copy-paste problems
This commit is contained in:
36
src/assignments/assignment07/generator.rs
Normal file
36
src/assignments/assignment07/generator.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
//! Generators
|
||||
|
||||
enum Yielded<T> {
|
||||
Value(T),
|
||||
Stop,
|
||||
}
|
||||
|
||||
/// Generator
|
||||
///
|
||||
/// Reference:
|
||||
/// - [Python generator](https://python-reference.readthedocs.io/en/latest/docs/generator/)
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Generator<T, S> {
|
||||
state: S,
|
||||
f: fn(&mut S) -> Yielded<T>,
|
||||
}
|
||||
|
||||
impl<T, S> Iterator for Generator<T, S> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a generator that yields fibonacci numbers.
|
||||
pub fn fib_generator(first: usize, second: usize) -> Generator<usize, (usize, usize)> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Returns a generator that yields collatz numbers.
|
||||
///
|
||||
/// The generator stops when it reaches to 1.
|
||||
pub fn collatz_conjecture(start: usize) -> Generator<usize, usize> {
|
||||
todo!()
|
||||
}
|
||||
38
src/assignments/assignment07/generator_grade.rs
Normal file
38
src/assignments/assignment07/generator_grade.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use itertools::Itertools;
|
||||
use ntest::assert_about_eq;
|
||||
|
||||
use super::super::generator::*;
|
||||
|
||||
#[test]
|
||||
fn test_generator() {
|
||||
assert_eq!(
|
||||
fib_generator(0, 1).take(10).collect::<Vec<_>>(),
|
||||
vec![0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
collatz_conjecture(12).collect::<Vec<_>>(),
|
||||
vec![12, 6, 3, 10, 5, 16, 8, 4, 2, 1]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
collatz_conjecture(19).collect::<Vec<_>>(),
|
||||
vec![19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
collatz_conjecture(27).collect::<Vec<_>>(),
|
||||
vec![
|
||||
27, 82, 41, 124, 62, 31, 94, 47, 142, 71, 214, 107, 322, 161, 484, 242, 121, 364,
|
||||
182, 91, 274, 137, 412, 206, 103, 310, 155, 466, 233, 700, 350, 175, 526, 263, 790,
|
||||
395, 1186, 593, 1780, 890, 445, 1336, 668, 334, 167, 502, 251, 754, 377, 1132, 566,
|
||||
283, 850, 425, 1276, 638, 319, 958, 479, 1438, 719, 2158, 1079, 3238, 1619, 4858,
|
||||
2429, 7288, 3644, 1822, 911, 2734, 1367, 4102, 2051, 6154, 3077, 9232, 4616, 2308,
|
||||
1154, 577, 1732, 866, 433, 1300, 650, 325, 976, 488, 244, 122, 61, 184, 92, 46, 23,
|
||||
70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
84
src/assignments/assignment07/hubo.rs
Normal file
84
src/assignments/assignment07/hubo.rs
Normal file
@@ -0,0 +1,84 @@
|
||||
//! Hubo is back!
|
||||
|
||||
/// Types that represent a direction.
|
||||
pub trait Direction {
|
||||
/// Get the direction in the form of a 2-dimensional vector.
|
||||
/// The resulting value doesn't have to be normalized.
|
||||
fn get_vector(&self) -> (f32, f32);
|
||||
}
|
||||
|
||||
/// 4-way enum to indicate directions.
|
||||
#[derive(Debug)]
|
||||
pub enum Dir4 {
|
||||
/// +x direction
|
||||
Right,
|
||||
/// -x direction
|
||||
Left,
|
||||
/// +y direction
|
||||
Up,
|
||||
/// -y direction
|
||||
Down,
|
||||
}
|
||||
|
||||
impl Direction for Dir4 {
|
||||
fn get_vector(&self) -> (f32, f32) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Direction for (f32, f32) {
|
||||
fn get_vector(&self) -> (f32, f32) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Hubo.
|
||||
/// It's direction can be represented by an arbitrary type.
|
||||
///
|
||||
/// It can be controlled by [HuboController] only if the direction type implements the [Direction] trait.
|
||||
#[derive(Debug)]
|
||||
pub struct Hubo<TDir> {
|
||||
direction: TDir,
|
||||
x: f32,
|
||||
y: f32,
|
||||
}
|
||||
|
||||
/// Controller of the Hubo
|
||||
#[derive(Debug)]
|
||||
pub struct HuboController<'s, TDir> {
|
||||
hubo: &'s mut Hubo<TDir>,
|
||||
}
|
||||
|
||||
impl<TDir> Hubo<TDir> {
|
||||
/// Create a Hubo.
|
||||
pub fn new(direction: TDir, x: f32, y: f32) -> Self {
|
||||
Self { direction, x, y }
|
||||
}
|
||||
|
||||
/// Return the current position of Hubo.
|
||||
pub fn get_position(&self) -> (f32, f32) {
|
||||
(self.x, self.y)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, TDir: Direction> HuboController<'s, TDir> {
|
||||
/// Return the controller of the given Hubo.
|
||||
/// Note that the lifetime of hubo's mutable reference \['s\] is repeated in the return type.
|
||||
///
|
||||
/// This represents that the controller cannot live longer than the mutable reference,
|
||||
/// since the controller takes and stores the reference.
|
||||
pub fn new(hubo: &'s mut Hubo<TDir>) -> HuboController<'s, TDir> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Make Hubo move forward by the given distance. You might need to normalize the vector
|
||||
/// acquired from `Direction::get_move_vector`.
|
||||
pub fn move_hubo_forward(&mut self, distance: f32) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Make Hubo turn to the given direction.
|
||||
pub fn set_hubo_direction(&mut self, dir: TDir) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
40
src/assignments/assignment07/hubo_grade.rs
Normal file
40
src/assignments/assignment07/hubo_grade.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use itertools::Itertools;
|
||||
use ntest::assert_about_eq;
|
||||
|
||||
use super::super::hubo::*;
|
||||
|
||||
#[test]
|
||||
fn test_hubo_dir4_movement() {
|
||||
let mut hubo = Hubo::new(Dir4::Right, 0.0, 0.0);
|
||||
let mut controller = HuboController::new(&mut hubo);
|
||||
|
||||
// Test moving forward
|
||||
controller.move_hubo_forward(5.0);
|
||||
|
||||
controller.set_hubo_direction(Dir4::Up);
|
||||
controller.move_hubo_forward(3.0);
|
||||
|
||||
controller.set_hubo_direction(Dir4::Left);
|
||||
controller.move_hubo_forward(2.0);
|
||||
|
||||
assert_eq!(hubo.get_position(), (3.0, 3.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hubo_tuple_movement() {
|
||||
let mut hubo = Hubo::new((1., 0.), 0.0, 0.0);
|
||||
let mut controller = HuboController::new(&mut hubo);
|
||||
|
||||
// Test moving forward
|
||||
controller.move_hubo_forward(5.0);
|
||||
|
||||
controller.set_hubo_direction((3., 4.));
|
||||
controller.move_hubo_forward(5.0);
|
||||
|
||||
controller.set_hubo_direction((-8., -6.));
|
||||
controller.move_hubo_forward(15.0);
|
||||
assert_eq!(hubo.get_position(), (-4., -5.));
|
||||
}
|
||||
}
|
||||
18
src/assignments/assignment07/mod.rs
Normal file
18
src/assignments/assignment07/mod.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
//! Assignment 7: Mastering advanced types (2/2).
|
||||
//!
|
||||
//! The primary goal of this assignment is to understand generics, traits, and lifetimes.
|
||||
//!
|
||||
//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-07.sh` works fine.
|
||||
//! See `assignment07_grade.rs` and `/scripts/grade-07.sh` for the test script.
|
||||
|
||||
pub mod generator;
|
||||
pub mod hubo;
|
||||
pub mod my_itertools;
|
||||
pub mod small_exercises;
|
||||
pub mod transform;
|
||||
|
||||
mod generator_grade;
|
||||
mod hubo_grade;
|
||||
mod my_itertools_grade;
|
||||
mod small_exercises_grade;
|
||||
mod transform_grade;
|
||||
117
src/assignments/assignment07/my_itertools.rs
Normal file
117
src/assignments/assignment07/my_itertools.rs
Normal file
@@ -0,0 +1,117 @@
|
||||
//! Implement your own minimal `itertools` crate.
|
||||
|
||||
use std::hash::Hash;
|
||||
|
||||
/// Iterator that iterates over the given iterator and returns only unique elements.
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Unique<I: Iterator> {
|
||||
// TODO: remove `_marker` and add necessary fields as you want
|
||||
_marker: std::marker::PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<I: Iterator> Iterator for Unique<I>
|
||||
where
|
||||
I::Item: Eq + Hash + Clone,
|
||||
{
|
||||
type Item = I::Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator that chains two iterators together.
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Chain<I1: Iterator, I2: Iterator> {
|
||||
// TODO: remove `_marker` and add necessary fields as you want
|
||||
_marker: std::marker::PhantomData<(I1, I2)>,
|
||||
}
|
||||
|
||||
impl<T: Eq + Hash + Clone, I1: Iterator<Item = T>, I2: Iterator<Item = T>> Iterator
|
||||
for Chain<I1, I2>
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator that iterates over given iterator and enumerates each element.
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Enumerate<I: Iterator> {
|
||||
// TODO: remove `_marker` and add necessary fields as you want
|
||||
_marker: std::marker::PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<I: Iterator> Iterator for Enumerate<I> {
|
||||
type Item = (usize, I::Item);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator that zips two iterators together.
|
||||
///
|
||||
/// If one iterator is longer than the other one, the remaining elements for the longer element
|
||||
/// should be ignored.
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Zip<I1: Iterator, I2: Iterator> {
|
||||
// TODO: remove `_marker` and add necessary fields as you want
|
||||
_marker: std::marker::PhantomData<(I1, I2)>,
|
||||
}
|
||||
|
||||
impl<I1: Iterator, I2: Iterator> Iterator for Zip<I1, I2> {
|
||||
type Item = (I1::Item, I2::Item);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// My Itertools trait.
|
||||
pub trait MyIterTools: Iterator {
|
||||
/// Returns an iterator that iterates over the `self` and returns only unique elements.
|
||||
fn my_unique(self) -> Unique<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Returns an iterator that chains `self` and `other` together.
|
||||
fn my_chain<I: Iterator>(self, other: I) -> Chain<Self, I>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Returns an iterator that iterates over `self` and enumerates each element.
|
||||
fn my_enumerate(self) -> Enumerate<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Returns an iterator that zips `self` and `other` together.
|
||||
fn my_zip<I: Iterator>(self, other: I) -> Zip<Self, I>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Foldleft for `MyIterTools`
|
||||
fn my_fold<T, F>(mut self, init: T, mut f: F) -> T
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(Self::Item, T) -> T,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> MyIterTools for T where T: Iterator {}
|
||||
65
src/assignments/assignment07/my_itertools_grade.rs
Normal file
65
src/assignments/assignment07/my_itertools_grade.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use itertools::Itertools;
|
||||
use ntest::assert_about_eq;
|
||||
|
||||
use super::super::my_itertools::*;
|
||||
|
||||
#[test]
|
||||
fn test_itertools() {
|
||||
assert_eq!(
|
||||
[10, 1, 1, 1, 2, 3, 4, 1, 3, 2]
|
||||
.into_iter()
|
||||
.my_chain(std::iter::repeat(100))
|
||||
.my_unique()
|
||||
.take(4)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![10, 1, 2, 3]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
std::iter::repeat(5)
|
||||
.my_enumerate()
|
||||
.map(|(i, e)| { i * e })
|
||||
.take(5)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![0, 5, 10, 15, 20]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
vec![0, 1, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,],
|
||||
[0, 1, 10].into_iter().my_chain(0..10).collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
let it = || (1..=5).cycle().my_zip((1..=3).cycle()).map(|(x, y)| x * y);
|
||||
let take15 = vec![
|
||||
2, // 1 * 1,
|
||||
4, // 2 * 2,
|
||||
9, // 3 * 3,
|
||||
4, // 4 * 1,
|
||||
10, // 5 * 2,
|
||||
3, // 1 * 3,
|
||||
2, // 2 * 1,
|
||||
6, // 3 * 2,
|
||||
12, // 4 * 3,
|
||||
5, // 5 * 1,
|
||||
2, // 1 * 2,
|
||||
6, // 2 * 3,
|
||||
3, // 3 * 1,
|
||||
8, // 4 * 2,
|
||||
15, // 5 * 3,
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
// 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
|
||||
// 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
|
||||
it().take(15).collect::<Vec<_>>(),
|
||||
take15
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
it().take(15).my_fold(0, |elt, acc| elt + acc),
|
||||
take15.iter().sum()
|
||||
);
|
||||
}
|
||||
}
|
||||
119
src/assignments/assignment07/small_exercises.rs
Normal file
119
src/assignments/assignment07/small_exercises.rs
Normal file
@@ -0,0 +1,119 @@
|
||||
//! Implement functions usint `Iterator` trait
|
||||
|
||||
struct FindIter<'s, T: Eq> {
|
||||
query: &'s [T],
|
||||
base: &'s [T],
|
||||
curr: usize,
|
||||
}
|
||||
|
||||
impl<T: Eq> Iterator for FindIter<'_, T> {
|
||||
type Item = usize;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over substring query indexes in the base.
|
||||
pub fn find<'s, T: Eq>(query: &'s [T], base: &'s [T]) -> impl 's + Iterator<Item = usize> {
|
||||
FindIter {
|
||||
query,
|
||||
base,
|
||||
curr: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement fibonacci iterator
|
||||
struct FibIter<T> {
|
||||
// TODO: remove `_marker` and add necessary fields as you want
|
||||
_marker: std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: std::ops::Add<Output = T> + Copy> FibIter<T> {
|
||||
fn new(first: T, second: T) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Iterator for FibIter<T>
|
||||
where
|
||||
T: std::ops::Add<Output = T> + Copy,
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns and iterator over the generic fibonacci sequence starting from `first` and `second`.
|
||||
/// This is a generic version of `fibonacci` function, which works for any types that implements `std::ops::Add` trait.
|
||||
pub fn fib<T>(first: T, second: T) -> impl Iterator<Item = T>
|
||||
where
|
||||
T: std::ops::Add<Output = T> + Copy,
|
||||
{
|
||||
todo!("remove below");
|
||||
std::iter::empty()
|
||||
}
|
||||
|
||||
/// Endpoint of range, inclusive or exclusive.
|
||||
#[derive(Debug)]
|
||||
pub enum Endpoint {
|
||||
/// Inclusive endpoint
|
||||
Inclusive(isize),
|
||||
|
||||
/// Exclusive endpoint
|
||||
Exclusive(isize),
|
||||
}
|
||||
|
||||
struct RangeIter {
|
||||
// TODO: add necessary fields as you want
|
||||
}
|
||||
|
||||
impl RangeIter {
|
||||
fn new(endpoints: (Endpoint, Endpoint), step: isize) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for RangeIter {
|
||||
type Item = isize;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over the range [left, right) with the given step.
|
||||
pub fn range(left: Endpoint, right: Endpoint, step: isize) -> impl Iterator<Item = isize> {
|
||||
todo!("remove below");
|
||||
std::iter::empty()
|
||||
}
|
||||
|
||||
/// Write an iterator that returns all divisors of n in increasing order.
|
||||
/// Assume n > 0.
|
||||
///
|
||||
/// Hint: trying all candidates from 1 to n will most likely time out!
|
||||
/// To optimize it, make use of the following fact:
|
||||
/// if x is a divisor of n that is greater than sqrt(n),
|
||||
/// then n/x is a divisor of n that is smaller than sqrt(n).
|
||||
struct Divisors {
|
||||
n: u64,
|
||||
// TODO: you may define additional fields here
|
||||
}
|
||||
|
||||
impl Iterator for Divisors {
|
||||
type Item = u64;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over the divisors of n.
|
||||
pub fn divisors(n: u64) -> impl Iterator<Item = u64> {
|
||||
Divisors {
|
||||
n,
|
||||
// TODO: you may define additional fields here
|
||||
}
|
||||
}
|
||||
189
src/assignments/assignment07/small_exercises_grade.rs
Normal file
189
src/assignments/assignment07/small_exercises_grade.rs
Normal file
@@ -0,0 +1,189 @@
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use itertools::Itertools;
|
||||
use ntest::assert_about_eq;
|
||||
|
||||
use super::super::small_exercises::*;
|
||||
|
||||
#[test]
|
||||
fn test_find() {
|
||||
assert_eq!(
|
||||
find("abc".as_bytes(), "abcdabcd".as_bytes()).collect::<Vec<usize>>(),
|
||||
vec![0, 4]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
find("aaba".as_bytes(), "aabaacaadaabaaba".as_bytes()).collect::<Vec<usize>>(),
|
||||
vec![0, 9, 12]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
find("ababac".as_bytes(), "abababcabababcabababc".as_bytes()).collect::<Vec<usize>>(),
|
||||
vec![]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
find("ababc".as_bytes(), "abc".as_bytes()).collect::<Vec<usize>>(),
|
||||
vec![]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_usize() {
|
||||
assert_eq!(
|
||||
find(&[1, 2, 3], &[1, 2, 3, 4, 1, 2, 3, 4]).collect::<Vec<usize>>(),
|
||||
vec![0, 4]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
find(
|
||||
&[5, 5, 7, 5],
|
||||
&[5, 5, 7, 5, 5, 8, 5, 5, 9, 5, 5, 7, 5, 5, 7, 5]
|
||||
)
|
||||
.collect::<Vec<usize>>(),
|
||||
vec![0, 9, 12]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fib_iter() {
|
||||
assert_eq!(
|
||||
fib(0, 1).take(10).collect::<Vec<_>>(),
|
||||
vec![0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
|
||||
);
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
struct Rgb(u8, u8, u8);
|
||||
|
||||
impl std::ops::Add for Rgb {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(
|
||||
((self.0 as u16 + rhs.0 as u16) / 2) as u8,
|
||||
((self.1 as u16 + rhs.1 as u16) / 2) as u8,
|
||||
((self.2 as u16 + rhs.2 as u16) / 2) as u8,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
fib(Rgb(255, 0, 100), Rgb(1, 128, 0))
|
||||
.take(20)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
Rgb(255, 0, 100),
|
||||
Rgb(1, 128, 0),
|
||||
Rgb(128, 64, 50),
|
||||
Rgb(64, 96, 25),
|
||||
Rgb(96, 80, 37),
|
||||
Rgb(80, 88, 31),
|
||||
Rgb(88, 84, 34),
|
||||
Rgb(84, 86, 32),
|
||||
Rgb(86, 85, 33),
|
||||
Rgb(85, 85, 32),
|
||||
Rgb(85, 85, 32),
|
||||
Rgb(85, 85, 32),
|
||||
Rgb(85, 85, 32),
|
||||
Rgb(85, 85, 32),
|
||||
Rgb(85, 85, 32),
|
||||
Rgb(85, 85, 32),
|
||||
Rgb(85, 85, 32),
|
||||
Rgb(85, 85, 32),
|
||||
Rgb(85, 85, 32),
|
||||
Rgb(85, 85, 32)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_iter() {
|
||||
let one_to_tens = vec![
|
||||
vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
||||
range(Endpoint::Inclusive(1), Endpoint::Inclusive(10), 1).collect(),
|
||||
range(Endpoint::Exclusive(0), Endpoint::Inclusive(10), 1).collect(),
|
||||
range(Endpoint::Inclusive(1), Endpoint::Exclusive(11), 1).collect(),
|
||||
range(Endpoint::Exclusive(0), Endpoint::Exclusive(11), 1).collect(),
|
||||
];
|
||||
assert!(one_to_tens.iter().all_equal());
|
||||
|
||||
let ten_to_ones = vec![
|
||||
vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 1],
|
||||
range(Endpoint::Inclusive(10), Endpoint::Inclusive(1), -1).collect(),
|
||||
range(Endpoint::Exclusive(11), Endpoint::Inclusive(1), -1).collect(),
|
||||
range(Endpoint::Inclusive(10), Endpoint::Exclusive(0), -1).collect(),
|
||||
range(Endpoint::Exclusive(11), Endpoint::Exclusive(0), -1).collect(),
|
||||
];
|
||||
assert!(ten_to_ones.iter().all_equal());
|
||||
|
||||
let five_evens = vec![
|
||||
vec![2, 4, 6, 8, 10],
|
||||
range(Endpoint::Inclusive(2), Endpoint::Inclusive(10), 2).collect(),
|
||||
range(Endpoint::Inclusive(2), Endpoint::Inclusive(11), 2).collect(),
|
||||
range(Endpoint::Exclusive(1), Endpoint::Inclusive(10), 2).collect(),
|
||||
range(Endpoint::Exclusive(1), Endpoint::Inclusive(11), 2).collect(),
|
||||
range(Endpoint::Inclusive(2), Endpoint::Exclusive(11), 2).collect(),
|
||||
range(Endpoint::Inclusive(2), Endpoint::Exclusive(12), 2).collect(),
|
||||
range(Endpoint::Exclusive(1), Endpoint::Exclusive(11), 2).collect(),
|
||||
range(Endpoint::Exclusive(1), Endpoint::Exclusive(12), 2).collect(),
|
||||
];
|
||||
assert!(five_evens.iter().all_equal());
|
||||
|
||||
let emptys = vec![
|
||||
vec![],
|
||||
range(Endpoint::Inclusive(2), Endpoint::Inclusive(10), -1).collect(),
|
||||
range(Endpoint::Inclusive(10), Endpoint::Inclusive(-100), 1).collect(),
|
||||
range(Endpoint::Inclusive(1), Endpoint::Exclusive(1), 1).collect(),
|
||||
];
|
||||
assert!(emptys.iter().all_equal());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_small() {
|
||||
assert_eq!(divisors(10).collect::<Vec<u64>>(), vec![1, 2, 5, 10]);
|
||||
|
||||
assert_eq!(divisors(17).collect::<Vec<u64>>(), vec![1, 17]);
|
||||
|
||||
assert_eq!(divisors(49).collect::<Vec<u64>>(), vec![1, 7, 49]);
|
||||
|
||||
assert_eq!(
|
||||
divisors(120).collect::<Vec<u64>>(),
|
||||
vec![1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 24, 30, 40, 60, 120]
|
||||
);
|
||||
|
||||
assert_eq!(divisors(1).collect::<Vec<u64>>(), vec![1]);
|
||||
|
||||
assert_eq!(divisors(2).collect::<Vec<u64>>(), vec![1, 2]);
|
||||
|
||||
assert_eq!(divisors(3).collect::<Vec<u64>>(), vec![1, 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_large() {
|
||||
assert_eq!(
|
||||
divisors(1_000_000_000_000_037).collect::<Vec<u64>>(),
|
||||
vec![1, 1_000_000_000_000_037]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
divisors(99_999_820_000_081).collect::<Vec<u64>>(),
|
||||
vec![1, 9_999_991, 99_999_820_000_081]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
divisors(1_234_567_890_123).collect::<Vec<u64>>(),
|
||||
vec![
|
||||
1,
|
||||
3,
|
||||
3_541,
|
||||
10_623,
|
||||
116_216_501,
|
||||
348_649_503,
|
||||
411_522_630_041,
|
||||
1_234_567_890_123
|
||||
]
|
||||
);
|
||||
|
||||
assert_eq!(divisors(97_821_761_637_600).count(), 17280);
|
||||
}
|
||||
}
|
||||
95
src/assignments/assignment07/transform.rs
Normal file
95
src/assignments/assignment07/transform.rs
Normal file
@@ -0,0 +1,95 @@
|
||||
//! Tranformer
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Add;
|
||||
|
||||
/// Represents transformation of type `T`.
|
||||
pub trait Transform<T> {
|
||||
/// Transforms value.
|
||||
fn transform(&self, value: T) -> T;
|
||||
}
|
||||
|
||||
impl<T1, T2, Tr1: Transform<T1>, Tr2: Transform<T2>> Transform<(T1, T2)> for (Tr1, Tr2) {
|
||||
fn transform(&self, value: (T1, T2)) -> (T1, T2) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Identity transformation.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Identity;
|
||||
|
||||
impl<T> Transform<T> for Identity {
|
||||
fn transform(&self, value: T) -> T {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Custom transformation.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Custom<T, F: Fn(T) -> T> {
|
||||
f: F,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T, F: Fn(T) -> T> From<F> for Custom<T, F> {
|
||||
fn from(f: F) -> Self {
|
||||
Self {
|
||||
f,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F: Fn(T) -> T> Transform<T> for Custom<T, F> {
|
||||
fn transform(&self, value: T) -> T {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Repeats transformation for `n` times.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Repeat<T, Tr: Transform<T>> {
|
||||
inner: Tr,
|
||||
n: u32,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T, Tr: Transform<T>> Repeat<T, Tr> {
|
||||
/// Creates a new repeat transformation.
|
||||
pub fn new(inner: Tr, n: u32) -> Self {
|
||||
Repeat {
|
||||
inner,
|
||||
n,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Tr: Transform<T>> Transform<T> for Repeat<T, Tr> {
|
||||
fn transform(&self, mut value: T) -> T {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Repeats transformation until converges.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct RepeatUntilConverge<T: Eq, Tr: Transform<T>> {
|
||||
inner: Tr,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Clone + Eq, Tr: Transform<T>> RepeatUntilConverge<T, Tr> {
|
||||
/// Creates a new repeat transformation.
|
||||
pub fn new(inner: Tr) -> Self {
|
||||
RepeatUntilConverge {
|
||||
inner,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Eq, Tr: Transform<T>> Transform<T> for RepeatUntilConverge<T, Tr> {
|
||||
fn transform(&self, mut value: T) -> T {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
62
src/assignments/assignment07/transform_grade.rs
Normal file
62
src/assignments/assignment07/transform_grade.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use itertools::Itertools;
|
||||
use ntest::assert_about_eq;
|
||||
|
||||
use super::super::transform::*;
|
||||
|
||||
#[test]
|
||||
fn test_transform_identity() {
|
||||
let tr = Identity;
|
||||
|
||||
assert_eq!(tr.transform(3), 3);
|
||||
assert_eq!(tr.transform(3.0), 3.0);
|
||||
assert_eq!(tr.transform("abc"), "abc");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_tuple() {
|
||||
let f1 = |x: u32| x + 1;
|
||||
let f2 = |x: String| x.clone() + &x;
|
||||
|
||||
let tr1: Custom<_, _> = f1.into();
|
||||
let tr2: Custom<_, _> = f2.into();
|
||||
|
||||
let list1 = 0u32..10u32;
|
||||
let list2 = ["a".to_string(), "bb".to_string(), "ccc".to_string()];
|
||||
|
||||
for v1 in list1 {
|
||||
for v2 in list2.clone() {
|
||||
let tr = (tr1, tr2.clone());
|
||||
let input = (v1, v2.clone());
|
||||
let expected = (f1(v1), f2(v2));
|
||||
assert_eq!(tr.transform(input), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_repeat() {
|
||||
let inc = Custom::from(|x: i32| x + 1);
|
||||
let dec = Custom::from(|x: i32| x - 1);
|
||||
|
||||
for i in 0..10 {
|
||||
for j in -10..10 {
|
||||
assert_eq!(Repeat::new(inc, i as u32).transform(j), j + i);
|
||||
assert_eq!(Repeat::new(dec, i as u32).transform(j), j - i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_repeat_until_converge() {
|
||||
let inc = Custom::from(|x: i32| if x < 50 { x + 1 } else { x });
|
||||
let dec = Custom::from(|x: i32| if x > 50 { x - 1 } else { x });
|
||||
|
||||
assert_eq!(RepeatUntilConverge::new(inc).transform(40), 50);
|
||||
assert_eq!(RepeatUntilConverge::new(inc).transform(60), 60);
|
||||
|
||||
assert_eq!(RepeatUntilConverge::new(dec).transform(40), 40);
|
||||
assert_eq!(RepeatUntilConverge::new(dec).transform(60), 50);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user