mirror of
https://github.com/kmc7468/cs220.git
synced 2025-12-12 21:08:45 +00:00
Merge branch 'main' into 'main'
# Conflicts: # scripts/grade-12.sh
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -227,6 +227,7 @@ dependencies = [
|
||||
"num-traits",
|
||||
"pest",
|
||||
"pest_derive",
|
||||
"rand",
|
||||
"rayon",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
@@ -20,3 +20,4 @@ approx = "0.5.1"
|
||||
num-traits = "0.2"
|
||||
ndarray = "0.15.0"
|
||||
ndarray-rand = "0.14.0"
|
||||
rand = "0.8.5"
|
||||
|
||||
@@ -9,12 +9,12 @@ BASEDIR=$(dirname "$0")
|
||||
source $BASEDIR/grade-utils.sh
|
||||
|
||||
RUNNERS=(
|
||||
"cargo"
|
||||
"cargo --release"
|
||||
"cargo_asan"
|
||||
"cargo_asan --release"
|
||||
"cargo_tsan"
|
||||
"cargo_tsan --release"
|
||||
"cargo"
|
||||
"cargo --release"
|
||||
"cargo_asan"
|
||||
"cargo_asan --release"
|
||||
"cargo_tsan"
|
||||
"cargo_tsan --release"
|
||||
)
|
||||
|
||||
# Lints.
|
||||
@@ -22,12 +22,12 @@ run_linters || exit 1
|
||||
|
||||
# Executes test for each runner.
|
||||
for RUNNER in "${RUNNERS[@]}"; do
|
||||
echo "Running with $RUNNER..."
|
||||
echo "Running with $RUNNER..."
|
||||
|
||||
TESTS=("--lib assignment06_grade")
|
||||
if [ $(run_tests) -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
TESTS=("--lib assignment06")
|
||||
if [ $(run_tests) -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -9,12 +9,12 @@ BASEDIR=$(dirname "$0")
|
||||
source $BASEDIR/grade-utils.sh
|
||||
|
||||
RUNNERS=(
|
||||
"cargo"
|
||||
"cargo --release"
|
||||
"cargo_asan"
|
||||
"cargo_asan --release"
|
||||
"cargo_tsan"
|
||||
"cargo_tsan --release"
|
||||
"cargo"
|
||||
"cargo --release"
|
||||
"cargo_asan"
|
||||
"cargo_asan --release"
|
||||
"cargo_tsan"
|
||||
"cargo_tsan --release"
|
||||
)
|
||||
|
||||
# Lints.
|
||||
@@ -22,12 +22,12 @@ run_linters || exit 1
|
||||
|
||||
# Executes test for each runner.
|
||||
for RUNNER in "${RUNNERS[@]}"; do
|
||||
echo "Running with $RUNNER..."
|
||||
echo "Running with $RUNNER..."
|
||||
|
||||
TESTS=("--lib assignment07_grade")
|
||||
if [ $(run_tests) -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
TESTS=("--lib assignment07")
|
||||
if [ $(run_tests) -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -9,12 +9,12 @@ BASEDIR=$(dirname "$0")
|
||||
source $BASEDIR/grade-utils.sh
|
||||
|
||||
RUNNERS=(
|
||||
"cargo"
|
||||
"cargo --release"
|
||||
"cargo_asan"
|
||||
"cargo_asan --release"
|
||||
"cargo_tsan"
|
||||
"cargo_tsan --release"
|
||||
"cargo"
|
||||
"cargo --release"
|
||||
"cargo_asan"
|
||||
"cargo_asan --release"
|
||||
"cargo_tsan"
|
||||
"cargo_tsan --release"
|
||||
)
|
||||
|
||||
# Lints.
|
||||
@@ -22,12 +22,12 @@ run_linters || exit 1
|
||||
|
||||
# Executes test for each runner.
|
||||
for RUNNER in "${RUNNERS[@]}"; do
|
||||
echo "Running with $RUNNER..."
|
||||
echo "Running with $RUNNER..."
|
||||
|
||||
TESTS=("--lib assignment09_grade")
|
||||
if [ $(run_tests) -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
TESTS=("--lib assignment09")
|
||||
if [ $(run_tests) -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -9,12 +9,12 @@ BASEDIR=$(dirname "$0")
|
||||
source $BASEDIR/grade-utils.sh
|
||||
|
||||
RUNNERS=(
|
||||
"cargo"
|
||||
"cargo --release"
|
||||
"cargo_asan"
|
||||
"cargo_asan --release"
|
||||
"cargo_tsan"
|
||||
"cargo_tsan --release"
|
||||
"cargo"
|
||||
"cargo --release"
|
||||
"cargo_asan"
|
||||
"cargo_asan --release"
|
||||
"cargo_tsan"
|
||||
"cargo_tsan --release"
|
||||
)
|
||||
|
||||
# Lints.
|
||||
@@ -22,12 +22,12 @@ run_linters || exit 1
|
||||
|
||||
# Executes test for each runner.
|
||||
for RUNNER in "${RUNNERS[@]}"; do
|
||||
echo "Running with $RUNNER..."
|
||||
echo "Running with $RUNNER..."
|
||||
|
||||
TESTS=("--lib assignment10_grade")
|
||||
if [ $(run_tests) -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
TESTS=("--lib assignment10")
|
||||
if [ $(run_tests) -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -24,7 +24,7 @@ run_linters || exit 1
|
||||
for RUNNER in "${RUNNERS[@]}"; do
|
||||
echo "Running with $RUNNER..."
|
||||
|
||||
TESTS=("--lib assignment11")
|
||||
TESTS=("--lib assignment11_grade")
|
||||
if [ $(run_tests) -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
16
src/assignments/assignment06/mod.rs
Normal file
16
src/assignments/assignment06/mod.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
//! Assignment 6: Mastering advanced types (1/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-06.sh` works fine.
|
||||
//! See `assignment06_grade.rs` and `/scripts/grade-06.sh` for the test script.
|
||||
|
||||
use std::{collections::HashMap, fmt::Debug};
|
||||
|
||||
pub mod semiring;
|
||||
pub mod square_matrix;
|
||||
pub mod symbolic_differentiation;
|
||||
|
||||
mod semiring_grade;
|
||||
mod square_matrix_grade;
|
||||
mod symbolic_differentiation_grade;
|
||||
@@ -1,9 +1,4 @@
|
||||
//! Assignment 6: Mastering advanced types (1/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-06.sh` works fine.
|
||||
//! See `assignment06_grade.rs` and `/scripts/grade-06.sh` for the test script.
|
||||
//! Semiring
|
||||
|
||||
use std::{collections::HashMap, fmt::Debug};
|
||||
|
||||
@@ -123,12 +118,6 @@ impl<C: Semiring> Semiring for Polynomial<C> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Semiring> From<C> for Polynomial<C> {
|
||||
fn from(value: C) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Semiring> Polynomial<C> {
|
||||
/// Constructs polynomial `x`.
|
||||
pub fn x() -> Self {
|
||||
@@ -139,4 +128,41 @@ impl<C: Semiring> Polynomial<C> {
|
||||
pub fn eval(&self, value: C) -> C {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Constructs polynomial `ax^n`.
|
||||
pub fn term(a: C, n: u64) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Semiring> From<C> for Polynomial<C> {
|
||||
fn from(value: C) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a string `s`, parse it into a `Polynomial<C>`.
|
||||
/// You may assume that `s` follows the criteria below.
|
||||
/// Therefore, you do not have to return `Err`.
|
||||
///
|
||||
/// Assumptions:
|
||||
/// - Each term is separated by ` + `.
|
||||
/// - Each term is one of the following form:
|
||||
/// `a`, `x`, `ax`, `x^n`, and `ax^n`,
|
||||
/// where `a` is a `usize` number and `n` is a `u64` number.
|
||||
/// This `a` should then be converted to a `C` type.
|
||||
/// - In `a`, it is guaranteed that `a >= 1`.
|
||||
/// - In `ax` and `ax^n`, it is guaranteed that `a >= 2`.
|
||||
/// - In `x^n` and `ax^n`, it is guaranteed that `n >= 2`.
|
||||
/// - All terms have unique degrees.
|
||||
///
|
||||
/// Consult `assignment06_jaemin_choi_grade.rs` for example valid strings.
|
||||
///
|
||||
/// Hint: `.split`, `.parse`, and `Polynomial::term`
|
||||
impl<C: Semiring> std::str::FromStr for Polynomial<C> {
|
||||
type Err = (); // Ignore this for now...
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,14 @@
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::super::assignment06::*;
|
||||
use super::super::semiring::*;
|
||||
use ntest::assert_about_eq;
|
||||
|
||||
fn test_from_str(s: &str, f: impl Fn(i64) -> i64) {
|
||||
let poly = s.parse::<Polynomial<i64>>().unwrap();
|
||||
for i in 0..10 {
|
||||
assert_eq!(poly.eval(i), f(i));
|
||||
}
|
||||
}
|
||||
|
||||
fn test_polynomial<T: Semiring>() {
|
||||
// x^2 + 5x + 6
|
||||
@@ -21,6 +29,43 @@ mod test {
|
||||
assert_eq!(value, from_usize(13 * 13 + 5 * 13 + 6));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_123() {
|
||||
test_from_str("123", |x| 123);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_x() {
|
||||
test_from_str("x", |x| x);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_24x() {
|
||||
test_from_str("24x", |x| 24 * x);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_2x_3() {
|
||||
test_from_str("2x + 3", |x| 2 * x + 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_x3() {
|
||||
test_from_str("x^3", |x| x * x * x);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_2x3_3x2_5x_12() {
|
||||
test_from_str("2x^3 + 3x^2 + 5x + 12", |x| {
|
||||
2 * x * x * x + 3 * x * x + 5 * x + 12
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_x5_1() {
|
||||
test_from_str("x^5 + 1", |x| x * x * x * x * x + 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_polynomial_u64() {
|
||||
test_polynomial::<u64>();
|
||||
88
src/assignments/assignment06/square_matrix.rs
Normal file
88
src/assignments/assignment06/square_matrix.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
//! Square matrix
|
||||
|
||||
/// Square matrix
|
||||
pub trait SquareMatrix {
|
||||
/// The type of the submatrix of this square matrix.
|
||||
/// For example, the submatrix of a 3 x 3 matrix is a 2 x 2 matrix.
|
||||
/// https://en.wikipedia.org/wiki/Matrix_(mathematics)#Submatrix
|
||||
type Submatrix;
|
||||
|
||||
/// Returns the submatrix obtained by removing the `row`th row and `col`th column
|
||||
/// from the original matrix.
|
||||
/// https://en.wikipedia.org/wiki/Matrix_(mathematics)#Submatrix
|
||||
fn sub_matrix(&self, row: usize, col: usize) -> Self::Submatrix;
|
||||
|
||||
/// Returns the determinant of the matrix.
|
||||
fn det(&self) -> i64;
|
||||
|
||||
/// Returns the determinant of ab, where a is self, b is given, and ab is the matrix product of them.
|
||||
/// Note that the size of a and b are the same.
|
||||
/// Hint: Use the fact that det(ab) = det(a) * det(b)
|
||||
/// https://en.wikipedia.org/wiki/Determinant#Multiplicativity_and_matrix_groups
|
||||
fn det_ab(&self, b: &Self) -> i64 {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// 2 x 2 matrix
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Mat2 {
|
||||
/// inner is a 2 dimensional array (size: 2 x 2)
|
||||
pub inner: [[i64; 2]; 2],
|
||||
}
|
||||
|
||||
impl SquareMatrix for Mat2 {
|
||||
type Submatrix = i64;
|
||||
|
||||
fn sub_matrix(&self, row: usize, col: usize) -> Self::Submatrix {
|
||||
// Hint: The submatrix of a 2 x 2 matrix is simply a single number.
|
||||
todo!()
|
||||
}
|
||||
|
||||
// Hint: https://en.wikipedia.org/wiki/Determinant
|
||||
fn det(&self) -> i64 {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// 3 x 3 matrix
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Mat3 {
|
||||
/// inner is a 2 dimensional array (size: 3 x 3)
|
||||
pub inner: [[i64; 3]; 3],
|
||||
}
|
||||
|
||||
impl SquareMatrix for Mat3 {
|
||||
type Submatrix = Mat2;
|
||||
|
||||
fn sub_matrix(&self, row: usize, col: usize) -> Self::Submatrix {
|
||||
todo!()
|
||||
}
|
||||
|
||||
// Hint: Use the determinant of the sub-matrices.
|
||||
// https://semath.info/src/determinant-three-by-three.html
|
||||
fn det(&self) -> i64 {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// 4 x 4 matrix
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Mat4 {
|
||||
/// inner is a 2 dimensional array (size: 4 x 4)
|
||||
pub inner: [[i64; 4]; 4],
|
||||
}
|
||||
|
||||
impl SquareMatrix for Mat4 {
|
||||
type Submatrix = Mat3;
|
||||
|
||||
fn sub_matrix(&self, row: usize, col: usize) -> Self::Submatrix {
|
||||
todo!()
|
||||
}
|
||||
|
||||
// Hint: Use the determinant of the sub-matrices.
|
||||
// https://semath.info/src/determinant-four-by-four.html
|
||||
fn det(&self) -> i64 {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
72
src/assignments/assignment06/square_matrix_grade.rs
Normal file
72
src/assignments/assignment06/square_matrix_grade.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::super::square_matrix::*;
|
||||
use ntest::assert_about_eq;
|
||||
|
||||
#[test]
|
||||
fn test_mat2() {
|
||||
let mat = Mat2 {
|
||||
inner: [[1, 2], [3, 4]],
|
||||
};
|
||||
assert_eq!(mat.sub_matrix(1, 1), 4);
|
||||
assert_eq!(mat.sub_matrix(1, 2), 3);
|
||||
assert_eq!(mat.sub_matrix(2, 1), 2);
|
||||
assert_eq!(mat.sub_matrix(2, 2), 1);
|
||||
assert_eq!(mat.det(), -2);
|
||||
|
||||
let mat2 = Mat2 {
|
||||
inner: [[2, 3], [5, 7]],
|
||||
};
|
||||
assert_eq!(mat.det_ab(&mat2), mat.det() * mat2.det());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mat3() {
|
||||
let mat = Mat3 {
|
||||
inner: [[1, 2, 3], [5, 5, 6], [7, 8, 10]],
|
||||
};
|
||||
assert_eq!(
|
||||
mat.sub_matrix(1, 2),
|
||||
Mat2 {
|
||||
inner: [[5, 6], [7, 10]]
|
||||
}
|
||||
);
|
||||
assert_eq!(mat.det(), 1);
|
||||
|
||||
let mat2 = Mat3 {
|
||||
inner: [[2, 3, 5], [7, 10, 11], [12, 14, 20]],
|
||||
};
|
||||
assert_eq!(mat2.det(), -42);
|
||||
assert_eq!(mat.det_ab(&mat2), mat.det() * mat2.det());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mat4() {
|
||||
let mat = Mat4 {
|
||||
inner: [
|
||||
[1, 11, 3, 4],
|
||||
[5, 6, 7, 9],
|
||||
[25, 10, 11, 20],
|
||||
[36, 14, 15, 30],
|
||||
],
|
||||
};
|
||||
assert_eq!(
|
||||
mat.sub_matrix(2, 3),
|
||||
Mat3 {
|
||||
inner: [[1, 11, 4], [25, 10, 20], [36, 14, 30]]
|
||||
}
|
||||
);
|
||||
assert_eq!(mat.det(), 2089);
|
||||
|
||||
let mat2 = Mat4 {
|
||||
inner: [
|
||||
[2, 3, 5, 5],
|
||||
[7, 10, 11, 20],
|
||||
[12, 14, 20, 30],
|
||||
[1, 2, 5, 10],
|
||||
],
|
||||
};
|
||||
assert_eq!(mat2.det(), -340);
|
||||
assert_eq!(mat.det_ab(&mat2), mat.det() * mat2.det());
|
||||
}
|
||||
}
|
||||
360
src/assignments/assignment06/symbolic_differentiation.rs
Normal file
360
src/assignments/assignment06/symbolic_differentiation.rs
Normal file
@@ -0,0 +1,360 @@
|
||||
//! Symbolic differentiation with rational coefficents.
|
||||
|
||||
use std::fmt;
|
||||
use std::ops::*;
|
||||
|
||||
/// Rational number represented by two isize, numerator and denominator.
|
||||
///
|
||||
/// Each Rational number should be normalized so that `demoninator` is nonnegative and `numerator` and `demoninator` are coprime.
|
||||
/// See [`normalize`] for examples. As a corner case, 0 is represented by Rational { numerator: 0, demoninator: 0 }.
|
||||
///
|
||||
/// For "natural use", Rational also overloads standard arithmetic operations, i.e, `+`, `-`, `*`, `/`.
|
||||
///
|
||||
/// See [here](https://doc.rust-lang.org/core/ops/index.html) for details.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Rational {
|
||||
numerator: isize,
|
||||
denominator: isize,
|
||||
}
|
||||
|
||||
// Some useful constants.
|
||||
|
||||
/// Zero
|
||||
pub const ZERO: Rational = Rational::new(0, 0);
|
||||
/// One
|
||||
pub const ONE: Rational = Rational::new(1, 1);
|
||||
/// Minus one
|
||||
pub const MINUS_ONE: Rational = Rational::new(-1, 1);
|
||||
|
||||
impl Rational {
|
||||
/// Creates a new rational number.
|
||||
pub const fn new(numerator: isize, denominator: isize) -> Self {
|
||||
Self {
|
||||
numerator,
|
||||
denominator,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Rational {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul for Rational {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Rational {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Div for Rational {
|
||||
type Output = Self;
|
||||
|
||||
fn div(self, rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Differentiable functions.
|
||||
///
|
||||
/// For simplicity, we only consider infinitely differentiable functions.
|
||||
pub trait Differentiable: Clone {
|
||||
/// Differentiate.
|
||||
///
|
||||
/// Since the return type is `Self`, this trait can only be implemented
|
||||
/// for types that are closed under differentiation.
|
||||
fn diff(&self) -> Self;
|
||||
}
|
||||
|
||||
impl Differentiable for Rational {
|
||||
fn diff(&self) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Singleton polynomial.
|
||||
///
|
||||
/// Unlike regular polynomials, this type only represents a single term.
|
||||
/// The `Const` variant is included to make `Polynomial` closed under differentiation.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SingletonPolynomial {
|
||||
/// Constant polynomial.
|
||||
Const(Rational),
|
||||
/// Non-const polynomial.
|
||||
Polynomial {
|
||||
/// coefficent of polynomial. Must be non-zero.
|
||||
coeff: Rational,
|
||||
/// power of polynomial. Must be non-zero.
|
||||
power: Rational,
|
||||
},
|
||||
}
|
||||
|
||||
impl SingletonPolynomial {
|
||||
/// Creates a new const polynomial.
|
||||
pub fn new_c(r: Rational) -> Self {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Creates a new polynomial.
|
||||
pub fn new_poly(coeff: Rational, power: Rational) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Differentiable for SingletonPolynomial {
|
||||
fn diff(&self) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Expoential function.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Exp;
|
||||
|
||||
impl Exp {
|
||||
/// Creates a new exponential function.
|
||||
pub fn new() -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Exp {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Differentiable for Exp {
|
||||
fn diff(&self) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Trigonometric functions.
|
||||
///
|
||||
/// The trig fucntions carry their coefficents to be closed under differntiation.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Trignometric {
|
||||
/// Sine function.
|
||||
Sine {
|
||||
/// Coefficent
|
||||
coeff: Rational,
|
||||
},
|
||||
/// Sine function.
|
||||
Cosine {
|
||||
/// Coefficent
|
||||
coeff: Rational,
|
||||
},
|
||||
}
|
||||
|
||||
impl Trignometric {
|
||||
/// Creates a new sine function.
|
||||
pub fn new_sine(coeff: Rational) -> Self {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Creates a new cosine function.
|
||||
pub fn new_cosine(coeff: Rational) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Differentiable for Trignometric {
|
||||
fn diff(&self) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Basic functions
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum BaseFuncs {
|
||||
/// Constant
|
||||
Const(Rational),
|
||||
/// Polynomial
|
||||
Poly(SingletonPolynomial),
|
||||
/// Exponential
|
||||
Exp(Exp),
|
||||
/// Trignometirc
|
||||
Trig(Trignometric),
|
||||
}
|
||||
|
||||
impl Differentiable for BaseFuncs {
|
||||
fn diff(&self) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Complex functions.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ComplexFuncs<F> {
|
||||
/// Basic functions
|
||||
Func(F),
|
||||
/// Addition
|
||||
Add(Box<ComplexFuncs<F>>, Box<ComplexFuncs<F>>),
|
||||
/// Subtraction
|
||||
Sub(Box<ComplexFuncs<F>>, Box<ComplexFuncs<F>>),
|
||||
/// Multipliciation
|
||||
Mul(Box<ComplexFuncs<F>>, Box<ComplexFuncs<F>>),
|
||||
/// Division
|
||||
Div(Box<ComplexFuncs<F>>, Box<ComplexFuncs<F>>),
|
||||
/// Composition
|
||||
Comp(Box<ComplexFuncs<F>>, Box<ComplexFuncs<F>>),
|
||||
}
|
||||
|
||||
impl<F: Differentiable> Differentiable for Box<F> {
|
||||
fn diff(&self) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Differentiable> Differentiable for ComplexFuncs<F> {
|
||||
fn diff(&self) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Evaluate functions.
|
||||
pub trait Evaluate {
|
||||
/// Evaluate `self` at `x`.
|
||||
fn evaluate(&self, x: f64) -> f64;
|
||||
}
|
||||
|
||||
impl Evaluate for Rational {
|
||||
fn evaluate(&self, x: f64) -> f64 {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Evaluate for SingletonPolynomial {
|
||||
fn evaluate(&self, x: f64) -> f64 {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Evaluate for Exp {
|
||||
fn evaluate(&self, x: f64) -> f64 {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Evaluate for Trignometric {
|
||||
fn evaluate(&self, x: f64) -> f64 {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Evaluate for BaseFuncs {
|
||||
fn evaluate(&self, x: f64) -> f64 {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Evaluate> Evaluate for ComplexFuncs<F> {
|
||||
fn evaluate(&self, x: f64) -> f64 {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Rational {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if *self == ZERO {
|
||||
return write!(f, "0");
|
||||
} else if self.denominator == 1 {
|
||||
return write!(f, "{}", self.numerator);
|
||||
}
|
||||
write!(f, "{}/{}", self.numerator, self.denominator)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for SingletonPolynomial {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Const(r) => write!(f, "{r}"),
|
||||
Self::Polynomial { coeff, power } => {
|
||||
// coeff or power is zero
|
||||
if *coeff == ZERO {
|
||||
return write!(f, "0");
|
||||
} else if *power == ZERO {
|
||||
return write!(f, "{coeff}");
|
||||
}
|
||||
|
||||
// Standard form of px^q
|
||||
let coeff = if *coeff == ONE {
|
||||
"".to_string()
|
||||
} else if *coeff == MINUS_ONE {
|
||||
"-".to_string()
|
||||
} else {
|
||||
format!("({coeff})")
|
||||
};
|
||||
let var = if *power == ONE {
|
||||
"x".to_string()
|
||||
} else {
|
||||
format!("x^({power})")
|
||||
};
|
||||
write!(f, "{coeff}{var}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Exp {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "exp(x)")
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Trignometric {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let (func, coeff) = match self {
|
||||
Trignometric::Sine { coeff } => ("sin(x)", coeff),
|
||||
Trignometric::Cosine { coeff } => ("cos(x)", coeff),
|
||||
};
|
||||
|
||||
if *coeff == ZERO {
|
||||
write!(f, "0")
|
||||
} else if *coeff == ONE {
|
||||
write!(f, "{func}")
|
||||
} else if *coeff == MINUS_ONE {
|
||||
write!(f, "-{func}")
|
||||
} else {
|
||||
write!(f, "({coeff}){func}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for BaseFuncs {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Const(r) => write!(f, "{r}"),
|
||||
Self::Poly(p) => write!(f, "{p}"),
|
||||
Self::Exp(e) => write!(f, "{e}"),
|
||||
Self::Trig(t) => write!(f, "{t}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Differentiable + fmt::Display> fmt::Display for ComplexFuncs<F> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ComplexFuncs::Func(func) => write!(f, "{func}"),
|
||||
ComplexFuncs::Add(l, r) => write!(f, "({l} + {r})"),
|
||||
ComplexFuncs::Sub(l, r) => write!(f, "({l} - {r})"),
|
||||
ComplexFuncs::Mul(l, r) => write!(f, "({l} * {r})"),
|
||||
ComplexFuncs::Div(l, r) => write!(f, "({l} / {r})"),
|
||||
ComplexFuncs::Comp(l, r) => write!(f, "({l} ∘ {r})"),
|
||||
}
|
||||
}
|
||||
}
|
||||
216
src/assignments/assignment06/symbolic_differentiation_grade.rs
Normal file
216
src/assignments/assignment06/symbolic_differentiation_grade.rs
Normal file
@@ -0,0 +1,216 @@
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::super::symbolic_differentiation::*;
|
||||
use ntest::assert_about_eq;
|
||||
|
||||
// Constant rationals to use
|
||||
const TWO: Rational = Rational::new(2, 1);
|
||||
const FOUR: Rational = Rational::new(4, 1);
|
||||
const THIRD: Rational = Rational::new(1, 3);
|
||||
const FIVE_THIRD: Rational = Rational::new(5, 3);
|
||||
const TWO_SEVENTH: Rational = Rational::new(2, 7);
|
||||
|
||||
#[test]
|
||||
fn test_rational_simpl() {
|
||||
assert_eq!(format!("{}", Rational::new(1, 2)), "1/2".to_string());
|
||||
|
||||
assert_eq!(format!("{}", Rational::new(0, 0)), "0".to_string());
|
||||
|
||||
assert_eq!(format!("{}", Rational::new(1, 1)), "1".to_string());
|
||||
|
||||
assert_eq!(format!("{}", Rational::new(-3, 7)), "-3/7".to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rational_arithmetic() {
|
||||
assert_eq!(
|
||||
format!("{}", Rational::new(1, 4) + Rational::new(3, 4)),
|
||||
"1".to_string()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
format!("{}", Rational::new(1, 3) + Rational::new(1, 6)),
|
||||
"1/2".to_string()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
format!("{}", Rational::new(1, 5) - Rational::new(1, 2)),
|
||||
"-3/10".to_string()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
format!("{}", Rational::new(-5, 12) * Rational::new(6, 125)),
|
||||
"-1/50".to_string()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
format!("{}", Rational::new(-3, 4) / Rational::new(-7, 13)),
|
||||
"39/28".to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rational_arithmetic_long() {
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{}",
|
||||
Rational::new(1, 2) + Rational::new(1, 2) + Rational::new(1, 2)
|
||||
),
|
||||
"3/2".to_string()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{}",
|
||||
Rational::new(1, 2) - Rational::new(1, 4) + Rational::new(1, 5)
|
||||
),
|
||||
"9/20".to_string()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{}",
|
||||
Rational::new(1, 2)
|
||||
* Rational::new(1, 4)
|
||||
* Rational::new(1, 8)
|
||||
* Rational::new(1, 16)
|
||||
/ Rational::new(1, 1024)
|
||||
),
|
||||
"1".to_string()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{}",
|
||||
Rational::new(123, 798)
|
||||
+ Rational::new(684, 32) / (Rational::new(13, 44) - Rational::new(123, 4472))
|
||||
* Rational::new(1237, 2)
|
||||
),
|
||||
"12356494070/250439".to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_differentiate_simple() {
|
||||
// Constant
|
||||
assert_eq!(format!("{}", Rational::new(3, 2).diff()), "0".to_string());
|
||||
|
||||
// Polynomials
|
||||
assert_eq!(
|
||||
format!("{}", SingletonPolynomial::new_c(Rational::new(3, 1)).diff()),
|
||||
"0".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
format!("{}", SingletonPolynomial::new_poly(TWO, FOUR).diff()),
|
||||
"(8)x^(3)".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{}",
|
||||
SingletonPolynomial::new_poly(FIVE_THIRD, THIRD).diff()
|
||||
),
|
||||
"(5/9)x^(-2/3)".to_string()
|
||||
);
|
||||
|
||||
// Exponential
|
||||
assert_eq!(format!("{}", Exp::new().diff()), "exp(x)".to_string());
|
||||
|
||||
// Trigonometric
|
||||
assert_eq!(
|
||||
format!("{}", Trignometric::new_sine(ONE).diff()),
|
||||
"cos(x)".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
format!("{}", Trignometric::new_cosine(ONE).diff()),
|
||||
"-sin(x)".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
format!("{}", Trignometric::new_sine(FIVE_THIRD).diff()),
|
||||
"(5/3)cos(x)".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
format!("{}", Trignometric::new_cosine(TWO_SEVENTH).diff()),
|
||||
"(-2/7)sin(x)".to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_differentiate_complex() {
|
||||
type BF = BaseFuncs;
|
||||
type CF = ComplexFuncs<BF>;
|
||||
|
||||
// Unlike the above simple test, it is hard to state a canonical
|
||||
// form for derivative of more complex functions. Thus, we only test that the
|
||||
// derivative is correct at certain points.
|
||||
|
||||
// Add
|
||||
//
|
||||
// d/dx (2x^4 + exp(x)) = 8x^3 + exp(x)
|
||||
let f1 = SingletonPolynomial::new_poly(TWO, FOUR);
|
||||
let f2 = Exp::new();
|
||||
let deriv = CF::Add(
|
||||
Box::new(CF::Func(BF::Poly(f1))),
|
||||
Box::new(CF::Func(BF::Exp(f2))),
|
||||
)
|
||||
.diff();
|
||||
assert_about_eq!(deriv.evaluate(2.2), 94.2090134994f64);
|
||||
assert_about_eq!(deriv.evaluate(4.5), 819.017131301);
|
||||
|
||||
// Sub
|
||||
//
|
||||
// d/dx ((5/3)cos(x) - sin(x)) = (-5/3)sin(x) - cos(x)
|
||||
let f1 = Trignometric::new_cosine(FIVE_THIRD);
|
||||
let f2 = Trignometric::new_sine(ONE);
|
||||
let deriv = CF::Sub(
|
||||
Box::new(CF::Func(BF::Trig(f1))),
|
||||
Box::new(CF::Func(BF::Trig(f2))),
|
||||
)
|
||||
.diff();
|
||||
assert_about_eq!(deriv.evaluate(2.7), 0.191772341627);
|
||||
assert_about_eq!(deriv.evaluate(0.01), -1.01661638931);
|
||||
|
||||
// Mult
|
||||
//
|
||||
// d/dx (2x^4 * cos(x) * exp(x)) =
|
||||
// 8x^2 * cos(x) * exp(x) - 2x^4 * sin(x) * exp(x) + 2x^4 * cos(x) * exp(x)
|
||||
let f1 = SingletonPolynomial::new_poly(TWO, FOUR);
|
||||
let f2 = Trignometric::new_cosine(ONE);
|
||||
let f3 = Exp::new();
|
||||
let deriv = CF::Mul(
|
||||
Box::new(CF::Func(BF::Poly(f1))),
|
||||
Box::new(CF::Mul(
|
||||
Box::new(CF::Func(BF::Trig(f2))),
|
||||
Box::new(CF::Func(BF::Exp(f3))),
|
||||
)),
|
||||
)
|
||||
.diff();
|
||||
assert_about_eq!(deriv.evaluate(3.4), -14804.9016757);
|
||||
assert_about_eq!(deriv.evaluate(0.07), 0.00298352866);
|
||||
|
||||
// Div
|
||||
//
|
||||
// (d/dx) (sin(x)/cos(x)) = (cos(x)*cos(x) + sin(x)*sin(x)) / cos(x)*cos(x)
|
||||
let f1 = Trignometric::new_sine(ONE);
|
||||
let f2 = Trignometric::new_cosine(ONE);
|
||||
let deriv = CF::Div(
|
||||
Box::new(CF::Func(BF::Trig(f1))),
|
||||
Box::new(CF::Func(BF::Trig(f2))),
|
||||
)
|
||||
.diff();
|
||||
assert_about_eq!(deriv.evaluate(core::f64::consts::PI), 1f64);
|
||||
assert_about_eq!(deriv.evaluate(0f64), 1f64);
|
||||
|
||||
// Comp
|
||||
//
|
||||
// d/dx (cos(x^2)) = -2x * sin(x^2)
|
||||
let f1 = Trignometric::new_cosine(ONE);
|
||||
let f2 = SingletonPolynomial::new_poly(ONE, TWO);
|
||||
let deriv = CF::Comp(
|
||||
Box::new(CF::Func(BF::Trig(f1))),
|
||||
Box::new(CF::Func(BF::Poly(f2))),
|
||||
)
|
||||
.diff();
|
||||
assert_about_eq!(deriv.evaluate(2.714), -4.79392977);
|
||||
assert_about_eq!(deriv.evaluate(3.9), -3.72556973);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
//! 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.
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::super::assignment07::*;
|
||||
|
||||
#[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]
|
||||
);
|
||||
}
|
||||
}
|
||||
94
src/assignments/assignment09/bigint.rs
Normal file
94
src/assignments/assignment09/bigint.rs
Normal file
@@ -0,0 +1,94 @@
|
||||
//! Big integer with infinite precision.
|
||||
|
||||
use std::fmt;
|
||||
use std::{iter::zip, ops::*};
|
||||
|
||||
/// An signed integer with infinite precision implemented with an "carrier" vector of `u32`s.
|
||||
///
|
||||
/// The vector is interpreted as a base 2^(32 * (len(carrier) - 1)) integer, where negative
|
||||
/// integers are represented in their [2's complement form](https://en.wikipedia.org/wiki/Two%27s_complement).
|
||||
///
|
||||
/// For example, the vector `vec![44,345,3]` represents the integer
|
||||
/// `44 * (2^32)^2 + 345 * (2^32) + 3`,
|
||||
/// and the vector `vec![u32::MAX - 5, u32::MAX - 7]` represents the integer
|
||||
/// `- (5 * 2^32 + 8)
|
||||
///
|
||||
/// You will implement the `Add` and `Sub` trait for this type.
|
||||
///
|
||||
/// Unlike standard fix-sized intergers in Rust where overflow will panic, the carrier is extended to save the overflowed bit.
|
||||
/// On the contrary, if the precision is too much (e.g, vec![0,0] is used to represent 0, where `vec![0]` is sufficent), the carrier is truncated.
|
||||
///
|
||||
/// See [this section](https://en.wikipedia.org/wiki/Two%27s_complement#Arithmetic_operations) for a rouge guide on implementation,
|
||||
/// while keeping in mind that the carrier should be extended to deal with overflow.
|
||||
///
|
||||
/// The `sign_extension()`, `two_complement()`, and `truncate()` are non-mandatory helper methods.
|
||||
///
|
||||
/// For testing and debugging pruposes, the `Display` trait is implemented for you, which shows the integer in hexadecimal form.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BigInt {
|
||||
/// The carrier for `BigInt`.
|
||||
///
|
||||
/// Note that the carrier should always be non-empty.
|
||||
pub carrier: Vec<u32>,
|
||||
}
|
||||
|
||||
impl BigInt {
|
||||
/// Create a new `BigInt` from a `usize`.
|
||||
pub fn new(n: u32) -> Self {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Creates a new `BigInt` from a `Vec<u32>`.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// Panics if `carrier` is empty.
|
||||
pub fn new_large(carrier: Vec<u32>) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
const SIGN_MASK: u32 = 1 << 31;
|
||||
|
||||
impl BigInt {
|
||||
/// Extend `self` to `len` bits.
|
||||
fn sign_extension(&self, len: usize) -> Self {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Compute the two's complement of `self`.
|
||||
fn two_complement(&self) -> Self {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Truncate a `BigInt` to the minimum length.
|
||||
fn truncate(&self) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for BigInt {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for BigInt {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for BigInt {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// Hex formatting so that each u32 can be formatted independently.
|
||||
for i in self.carrier.iter() {
|
||||
write!(f, "{:08x}", i)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
104
src/assignments/assignment09/bigint_grade.rs
Normal file
104
src/assignments/assignment09/bigint_grade.rs
Normal file
@@ -0,0 +1,104 @@
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use ntest::{assert_false, assert_true};
|
||||
|
||||
use super::super::bigint::*;
|
||||
|
||||
#[test]
|
||||
fn test_inf_prec_simple() {
|
||||
// Basic
|
||||
assert_eq!("00000000", format!("{}", BigInt::new(0)));
|
||||
assert_eq!("ffffffff", format!("{}", BigInt::new(u32::MAX)));
|
||||
assert_eq!("00bc4fdc", format!("{}", BigInt::new(12_341_212)));
|
||||
assert_eq!("fffffed8", format!("{}", BigInt::new(4_294_967_000u32)));
|
||||
|
||||
// Add Basic
|
||||
assert_eq!("00000001", format!("{}", BigInt::new(0) + BigInt::new(1)));
|
||||
|
||||
assert_eq!(
|
||||
"0df655df",
|
||||
format!("{}", BigInt::new(13_413) + BigInt::new(234_234_234))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
"ffffff03",
|
||||
format!("{}", BigInt::new(4_294_967_000u32) + BigInt::new(43))
|
||||
);
|
||||
|
||||
// Sub Basic
|
||||
assert_eq!("ffffffff", format!("{}", BigInt::new(0) - BigInt::new(1)));
|
||||
|
||||
assert_eq!(
|
||||
"f20a12eb",
|
||||
format!("{}", BigInt::new(13_413) - BigInt::new(234_234_234))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
"fffffead",
|
||||
format!("{}", BigInt::new(4_294_967_000u32) - BigInt::new(43))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_inf_prec_panic() {
|
||||
let _ = BigInt::new_large(vec![]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inf_prec_complex() {
|
||||
// Positive overflow
|
||||
assert_eq!(
|
||||
"0000000080000000",
|
||||
format!("{}", BigInt::new(i32::MAX as u32) + BigInt::new(1))
|
||||
);
|
||||
|
||||
// Negative overflow
|
||||
assert_eq!(
|
||||
"ffffffff7fffffff",
|
||||
format!("{}", BigInt::new(i32::MIN as u32) - BigInt::new(1))
|
||||
);
|
||||
|
||||
// Larger positive overflow
|
||||
assert_eq!(
|
||||
"00000000fffffffe00000000",
|
||||
format!(
|
||||
"{}",
|
||||
BigInt::new_large(vec![i32::MAX as u32, 0])
|
||||
+ BigInt::new_large(vec![i32::MAX as u32, 0])
|
||||
)
|
||||
);
|
||||
|
||||
// Smaller negative overflow
|
||||
assert_eq!(
|
||||
"ffffffff000000000119464a",
|
||||
format!(
|
||||
"{}",
|
||||
BigInt::new_large(vec![i32::MIN as u32, 2_871_572])
|
||||
+ BigInt::new_large(vec![i32::MIN as u32, 15_562_038])
|
||||
)
|
||||
);
|
||||
|
||||
// Truncate
|
||||
assert_eq!(
|
||||
"00000000",
|
||||
format!(
|
||||
"{}",
|
||||
BigInt::new_large(vec![i32::MIN as u32, 2_871_572, 123_456])
|
||||
- BigInt::new_large(vec![i32::MIN as u32, 2_871_572, 123_456])
|
||||
)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
"ffffffff",
|
||||
format!(
|
||||
"{}",
|
||||
BigInt::new_large(vec![i32::MIN as u32, 2_871_572, 123_456])
|
||||
- BigInt::new_large(vec![i32::MIN as u32, 2_871_572, 123_457])
|
||||
)
|
||||
);
|
||||
|
||||
// TODO: add a test case testing sign extension.
|
||||
}
|
||||
}
|
||||
12
src/assignments/assignment09/mod.rs
Normal file
12
src/assignments/assignment09/mod.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
//! Assignment 9: Iterators (1/2).
|
||||
//!
|
||||
//! The primary goal of this assignment is to get used to iterators.
|
||||
//!
|
||||
//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-09.sh` works fine.
|
||||
//! See `assignment09_grade.rs` and `/scripts/grade-09.sh` for the test script.
|
||||
|
||||
pub mod bigint;
|
||||
pub mod small_exercises;
|
||||
|
||||
mod bigint_grade;
|
||||
mod small_exercises_grade;
|
||||
@@ -1,14 +1,7 @@
|
||||
//! Assignment 9: Iterators (1/2).
|
||||
//!
|
||||
//! The primary goal of this assignment is to get used to iterators.
|
||||
//!
|
||||
//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-09.sh` works fine.
|
||||
//! See `assignment09_grade.rs` and `/scripts/grade-09.sh` for the test script.
|
||||
//! Small exercises.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use itertools::*;
|
||||
|
||||
/// Returns whether the given sequence is a fibonacci sequence starts from the given sequence's first two terms.
|
||||
///
|
||||
/// Returns `true` if the length of sequence is less or equal than 2.
|
||||
@@ -61,6 +54,27 @@ pub fn interleave3<T>(
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Alternate elements from array of n iterators until they have run out.
|
||||
///
|
||||
/// You can assume that the number of elements of iterators are same.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use cs220::assignments::assignment09::interleave_n;
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// interleave_n(&mut [[1, 2].into_iter(), [3, 4].into_iter(), [5, 6].into_iter()]),
|
||||
/// vec![1, 3, 5, 2, 4, 6]
|
||||
/// );
|
||||
/// ```
|
||||
pub fn interleave_n<T, const N: usize>(
|
||||
mut iters: [impl Iterator<Item = T>; N],
|
||||
) -> impl Iterator<Item = T> {
|
||||
todo!();
|
||||
std::iter::empty()
|
||||
}
|
||||
|
||||
/// Returns mean of k smallest value's mean.
|
||||
///
|
||||
/// # Example
|
||||
@@ -172,3 +186,26 @@ pub fn find_count_n(inner: Vec<usize>, n: usize) -> Vec<usize> {
|
||||
pub fn position_median<T: Ord>(inner: Vec<T>) -> Option<usize> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Returns the sum of all elements in a two-dimensional array.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// assert_eq!(
|
||||
/// two_dimensional_sum([[1, 2, 3].into_iter(), [4, 5, 6].into_iter()].into_iter()),
|
||||
/// 21
|
||||
/// );
|
||||
/// ```
|
||||
pub fn two_dimensional_sum(inner: impl Iterator<Item = impl Iterator<Item = i64>>) -> i64 {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Returns whether the given string is palindrome or not.
|
||||
///
|
||||
/// A palindrome is a word, number, phrase, or other sequence of characters which reads the same backward as forward.
|
||||
/// We consider the empty string is palindrome.
|
||||
///
|
||||
/// Consult <https://en.wikipedia.org/wiki/Palindrome>.
|
||||
pub fn is_palindrome(s: String) -> bool {
|
||||
todo!()
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::super::assignment09::*;
|
||||
|
||||
use ntest::{assert_false, assert_true};
|
||||
|
||||
use super::super::small_exercises::*;
|
||||
|
||||
#[test]
|
||||
fn test_is_fibonacci() {
|
||||
@@ -74,6 +77,35 @@ mod test {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_interleave_n() {
|
||||
assert_eq!(
|
||||
interleave_n([[1, 2].into_iter(), [3, 4].into_iter(), [5, 6].into_iter()])
|
||||
.collect::<Vec<_>>(),
|
||||
vec![1, 3, 5, 2, 4, 6]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
interleave_n([
|
||||
[1, 2, 3].into_iter(),
|
||||
[4, 5, 6].into_iter(),
|
||||
[7, 8, 9].into_iter()
|
||||
])
|
||||
.collect::<Vec<_>>(),
|
||||
vec![1, 4, 7, 2, 5, 8, 3, 6, 9]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
interleave_n([
|
||||
["a", "b", "c"].into_iter(),
|
||||
["d", "e", "f"].into_iter(),
|
||||
["g", "h", "i"].into_iter()
|
||||
])
|
||||
.collect::<String>(),
|
||||
"adgbehcfi"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_k_smallest_man() {
|
||||
assert_eq!(
|
||||
@@ -200,4 +232,37 @@ mod test {
|
||||
assert_eq!(position_median(vec![1, 3, 3, 6, 7, 8, 9]), Some(3));
|
||||
assert_eq!(position_median(vec![1, 2, 3, 4, 5, 6, 8, 9]), Some(4));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_two_dimensional_sum() {
|
||||
assert_eq!(
|
||||
two_dimensional_sum([[1, 2, 3].into_iter(), [4, 5, 6].into_iter()].into_iter()),
|
||||
21
|
||||
);
|
||||
assert_eq!(
|
||||
two_dimensional_sum(
|
||||
[
|
||||
[1, 2, 3, 4, 5].into_iter(),
|
||||
[10, 20, 30, 40, 50].into_iter()
|
||||
]
|
||||
.into_iter()
|
||||
),
|
||||
165
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_palindrome() {
|
||||
assert_true!(is_palindrome("kayak".to_string()));
|
||||
assert_true!(is_palindrome("dammitimmad".to_string()));
|
||||
assert_true!(is_palindrome("deified".to_string()));
|
||||
assert_true!(is_palindrome("rotator".to_string()));
|
||||
assert_true!(is_palindrome("noon".to_string()));
|
||||
assert_true!(is_palindrome("".to_string()));
|
||||
assert_true!(is_palindrome("a".to_string()));
|
||||
|
||||
assert_false!(is_palindrome("moon".to_string()));
|
||||
assert_false!(is_palindrome("hello".to_string()));
|
||||
assert_false!(is_palindrome("apple".to_string()));
|
||||
}
|
||||
}
|
||||
50
src/assignments/assignment10/labyrinth.rs
Normal file
50
src/assignments/assignment10/labyrinth.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
//! Labyrinth
|
||||
//!
|
||||
//! Look at the [test code](labyrinth_grade.rs) below before you start.
|
||||
//! HINT: https://en.wikipedia.org/wiki/100_prisoners_problem
|
||||
//!
|
||||
//! NOTE: You will have to implement a probabilistic algorithm, which means, the algorithm can fail
|
||||
//! even if you have implemented the solution. We recommend running multiple times (at least 5 times) to check your
|
||||
//! solution works well.
|
||||
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use std::cell::RefCell;
|
||||
|
||||
/// Husband
|
||||
#[derive(Debug)]
|
||||
pub struct Husband {
|
||||
brain: RefCell<[usize; 100]>,
|
||||
}
|
||||
|
||||
impl Husband {
|
||||
/// What might a husband, who is looking for his wife's ID my_wife, be thinking?
|
||||
pub fn seeking(my_wife: usize) -> Self {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn has_devised_a_strategy(&self) -> Strategy<'_> {
|
||||
Strategy { husband: self }
|
||||
}
|
||||
|
||||
/// Based on the information about currently visited room number and someone's wife ID trapped inside,
|
||||
/// what the husband should do next?
|
||||
pub fn carefully_checks_whos_inside(&self, room: usize, wife: usize) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Strategy of husband
|
||||
#[derive(Debug)]
|
||||
pub struct Strategy<'a> {
|
||||
husband: &'a Husband,
|
||||
}
|
||||
|
||||
impl Iterator for Strategy<'_> {
|
||||
type Item = usize;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
62
src/assignments/assignment10/labyrinth_grade.rs
Normal file
62
src/assignments/assignment10/labyrinth_grade.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
|
||||
use super::super::labyrinth::*;
|
||||
|
||||
type Wife = usize;
|
||||
type Rooms = Vec<Wife>;
|
||||
|
||||
struct Labyrinth {
|
||||
rooms: Rooms,
|
||||
}
|
||||
|
||||
impl From<Rooms> for Labyrinth {
|
||||
fn from(rooms: Rooms) -> Self {
|
||||
Self { rooms }
|
||||
}
|
||||
}
|
||||
|
||||
impl Labyrinth {
|
||||
fn open_the_door(&self, index: usize) -> Wife {
|
||||
self.rooms[index]
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_every_husband_rescue_his_wife() {
|
||||
// HINT: https://en.wikipedia.org/wiki/100_prisoners_problem
|
||||
const WIVES: usize = 100;
|
||||
|
||||
// One day, wives of 100 husbands were kidnapped by the Minotaur
|
||||
// and imprisoned in a labyrinth.... 🏰
|
||||
let labyrinth = Labyrinth::from({
|
||||
let mut rooms: Vec<_> = (0..WIVES).collect();
|
||||
rooms.shuffle(&mut thread_rng());
|
||||
rooms
|
||||
});
|
||||
|
||||
assert!((0..WIVES).all(|his_wife| {
|
||||
// A new husband steps into the labyrinth to rescue his wife...!
|
||||
let husband = Box::new(Husband::seeking(his_wife /*👩*/));
|
||||
let strategy = Box::new(husband.has_devised_a_strategy());
|
||||
|
||||
#[allow(clippy::all)]
|
||||
/* The Minotaur🐂 will arrive in */
|
||||
(0..50) /* steps... */
|
||||
.zip(strategy)
|
||||
.find(|(_, room)| {
|
||||
// The husband contemplates his next move... 🤔
|
||||
// and finally,
|
||||
let someone/*👤*/ = labyrinth.open_the_door(*room); // 🚪
|
||||
husband.carefully_checks_whos_inside(*room, someone);
|
||||
|
||||
// Has the husband found his wife...?
|
||||
someone/*👤*/ == his_wife /*👩*/
|
||||
})
|
||||
.is_some(/* The husband has successfully rescued his wife! 👫*/)
|
||||
// or is_none(/* The unfortunate husband has encountered the Minotaur and... 🪓*/)
|
||||
}));
|
||||
}
|
||||
}
|
||||
12
src/assignments/assignment10/mod.rs
Normal file
12
src/assignments/assignment10/mod.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
//!
|
||||
//! Assignment 10: Iterators (2/2).
|
||||
//! The primary goal of this assignment is to get used to iterators.
|
||||
//!
|
||||
//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-10.sh` works fine.
|
||||
//! See `assignment10_grade.rs` and `/scripts/grade-10.sh` for the test script.
|
||||
|
||||
pub mod labyrinth;
|
||||
pub mod small_exercises;
|
||||
|
||||
mod labyrinth_grade;
|
||||
mod small_exercises_grade;
|
||||
@@ -1,10 +1,4 @@
|
||||
//! Assignment 10: Iterators (2/2).
|
||||
//!
|
||||
//! The primary goal of this assignment is to get used to iterators.
|
||||
//!
|
||||
//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-10.sh` works fine.
|
||||
//! See `assignment10_grade.rs` and `/scripts/grade-10.sh` for the test script.
|
||||
|
||||
//! Small exercises.
|
||||
use itertools::*;
|
||||
|
||||
/// Returns the pairs of `(i, j)` where `i < j` and `inner[i] > inner[j]` in increasing order.
|
||||
@@ -117,3 +111,83 @@ pub enum File {
|
||||
pub fn du_sort(root: &File) -> Vec<(&str, usize)> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Remove all even numbers inside a vector using the given mutable reference.
|
||||
/// That is, you must modify the vector using the given mutable reference instead
|
||||
/// of returning a new vector.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// let mut vec = vec![1, 2, 3, 4, 5];
|
||||
/// remove_even(&mut vec);
|
||||
/// assert_eq!(*vec, vec![1, 3, 5]);
|
||||
/// ```
|
||||
#[allow(clippy::ptr_arg)]
|
||||
pub fn remove_even(inner: &mut Vec<i64>) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Remove all duplicate occurences of a number inside the array.
|
||||
/// That is, if an integer appears more than once, remove some occurences
|
||||
/// of it so that it only appears once. Note that you must modify the vector
|
||||
/// using the given mutable reference instead of returning a new vector.
|
||||
/// Also, note that the order does not matter.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// let mut vec = vec![1, 2, 1, 1, 3, 7, 5, 7];
|
||||
/// remove_duplicate(&mut vec);
|
||||
/// assert_eq!(*vec, vec![1, 2, 3, 7, 5]);
|
||||
/// ```
|
||||
#[allow(clippy::ptr_arg)]
|
||||
pub fn remove_duplicate(inner: &mut Vec<i64>) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Returns the natural join of two tables using the first column as the join argument.
|
||||
/// That is, for each pair of a row(`Vec<String>`) from table1 and a row(`Vec<String>`) from table2,
|
||||
/// if the first element of them are equal, then add all elements of the row from table2
|
||||
/// except its first element to the row from table1 and add it to the results.
|
||||
/// Note that the order of results does not matter.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// table1 table2
|
||||
/// ---------------------- ----------------------
|
||||
/// 20230001 | Jack 20230001 | CS
|
||||
/// 20231234 | Mike 20230001 | EE
|
||||
/// 20231234 | ME
|
||||
///
|
||||
///
|
||||
/// result
|
||||
/// -----------------------------------
|
||||
/// 20230001 | Jack | CS
|
||||
/// 20230001 | Jack | EE
|
||||
/// 20231234 | Mike | ME
|
||||
///
|
||||
pub fn natural_join(table1: Vec<Vec<String>>, table2: Vec<Vec<String>>) -> Vec<Vec<String>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
struct Pythagorean;
|
||||
|
||||
impl Pythagorean {
|
||||
fn new() -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Pythagorean {
|
||||
type Item = (u64, u64, u64);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates sequence of unique [primitive Pythagorean
|
||||
/// triples](https://en.wikipedia.org/wiki/Pythagorean_triple), i.e. (a,b,c) such that a² + b² =
|
||||
/// c², a and b are coprimes, and a < b. Generate in the increasing order of c.
|
||||
pub fn pythagorean() -> impl Iterator<Item = (u64, u64, u64)> {
|
||||
Pythagorean::new()
|
||||
}
|
||||
351
src/assignments/assignment10/small_exercises_grade.rs
Normal file
351
src/assignments/assignment10/small_exercises_grade.rs
Normal file
@@ -0,0 +1,351 @@
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::collections::HashSet;
|
||||
|
||||
use super::super::small_exercises::*;
|
||||
|
||||
#[test]
|
||||
fn test_inversion() {
|
||||
assert_eq!(inversion(vec![3, 5, 4]), vec![(1, 2)]);
|
||||
assert_eq!(inversion(vec!["c", "a", "b", "d"]), vec![(0, 1), (0, 2)]);
|
||||
assert_eq!(
|
||||
inversion(vec![2, 5, 4, 6, 3, 1]),
|
||||
vec![
|
||||
(0, 5),
|
||||
(1, 2),
|
||||
(1, 4),
|
||||
(1, 5),
|
||||
(2, 4),
|
||||
(2, 5),
|
||||
(3, 4),
|
||||
(3, 5),
|
||||
(4, 5)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_traverse_preorder() {
|
||||
let root = Node::NonLeaf((
|
||||
1,
|
||||
vec![
|
||||
Node::NonLeaf((2, vec![Node::Leaf(5), Node::Leaf(6)])),
|
||||
Node::Leaf(3),
|
||||
Node::NonLeaf((4, vec![Node::Leaf(7), Node::Leaf(8), Node::Leaf(9)])),
|
||||
],
|
||||
));
|
||||
|
||||
assert_eq!(traverse_preorder(root), vec![1, 2, 5, 6, 3, 4, 7, 8, 9]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_du_sort() {
|
||||
let rootfile = File::Directory(
|
||||
"root".to_string(),
|
||||
vec![
|
||||
File::Directory(
|
||||
"a".to_string(),
|
||||
vec![
|
||||
File::Data("a1".to_string(), 1),
|
||||
File::Data("a2".to_string(), 3),
|
||||
],
|
||||
),
|
||||
File::Directory(
|
||||
"b".to_string(),
|
||||
vec![
|
||||
File::Data("b1".to_string(), 3),
|
||||
File::Data("b2".to_string(), 15),
|
||||
],
|
||||
),
|
||||
File::Data("c".to_string(), 8),
|
||||
],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
du_sort(&rootfile),
|
||||
vec![
|
||||
("a1", 1),
|
||||
("a2", 3),
|
||||
("b1", 3),
|
||||
("a", 4),
|
||||
("c", 8),
|
||||
("b2", 15),
|
||||
("b", 18),
|
||||
("root", 1 + 3 + 3 + 15 + 8)
|
||||
]
|
||||
);
|
||||
|
||||
let rootfile = File::Directory(
|
||||
"root".to_string(),
|
||||
vec![
|
||||
File::Directory(
|
||||
"b".to_string(),
|
||||
vec![
|
||||
File::Data("b1".to_string(), 3),
|
||||
File::Data("b2".to_string(), 15),
|
||||
],
|
||||
),
|
||||
File::Data("c".to_string(), 8),
|
||||
File::Directory(
|
||||
"a".to_string(),
|
||||
vec![
|
||||
File::Data("a1".to_string(), 1),
|
||||
File::Data("a2".to_string(), 3),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
du_sort(&rootfile),
|
||||
vec![
|
||||
("a1", 1),
|
||||
("a2", 3),
|
||||
("b1", 3),
|
||||
("a", 4),
|
||||
("c", 8),
|
||||
("b2", 15),
|
||||
("b", 18),
|
||||
("root", 1 + 3 + 3 + 15 + 8)
|
||||
]
|
||||
);
|
||||
|
||||
let rootfile = File::Directory(
|
||||
"root".to_string(),
|
||||
vec![
|
||||
File::Directory(
|
||||
"a".to_string(),
|
||||
vec![
|
||||
File::Data("a1".to_string(), 1),
|
||||
File::Data("a2".to_string(), 3),
|
||||
File::Directory(
|
||||
"a3".to_string(),
|
||||
vec![
|
||||
File::Data("a31".to_string(), 1),
|
||||
File::Data("a32".to_string(), 3),
|
||||
File::Data("a33".to_string(), 6),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
File::Directory(
|
||||
"b".to_string(),
|
||||
vec![
|
||||
File::Data("b1".to_string(), 3),
|
||||
File::Data("b2".to_string(), 15),
|
||||
],
|
||||
),
|
||||
File::Data("c".to_string(), 16),
|
||||
],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
du_sort(&rootfile),
|
||||
vec![
|
||||
("a1", 1),
|
||||
("a31", 1),
|
||||
("a2", 3),
|
||||
("a32", 3),
|
||||
("b1", 3),
|
||||
("a33", 6),
|
||||
("a3", 10),
|
||||
("a", 14),
|
||||
("b2", 15),
|
||||
("c", 16),
|
||||
("b", 18),
|
||||
("root", 48)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remove_even() {
|
||||
let mut vec = vec![1, 2, 3, 4, 5];
|
||||
remove_even(&mut vec);
|
||||
assert_eq!(*vec, vec![1, 3, 5]);
|
||||
|
||||
let mut vec = vec![11, 1000, 12, 101, 105, 104, 200];
|
||||
remove_even(&mut vec);
|
||||
assert_eq!(*vec, vec![11, 101, 105]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remove_duplicate() {
|
||||
let mut vec = vec![1, 2, 1, 1, 3, 7, 5, 7];
|
||||
remove_duplicate(&mut vec);
|
||||
|
||||
let set1: HashSet<i64> = HashSet::from_iter(vec);
|
||||
let set2: HashSet<i64> = HashSet::from_iter(vec![1, 2, 3, 7, 5]);
|
||||
assert_eq!(set1, set2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_natural_join() {
|
||||
let row1: Vec<String> = vec!["20230001", "Jack"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let row2: Vec<String> = vec!["20231234", "Mike"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let table1 = vec![row1, row2];
|
||||
let row1: Vec<String> = vec!["20230001", "CS"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let row2: Vec<String> = vec!["20230001", "EE"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let row3: Vec<String> = vec!["20231234", "ME"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let table2 = vec![row1, row2, row3];
|
||||
let row1: Vec<String> = vec!["20230001", "Jack", "CS"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let row2: Vec<String> = vec!["20230001", "Jack", "EE"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let row3: Vec<String> = vec!["20231234", "Mike", "ME"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let table3 = vec![row1, row2, row3];
|
||||
|
||||
assert_eq!(
|
||||
HashSet::<Vec<String>>::from_iter(natural_join(table1, table2)),
|
||||
HashSet::<Vec<String>>::from_iter(table3)
|
||||
);
|
||||
|
||||
let row1: Vec<String> = vec!["20230001", "Alice"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let row2: Vec<String> = vec!["20230002", "Bob"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let row3: Vec<String> = vec!["20230003", "Charlie"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let row4: Vec<String> = vec!["20230004", "David"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let table1 = vec![row1, row2, row3, row4];
|
||||
let row1: Vec<String> = vec!["20230001", "Apple"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let row2: Vec<String> = vec!["20230001", "Avocado"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let row3: Vec<String> = vec!["20230002", "Banana"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let row4: Vec<String> = vec!["20230002", "Berries"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let row5: Vec<String> = vec!["20230004", "Durian"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let table2 = vec![row1, row2, row3, row4, row5];
|
||||
let row1: Vec<String> = vec!["20230001", "Alice", "Apple"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let row2: Vec<String> = vec!["20230001", "Alice", "Avocado"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let row3: Vec<String> = vec!["20230002", "Bob", "Banana"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let row4: Vec<String> = vec!["20230002", "Bob", "Berries"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let row5: Vec<String> = vec!["20230004", "David", "Durian"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let table3 = vec![row1, row2, row3, row4, row5];
|
||||
|
||||
assert_eq!(
|
||||
HashSet::<Vec<String>>::from_iter(natural_join(table1, table2)),
|
||||
HashSet::<Vec<String>>::from_iter(table3)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pythagorean() {
|
||||
let pythagoreans = [
|
||||
(3, 4, 5),
|
||||
(5, 12, 13),
|
||||
(8, 15, 17),
|
||||
(7, 24, 25),
|
||||
(20, 21, 29),
|
||||
(12, 35, 37),
|
||||
(9, 40, 41),
|
||||
(28, 45, 53),
|
||||
(11, 60, 61),
|
||||
(16, 63, 65),
|
||||
(33, 56, 65),
|
||||
(48, 55, 73),
|
||||
(13, 84, 85),
|
||||
(36, 77, 85),
|
||||
(39, 80, 89),
|
||||
(65, 72, 97),
|
||||
(20, 99, 101),
|
||||
(60, 91, 109),
|
||||
(15, 112, 113),
|
||||
(44, 117, 125),
|
||||
(88, 105, 137),
|
||||
(17, 144, 145),
|
||||
(24, 143, 145),
|
||||
(51, 140, 149),
|
||||
(85, 132, 157),
|
||||
(119, 120, 169),
|
||||
(52, 165, 173),
|
||||
(19, 180, 181),
|
||||
(57, 176, 185),
|
||||
(104, 153, 185),
|
||||
(95, 168, 193),
|
||||
(28, 195, 197),
|
||||
(84, 187, 205),
|
||||
(133, 156, 205),
|
||||
(21, 220, 221),
|
||||
(140, 171, 221),
|
||||
(60, 221, 229),
|
||||
(105, 208, 233),
|
||||
(120, 209, 241),
|
||||
(32, 255, 257),
|
||||
(23, 264, 265),
|
||||
(96, 247, 265),
|
||||
(69, 260, 269),
|
||||
(115, 252, 277),
|
||||
(160, 231, 281),
|
||||
(161, 240, 289),
|
||||
(68, 285, 293),
|
||||
];
|
||||
|
||||
for (i, t) in pythagorean().enumerate().take(1000) {
|
||||
if i < pythagoreans.len() {
|
||||
assert_eq!(pythagoreans[i], t)
|
||||
}
|
||||
let (a, b, c) = t;
|
||||
assert_eq!(a * a + b * b, c * c);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::super::assignment10::*;
|
||||
|
||||
#[test]
|
||||
fn test_inversion() {
|
||||
assert_eq!(inversion(vec![3, 5, 4]), vec![(1, 2)]);
|
||||
assert_eq!(inversion(vec!["c", "a", "b", "d"]), vec![(0, 1), (0, 2)]);
|
||||
assert_eq!(
|
||||
inversion(vec![2, 5, 4, 6, 3, 1]),
|
||||
vec![
|
||||
(0, 5),
|
||||
(1, 2),
|
||||
(1, 4),
|
||||
(1, 5),
|
||||
(2, 4),
|
||||
(2, 5),
|
||||
(3, 4),
|
||||
(3, 5),
|
||||
(4, 5)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_traverse_preorder() {
|
||||
let root = Node::NonLeaf((
|
||||
1,
|
||||
vec![
|
||||
Node::NonLeaf((2, vec![Node::Leaf(5), Node::Leaf(6)])),
|
||||
Node::Leaf(3),
|
||||
Node::NonLeaf((4, vec![Node::Leaf(7), Node::Leaf(8), Node::Leaf(9)])),
|
||||
],
|
||||
));
|
||||
|
||||
assert_eq!(traverse_preorder(root), vec![1, 2, 5, 6, 3, 4, 7, 8, 9]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_du_sort() {
|
||||
let rootfile = File::Directory(
|
||||
"root".to_string(),
|
||||
vec![
|
||||
File::Directory(
|
||||
"a".to_string(),
|
||||
vec![
|
||||
File::Data("a1".to_string(), 1),
|
||||
File::Data("a2".to_string(), 3),
|
||||
],
|
||||
),
|
||||
File::Directory(
|
||||
"b".to_string(),
|
||||
vec![
|
||||
File::Data("b1".to_string(), 3),
|
||||
File::Data("b2".to_string(), 15),
|
||||
],
|
||||
),
|
||||
File::Data("c".to_string(), 8),
|
||||
],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
du_sort(&rootfile),
|
||||
vec![
|
||||
("a1", 1),
|
||||
("a2", 3),
|
||||
("b1", 3),
|
||||
("a", 4),
|
||||
("c", 8),
|
||||
("b2", 15),
|
||||
("b", 18),
|
||||
("root", 1 + 3 + 3 + 15 + 8)
|
||||
]
|
||||
);
|
||||
|
||||
let rootfile = File::Directory(
|
||||
"root".to_string(),
|
||||
vec![
|
||||
File::Directory(
|
||||
"b".to_string(),
|
||||
vec![
|
||||
File::Data("b1".to_string(), 3),
|
||||
File::Data("b2".to_string(), 15),
|
||||
],
|
||||
),
|
||||
File::Data("c".to_string(), 8),
|
||||
File::Directory(
|
||||
"a".to_string(),
|
||||
vec![
|
||||
File::Data("a1".to_string(), 1),
|
||||
File::Data("a2".to_string(), 3),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
du_sort(&rootfile),
|
||||
vec![
|
||||
("a1", 1),
|
||||
("a2", 3),
|
||||
("b1", 3),
|
||||
("a", 4),
|
||||
("c", 8),
|
||||
("b2", 15),
|
||||
("b", 18),
|
||||
("root", 1 + 3 + 3 + 15 + 8)
|
||||
]
|
||||
);
|
||||
|
||||
let rootfile = File::Directory(
|
||||
"root".to_string(),
|
||||
vec![
|
||||
File::Directory(
|
||||
"a".to_string(),
|
||||
vec![
|
||||
File::Data("a1".to_string(), 1),
|
||||
File::Data("a2".to_string(), 3),
|
||||
File::Directory(
|
||||
"a3".to_string(),
|
||||
vec![
|
||||
File::Data("a31".to_string(), 1),
|
||||
File::Data("a32".to_string(), 3),
|
||||
File::Data("a33".to_string(), 6),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
File::Directory(
|
||||
"b".to_string(),
|
||||
vec![
|
||||
File::Data("b1".to_string(), 3),
|
||||
File::Data("b2".to_string(), 15),
|
||||
],
|
||||
),
|
||||
File::Data("c".to_string(), 16),
|
||||
],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
du_sort(&rootfile),
|
||||
vec![
|
||||
("a1", 1),
|
||||
("a31", 1),
|
||||
("a2", 3),
|
||||
("a32", 3),
|
||||
("b1", 3),
|
||||
("a33", 6),
|
||||
("a3", 10),
|
||||
("a", 14),
|
||||
("b2", 15),
|
||||
("c", 16),
|
||||
("b", 18),
|
||||
("root", 48)
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -15,15 +15,11 @@ mod assignment03_grade;
|
||||
pub mod assignment04;
|
||||
mod assignment04_grade;
|
||||
pub mod assignment06;
|
||||
mod assignment06_grade;
|
||||
pub mod assignment07;
|
||||
mod assignment07_grade;
|
||||
pub mod assignment08;
|
||||
mod assignment08_grade;
|
||||
pub mod assignment09;
|
||||
mod assignment09_grade;
|
||||
pub mod assignment10;
|
||||
mod assignment10_grade;
|
||||
pub mod assignment11;
|
||||
pub mod assignment12;
|
||||
pub mod assignment13;
|
||||
|
||||
Reference in New Issue
Block a user