mirror of
https://github.com/kmc7468/cs220.git
synced 2025-12-12 21:08:45 +00:00
assignment 1~5: fixes
- assignment05/pascal.mlw: lowered the difficulty (one more invariant given) - assignment02, 03: minor fixes & divide into sub-problems
This commit is contained in:
@@ -4,7 +4,6 @@
|
|||||||
return the maximum element of the array.
|
return the maximum element of the array.
|
||||||
|
|
||||||
You should stengthen the loop invariant.
|
You should stengthen the loop invariant.
|
||||||
|
|
||||||
*)
|
*)
|
||||||
|
|
||||||
module Max
|
module Max
|
||||||
@@ -20,8 +19,9 @@ module Max
|
|||||||
ensures { exists i. 0 <= i < n -> a[i] = max }
|
ensures { exists i. 0 <= i < n -> a[i] = max }
|
||||||
= let ref max = 0 in
|
= let ref max = 0 in
|
||||||
for i = 0 to n - 1 do
|
for i = 0 to n - 1 do
|
||||||
(* IMPORTANT: MODIFY ONLY THIS INVARIANT, OR YOU'LL GET ZERO POINTS *)
|
(* IMPORTANT: DON'T MODIFY THE ABOVE LINES *)
|
||||||
invariant { true (*TODO*) }
|
invariant { true (* TODO: Replace `true` with your solution *) }
|
||||||
|
(* IMPORTANT: DON'T MODIFY THE BELOW LINES *)
|
||||||
if max < a[i] then max <- a[i];
|
if max < a[i] then max <- a[i];
|
||||||
done;
|
done;
|
||||||
max
|
max
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
|
(* Pascal
|
||||||
|
|
||||||
|
Prove that the Pascal's triangle indeed computes combinations.
|
||||||
|
HINT: https://en.wikipedia.org/wiki/Pascal%27s_triangle
|
||||||
|
*)
|
||||||
|
|
||||||
module Pascal
|
module Pascal
|
||||||
use int.Int
|
use int.Int
|
||||||
use ref.Ref
|
use ref.Ref
|
||||||
use array.Array
|
use array.Array
|
||||||
|
|
||||||
(* HINT: https://en.wikipedia.org/wiki/Pascal%27s_triangle *)
|
|
||||||
(* You should understand the Pascal's triangle first to find good invariants *)
|
|
||||||
let rec function comb (n k: int) : int
|
let rec function comb (n k: int) : int
|
||||||
requires { 0 <= k <= n }
|
requires { 0 <= k <= n }
|
||||||
variant { n }
|
variant { n }
|
||||||
@@ -12,6 +16,7 @@ module Pascal
|
|||||||
= if k = 0 || k = n then 1 else comb (n-1) k + comb (n-1) (k-1)
|
= if k = 0 || k = n then 1 else comb (n-1) k + comb (n-1) (k-1)
|
||||||
|
|
||||||
(* Insert appropriate invariants so that Why3 can verify this function. *)
|
(* Insert appropriate invariants so that Why3 can verify this function. *)
|
||||||
|
(* You SHOULD understand the Pascal's triangle first to find good invariants. *)
|
||||||
let chooses (n : int) : array int
|
let chooses (n : int) : array int
|
||||||
requires { n > 0 }
|
requires { n > 0 }
|
||||||
ensures { forall i: int.
|
ensures { forall i: int.
|
||||||
@@ -20,10 +25,12 @@ module Pascal
|
|||||||
let ref row = Array.make 1 1 in
|
let ref row = Array.make 1 1 in
|
||||||
for r = 1 to n do
|
for r = 1 to n do
|
||||||
invariant { length row = r }
|
invariant { length row = r }
|
||||||
invariant { true (*TODO*) }
|
invariant { forall c: int. 0 <= c < r -> row[c] = comb (r-1) c }
|
||||||
let new_row = Array.make (r+1) 1 in
|
let new_row = Array.make (r+1) 1 in
|
||||||
for c = 1 to r-1 do
|
for c = 1 to r-1 do
|
||||||
invariant { true (*TODO*) }
|
(* IMPORTANT: DON'T MODIFY THE ABOVE LINES *)
|
||||||
|
invariant { true (* TODO: Replace `true` with your solution *) }
|
||||||
|
(* IMPORTANT: DON'T MODIFY THE BELOW LINES *)
|
||||||
new_row[c] <- row[c-1] + row[c]
|
new_row[c] <- row[c-1] + row[c]
|
||||||
done;
|
done;
|
||||||
row <- new_row
|
row <- new_row
|
||||||
@@ -11,7 +11,6 @@ module Division
|
|||||||
|
|
||||||
use int.Int
|
use int.Int
|
||||||
|
|
||||||
(* IMPORTANT: DON'T MODIFY LINES EXCEPT `TODO`s OR YOU WILL GET ZERO POINTS *)
|
|
||||||
let division (a b: int) : int
|
let division (a b: int) : int
|
||||||
requires { a >= 0 }
|
requires { a >= 0 }
|
||||||
requires { b > 0 }
|
requires { b > 0 }
|
||||||
@@ -20,7 +19,7 @@ module Division
|
|||||||
let ref q = 0 in
|
let ref q = 0 in
|
||||||
let ref r = a in
|
let ref r = a in
|
||||||
while r >= b do
|
while r >= b do
|
||||||
invariant { true (*TODO*) }
|
invariant { true (* TODO: Replace `true` with your solution *) }
|
||||||
variant { r }
|
variant { r }
|
||||||
q <- q + 1;
|
q <- q + 1;
|
||||||
r <- r - b
|
r <- r - b
|
||||||
@@ -39,10 +39,8 @@ module FactLoop
|
|||||||
= let ref m = 0 in
|
= let ref m = 0 in
|
||||||
let ref r = 1 in
|
let ref r = 1 in
|
||||||
while m < n do
|
while m < n do
|
||||||
(* IMPORTANT: DON'T MODIFY THE ABOVE LINES *)
|
invariant { true (* TODO: Replace `true` with your solution *) }
|
||||||
invariant { true (* TODO *) }
|
variant { n (* TODO: Replace `n` with your solution *) }
|
||||||
variant { n (* TODO *) }
|
|
||||||
(* IMPORTANT: DON'T MODIFY THE BELOW LINES *)
|
|
||||||
m <- m + 1;
|
m <- m + 1;
|
||||||
r <- r * m
|
r <- r * m
|
||||||
done;
|
done;
|
||||||
@@ -31,13 +31,11 @@ module TwoWaySort
|
|||||||
let ref j = length a - 1 in
|
let ref j = length a - 1 in
|
||||||
while i < j do
|
while i < j do
|
||||||
invariant { 0 <= i /\ j < length a }
|
invariant { 0 <= i /\ j < length a }
|
||||||
(* IMPORTANT: DON'T MODIFY THE ABOVE LINES *)
|
|
||||||
invariant { forall i1: int. 0 <= i1 < i
|
invariant { forall i1: int. 0 <= i1 < i
|
||||||
-> true (* TODO *) }
|
-> true (* TODO: Replace `true` with your solution *) }
|
||||||
invariant { forall i2: int. j < i2 < length a
|
invariant { forall i2: int. j < i2 < length a
|
||||||
-> true (* TODO *) }
|
-> true (* TODO: Replace `true` with your solution *) }
|
||||||
invariant { true (* TODO *) }
|
invariant { true (* TODO: Replace `true` with your solution *) }
|
||||||
(* IMPORTANT: DON'T MODIFY THE BELOW LINES *)
|
|
||||||
variant { j - i }
|
variant { j - i }
|
||||||
if not a[i] then
|
if not a[i] then
|
||||||
incr i
|
incr i
|
||||||
30
assets/why3/exercises/solutions/ex1_eucl_div_sol.mlw
Normal file
30
assets/why3/exercises/solutions/ex1_eucl_div_sol.mlw
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
(* Euclidean division
|
||||||
|
|
||||||
|
1. Prove correctness of euclideian divison:
|
||||||
|
`division a b` returns an integer `q` such that
|
||||||
|
`a = bq+r` and `0 <= r < b` for some `r`.
|
||||||
|
|
||||||
|
- You have to strengthen the precondition.
|
||||||
|
- You have to strengthen the loop invariant.
|
||||||
|
*)
|
||||||
|
|
||||||
|
module Division
|
||||||
|
|
||||||
|
use int.Int
|
||||||
|
|
||||||
|
let division (a b: int) : int
|
||||||
|
requires { a >= 0 }
|
||||||
|
requires { b > 0 }
|
||||||
|
ensures { exists r: int. a = b * result + r /\ 0 <= r < b }
|
||||||
|
=
|
||||||
|
let ref q = 0 in
|
||||||
|
let ref r = a in
|
||||||
|
while r >= b do
|
||||||
|
invariant { a = b * q + r /\ 0 <= r }
|
||||||
|
variant { r }
|
||||||
|
q <- q + 1;
|
||||||
|
r <- r - b
|
||||||
|
done;
|
||||||
|
q
|
||||||
|
|
||||||
|
end
|
||||||
37
assets/why3/exercises/solutions/ex2_fact_sol.mlw
Normal file
37
assets/why3/exercises/solutions/ex2_fact_sol.mlw
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
(* Two programs to compute the factorial
|
||||||
|
|
||||||
|
*)
|
||||||
|
|
||||||
|
module FactRecursive
|
||||||
|
|
||||||
|
use int.Int
|
||||||
|
use int.Fact
|
||||||
|
|
||||||
|
let rec fact_rec (n: int) : int
|
||||||
|
requires { n >= 0 }
|
||||||
|
ensures { result = fact n }
|
||||||
|
variant { n }
|
||||||
|
=
|
||||||
|
if n = 0 then 1 else n * fact_rec (n - 1)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module FactLoop
|
||||||
|
|
||||||
|
use int.Int
|
||||||
|
use int.Fact
|
||||||
|
|
||||||
|
let fact_loop (n: int) : int
|
||||||
|
requires { 0 < n }
|
||||||
|
ensures { result = fact n }
|
||||||
|
= let ref m = 0 in
|
||||||
|
let ref r = 1 in
|
||||||
|
while m < n do
|
||||||
|
invariant { 0 <= m <= n /\ r = fact m }
|
||||||
|
variant { n - m }
|
||||||
|
m <- m + 1;
|
||||||
|
r <- r * m
|
||||||
|
done;
|
||||||
|
r
|
||||||
|
|
||||||
|
end
|
||||||
49
assets/why3/exercises/solutions/ex3_two_way_sol.mlw
Normal file
49
assets/why3/exercises/solutions/ex3_two_way_sol.mlw
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
(* Two Way Sort
|
||||||
|
|
||||||
|
The following program sorts an array of Boolean values, with False<True.
|
||||||
|
|
||||||
|
E.g.
|
||||||
|
two_way_sorted [True; False; False; True; False]
|
||||||
|
= [False; False; False; True; True]
|
||||||
|
|
||||||
|
- Strengthen the invariant to prove correctness.
|
||||||
|
*)
|
||||||
|
|
||||||
|
module TwoWaySort
|
||||||
|
|
||||||
|
use int.Int
|
||||||
|
use bool.Bool
|
||||||
|
use ref.Refint
|
||||||
|
use array.Array
|
||||||
|
use array.ArraySwap
|
||||||
|
use array.ArrayPermut
|
||||||
|
|
||||||
|
predicate (<<) (x y: bool) = x = False \/ y = True
|
||||||
|
|
||||||
|
predicate sorted (a: array bool) =
|
||||||
|
forall i1 i2: int. 0 <= i1 <= i2 < a.length -> a[i1] << a[i2]
|
||||||
|
|
||||||
|
let two_way_sort (a: array bool) : unit
|
||||||
|
ensures { sorted a }
|
||||||
|
ensures { permut_all (old a) a }
|
||||||
|
=
|
||||||
|
let ref i = 0 in
|
||||||
|
let ref j = length a - 1 in
|
||||||
|
while i < j do
|
||||||
|
invariant { 0 <= i /\ j < length a }
|
||||||
|
invariant { forall i1: int. 0 <= i1 < i -> a[i1] = False }
|
||||||
|
invariant { forall i2: int. j < i2 < length a -> a[i2] = True }
|
||||||
|
invariant { permut_all (old a) a }
|
||||||
|
variant { j - i }
|
||||||
|
if not a[i] then
|
||||||
|
incr i
|
||||||
|
else if a[j] then
|
||||||
|
decr j
|
||||||
|
else begin
|
||||||
|
swap a i j;
|
||||||
|
incr i;
|
||||||
|
decr j
|
||||||
|
end
|
||||||
|
done
|
||||||
|
|
||||||
|
end
|
||||||
@@ -24,7 +24,7 @@ run_linters || exit 1
|
|||||||
for RUNNER in "${RUNNERS[@]}"; do
|
for RUNNER in "${RUNNERS[@]}"; do
|
||||||
echo "Running with $RUNNER..."
|
echo "Running with $RUNNER..."
|
||||||
|
|
||||||
TESTS=("--lib assignment02_grade")
|
TESTS=("--lib assignment02")
|
||||||
if [ $(run_tests) -ne 0 ]; then
|
if [ $(run_tests) -ne 0 ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ run_linters || exit 1
|
|||||||
for RUNNER in "${RUNNERS[@]}"; do
|
for RUNNER in "${RUNNERS[@]}"; do
|
||||||
echo "Running with $RUNNER..."
|
echo "Running with $RUNNER..."
|
||||||
|
|
||||||
TESTS=("--lib assignment03_grade")
|
TESTS=("--lib assignment03")
|
||||||
if [ $(run_tests) -ne 0 ]; then
|
if [ $(run_tests) -ne 0 ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,176 +0,0 @@
|
|||||||
//! Assignment 2: Mastering common programming concepts (1/2).
|
|
||||||
//!
|
|
||||||
//! The primary goal of this assignment is to re-learn the common programming concepts in Rust, especially those in the Rust Book chapters 3 and 5.
|
|
||||||
//! Please make sure you're comfortable with the concepts to proceed on to the next assignments.
|
|
||||||
//!
|
|
||||||
//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-02.sh` works fine.
|
|
||||||
//! See `assignment02_grade.rs` and `/scripts/grade-02.sh` for the test script.
|
|
||||||
|
|
||||||
use std::ops::Mul;
|
|
||||||
|
|
||||||
const FAHRENHEIT_OFFSET: f64 = 32.0;
|
|
||||||
const FAHRENHEIT_SCALE: f64 = 5.0 / 9.0;
|
|
||||||
|
|
||||||
/// Converts Fahrenheit to Celsius temperature degree.
|
|
||||||
pub fn fahrenheit_to_celsius(degree: f64) -> f64 {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Capitalizes English alphabets (leaving the other characters intact).
|
|
||||||
pub fn capitalize(input: String) -> String {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the sum of the given array. (We assume the absence of integer overflow.)
|
|
||||||
pub fn sum_array(input: &[u64]) -> u64 {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given a non-negative integer, say `n`, return the smallest integer of the form `3^m` that's greater than or equal to `n`.
|
|
||||||
///
|
|
||||||
/// For instance, up3(6) = 9, up3(9) = 9, up3(10) = 27. (We assume the absence of integer overflow.)
|
|
||||||
pub fn up3(n: u64) -> u64 {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the greatest common divisor (GCD) of two non-negative integers. (We assume the absence of integer overflow.)
|
|
||||||
pub fn gcd(lhs: u64, rhs: u64) -> u64 {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the array of nC0, nC1, nC2, ..., nCn, where nCk = n! / (k! * (n-k)!). (We assume the absence of integer overflow.)
|
|
||||||
///
|
|
||||||
/// Consult <https://en.wikipedia.org/wiki/Pascal%27s_triangle> for computation of binomial coefficients without integer overflow.
|
|
||||||
pub fn chooses(n: u64) -> Vec<u64> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the "zip" of two vectors.
|
|
||||||
///
|
|
||||||
/// For instance, `zip(vec![1, 2, 3], vec![4, 5])` equals to `vec![(1, 4), (2, 5)]`.
|
|
||||||
/// Here, `3` is ignored because it doesn't have a partner.
|
|
||||||
pub fn zip(lhs: Vec<u64>, rhs: Vec<u64>) -> Vec<(u64, u64)> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 2x2 matrix of the following configuration:
|
|
||||||
///
|
|
||||||
/// a, b
|
|
||||||
/// c, d
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
struct Mat2 {
|
|
||||||
a: u64,
|
|
||||||
b: u64,
|
|
||||||
c: u64,
|
|
||||||
d: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 2x1 matrix of the following configuration:
|
|
||||||
///
|
|
||||||
/// a
|
|
||||||
/// b
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
struct Vec2 {
|
|
||||||
a: u64,
|
|
||||||
b: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mat2 {
|
|
||||||
/// Creates an identity matrix.
|
|
||||||
fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
a: 1,
|
|
||||||
b: 0,
|
|
||||||
c: 0,
|
|
||||||
d: 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mul<Mat2> for Mat2 {
|
|
||||||
type Output = Mat2;
|
|
||||||
|
|
||||||
fn mul(self, rhs: Mat2) -> Self::Output {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mul<Vec2> for Mat2 {
|
|
||||||
type Output = Vec2;
|
|
||||||
|
|
||||||
fn mul(self, rhs: Vec2) -> Self::Output {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mat2 {
|
|
||||||
/// Calculates the power of matrix.
|
|
||||||
fn power(self, power: u64) -> Mat2 {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Vec2 {
|
|
||||||
/// Gets the upper value of vector.
|
|
||||||
fn get_upper(self) -> u64 {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The matrix used for calculating Fibonacci numbers.
|
|
||||||
const FIBONACCI_MAT: Mat2 = Mat2 {
|
|
||||||
a: 1,
|
|
||||||
b: 1,
|
|
||||||
c: 1,
|
|
||||||
d: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// The vector used for calculating Fibonacci numbers.
|
|
||||||
const FIBONACCI_VEC: Vec2 = Vec2 { a: 1, b: 0 };
|
|
||||||
|
|
||||||
/// Calculates the Fibonacci number. (We assume the absence of integer overflow.)
|
|
||||||
///
|
|
||||||
/// Consult <https://web.media.mit.edu/~holbrow/post/calculating-fibonacci-numbers-with-matrices-and-linear-algebra/> for matrix computation of Fibonacci numbers.
|
|
||||||
pub fn fibonacci(n: u64) -> u64 {
|
|
||||||
(FIBONACCI_MAT.power(n) * FIBONACCI_VEC).get_upper()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 2x2 floating-point matrix of the following configuration:
|
|
||||||
///
|
|
||||||
/// a, b
|
|
||||||
/// c, d
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct FMat2 {
|
|
||||||
/// row 1, column 1
|
|
||||||
pub a: f64,
|
|
||||||
/// row 1, column 2
|
|
||||||
pub b: f64,
|
|
||||||
/// row 2, column 1
|
|
||||||
pub c: f64,
|
|
||||||
/// row 2, column 2
|
|
||||||
pub d: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FMat2 {
|
|
||||||
/// Returns the inverse of the given matrix. (We assume the given matrix is always invertible.)
|
|
||||||
/// Hint: https://www.cuemath.com/algebra/inverse-of-2x2-matrix/
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// assert_eq!(
|
|
||||||
/// Mat2 { a: 1.0, b: 1.0, c: 2.0, d: 3.0 }.inverse(),
|
|
||||||
/// Mat2 { a: 3.0, b: -1.0, c: -2.0, d: 1.0}
|
|
||||||
/// );
|
|
||||||
/// ```
|
|
||||||
pub fn inverse(self) -> Self {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writes down the lyrics of "twelve days of christmas".
|
|
||||||
///
|
|
||||||
/// Hint: Google the song title for lyrics and look at the test code for the expected result.
|
|
||||||
pub fn twelve_days_of_christmas_lyrics() -> String {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
13
src/assignments/assignment02/mod.rs
Normal file
13
src/assignments/assignment02/mod.rs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
//! Assignment 2: Mastering common programming concepts (1/2).
|
||||||
|
//!
|
||||||
|
//! The primary goal of this assignment is to re-learn the common programming concepts in Rust, especially those in the Rust Book chapters 3 and 5.
|
||||||
|
//! Please make sure you're comfortable with the concepts to proceed on to the next assignments.
|
||||||
|
//!
|
||||||
|
//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-02.sh` works fine.
|
||||||
|
//! See `*_grade.rs` and `/scripts/grade-02.sh` for the test script.
|
||||||
|
|
||||||
|
pub mod small_problems;
|
||||||
|
mod small_problems_grade;
|
||||||
|
|
||||||
|
pub mod vec_and_mat;
|
||||||
|
mod vec_and_mat_grade;
|
||||||
46
src/assignments/assignment02/small_problems.rs
Normal file
46
src/assignments/assignment02/small_problems.rs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
//! Small problems.
|
||||||
|
|
||||||
|
const FAHRENHEIT_OFFSET: f64 = 32.0;
|
||||||
|
const FAHRENHEIT_SCALE: f64 = 5.0 / 9.0;
|
||||||
|
|
||||||
|
/// Converts Fahrenheit to Celsius temperature degree.
|
||||||
|
pub fn fahrenheit_to_celsius(degree: f64) -> f64 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Capitalizes English alphabets (leaving the other characters intact).
|
||||||
|
pub fn capitalize(input: String) -> String {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the sum of the given array. (We assume the absence of integer overflow.)
|
||||||
|
pub fn sum_array(input: &[u64]) -> u64 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given a non-negative integer, say `n`, return the smallest integer of the form `3^m` that's greater than or equal to `n`.
|
||||||
|
///
|
||||||
|
/// For instance, up3(6) = 9, up3(9) = 9, up3(10) = 27. (We assume the absence of integer overflow.)
|
||||||
|
pub fn up3(n: u64) -> u64 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the greatest common divisor (GCD) of two non-negative integers. (We assume the absence of integer overflow.)
|
||||||
|
pub fn gcd(lhs: u64, rhs: u64) -> u64 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the array of nC0, nC1, nC2, ..., nCn, where nCk = n! / (k! * (n-k)!). (We assume the absence of integer overflow.)
|
||||||
|
///
|
||||||
|
/// Consult <https://en.wikipedia.org/wiki/Pascal%27s_triangle> for computation of binomial coefficients without integer overflow.
|
||||||
|
pub fn chooses(n: u64) -> Vec<u64> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the "zip" of two vectors.
|
||||||
|
///
|
||||||
|
/// For instance, `zip(vec![1, 2, 3], vec![4, 5])` equals to `vec![(1, 4), (2, 5)]`.
|
||||||
|
/// Here, `3` is ignored because it doesn't have a partner.
|
||||||
|
pub fn zip(lhs: Vec<u64>, rhs: Vec<u64>) -> Vec<(u64, u64)> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
137
src/assignments/assignment02/small_problems_grade.rs
Normal file
137
src/assignments/assignment02/small_problems_grade.rs
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::assignments::assignment02::small_problems::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fahrenheit() {
|
||||||
|
assert_eq!(fahrenheit_to_celsius(32.0), 0.0);
|
||||||
|
assert_eq!(fahrenheit_to_celsius(212.0), 100.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_capitalize() {
|
||||||
|
assert_eq!(
|
||||||
|
capitalize(String::from("aAbbBcccCddddD❤한글과✓")),
|
||||||
|
String::from("AABBBCCCCDDDDD❤한글과✓"),
|
||||||
|
);
|
||||||
|
assert_eq!(capitalize(String::from("Tschüß")), String::from("TSCHüß"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_up3() {
|
||||||
|
assert_eq!(up3(0), 1);
|
||||||
|
assert_eq!(up3(1), 1);
|
||||||
|
assert_eq!(up3(6), 9);
|
||||||
|
assert_eq!(up3(9), 9);
|
||||||
|
assert_eq!(up3(10), 27);
|
||||||
|
assert_eq!(up3(1_000_000), 1_594_323);
|
||||||
|
assert_eq!(up3(3u64.pow(39).wrapping_add(1)), 3u64.pow(40));
|
||||||
|
assert_eq!(up3(3u64.pow(40)), 3u64.pow(40));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_gcd() {
|
||||||
|
assert_eq!(gcd(5, 1), 1);
|
||||||
|
assert_eq!(gcd(3, 3), 3);
|
||||||
|
assert_eq!(gcd(2, 6), 2);
|
||||||
|
assert_eq!(gcd(24, 18), 6);
|
||||||
|
assert_eq!(gcd(20, 63), 1);
|
||||||
|
assert_eq!(gcd(0, 33), 33);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sum_array() {
|
||||||
|
assert_eq!(sum_array(&[]), 0);
|
||||||
|
assert_eq!(sum_array(&[1]), 1);
|
||||||
|
assert_eq!(sum_array(&[1, 2, 3, 4, 5, 100]), 115);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_chooses() {
|
||||||
|
assert_eq!(chooses(0), vec![1]);
|
||||||
|
assert_eq!(chooses(1), vec![1, 1]);
|
||||||
|
assert_eq!(chooses(5), vec![1, 5, 10, 10, 5, 1]);
|
||||||
|
assert_eq!(chooses(6), vec![1, 6, 15, 20, 15, 6, 1]);
|
||||||
|
assert_eq!(
|
||||||
|
chooses(67),
|
||||||
|
vec![
|
||||||
|
1,
|
||||||
|
67,
|
||||||
|
2211,
|
||||||
|
47905,
|
||||||
|
766480,
|
||||||
|
9657648,
|
||||||
|
99795696,
|
||||||
|
869648208,
|
||||||
|
6522361560,
|
||||||
|
42757703560,
|
||||||
|
247994680648,
|
||||||
|
1285063345176,
|
||||||
|
5996962277488,
|
||||||
|
25371763481680,
|
||||||
|
97862516286480,
|
||||||
|
345780890878896,
|
||||||
|
1123787895356412,
|
||||||
|
3371363686069236,
|
||||||
|
9364899127970100,
|
||||||
|
24151581961607100,
|
||||||
|
57963796707857040,
|
||||||
|
129728497393775280,
|
||||||
|
271250494550621040,
|
||||||
|
530707489338171600,
|
||||||
|
972963730453314600,
|
||||||
|
1673497616379701112,
|
||||||
|
2703342303382594104,
|
||||||
|
4105075349580976232,
|
||||||
|
5864393356544251760,
|
||||||
|
7886597962249166160,
|
||||||
|
9989690752182277136,
|
||||||
|
11923179284862717872,
|
||||||
|
13413576695470557606,
|
||||||
|
14226520737620288370,
|
||||||
|
14226520737620288370,
|
||||||
|
13413576695470557606,
|
||||||
|
11923179284862717872,
|
||||||
|
9989690752182277136,
|
||||||
|
7886597962249166160,
|
||||||
|
5864393356544251760,
|
||||||
|
4105075349580976232,
|
||||||
|
2703342303382594104,
|
||||||
|
1673497616379701112,
|
||||||
|
972963730453314600,
|
||||||
|
530707489338171600,
|
||||||
|
271250494550621040,
|
||||||
|
129728497393775280,
|
||||||
|
57963796707857040,
|
||||||
|
24151581961607100,
|
||||||
|
9364899127970100,
|
||||||
|
3371363686069236,
|
||||||
|
1123787895356412,
|
||||||
|
345780890878896,
|
||||||
|
97862516286480,
|
||||||
|
25371763481680,
|
||||||
|
5996962277488,
|
||||||
|
1285063345176,
|
||||||
|
247994680648,
|
||||||
|
42757703560,
|
||||||
|
6522361560,
|
||||||
|
869648208,
|
||||||
|
99795696,
|
||||||
|
9657648,
|
||||||
|
766480,
|
||||||
|
47905,
|
||||||
|
2211,
|
||||||
|
67,
|
||||||
|
1
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_zip() {
|
||||||
|
assert_eq!(zip(vec![1, 2], vec![4, 5]), vec![(1, 4), (2, 5)]);
|
||||||
|
assert_eq!(zip(vec![1, 2, 3], vec![4, 5]), vec![(1, 4), (2, 5)]);
|
||||||
|
assert_eq!(zip(vec![1, 2], vec![4, 5, 6]), vec![(1, 4), (2, 5)]);
|
||||||
|
assert_eq!(zip(vec![], vec![4, 5]), vec![]);
|
||||||
|
}
|
||||||
|
}
|
||||||
121
src/assignments/assignment02/vec_and_mat.rs
Normal file
121
src/assignments/assignment02/vec_and_mat.rs
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
//! Vector and matrices.
|
||||||
|
//!
|
||||||
|
//! You will implement simple operations on vectors and matrices.
|
||||||
|
|
||||||
|
use std::ops::Mul;
|
||||||
|
|
||||||
|
/// 2x2 matrix of the following configuration:
|
||||||
|
///
|
||||||
|
/// a, b
|
||||||
|
/// c, d
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct Mat2 {
|
||||||
|
a: u64,
|
||||||
|
b: u64,
|
||||||
|
c: u64,
|
||||||
|
d: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 2x1 matrix of the following configuration:
|
||||||
|
///
|
||||||
|
/// a
|
||||||
|
/// b
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct Vec2 {
|
||||||
|
a: u64,
|
||||||
|
b: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mat2 {
|
||||||
|
/// Creates an identity matrix.
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
a: 1,
|
||||||
|
b: 0,
|
||||||
|
c: 0,
|
||||||
|
d: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<Mat2> for Mat2 {
|
||||||
|
type Output = Mat2;
|
||||||
|
|
||||||
|
fn mul(self, rhs: Mat2) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<Vec2> for Mat2 {
|
||||||
|
type Output = Vec2;
|
||||||
|
|
||||||
|
/// Multiplies the matrix by the vector.
|
||||||
|
fn mul(self, rhs: Vec2) -> Self::Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mat2 {
|
||||||
|
/// Calculates the power of matrix.
|
||||||
|
fn power(self, power: u64) -> Mat2 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vec2 {
|
||||||
|
/// Gets the upper value of vector.
|
||||||
|
fn get_upper(self) -> u64 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The matrix used for calculating Fibonacci numbers.
|
||||||
|
const FIBONACCI_MAT: Mat2 = Mat2 {
|
||||||
|
a: 1,
|
||||||
|
b: 1,
|
||||||
|
c: 1,
|
||||||
|
d: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The vector used for calculating Fibonacci numbers.
|
||||||
|
const FIBONACCI_VEC: Vec2 = Vec2 { a: 1, b: 0 };
|
||||||
|
|
||||||
|
/// Calculates the Fibonacci number. (We assume the absence of integer overflow.)
|
||||||
|
///
|
||||||
|
/// Consult <https://web.media.mit.edu/~holbrow/post/calculating-fibonacci-numbers-with-matrices-and-linear-algebra/> for matrix computation of Fibonacci numbers.
|
||||||
|
pub fn fibonacci(n: u64) -> u64 {
|
||||||
|
(FIBONACCI_MAT.power(n) * FIBONACCI_VEC).get_upper()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 2x2 floating-point matrix of the following configuration:
|
||||||
|
///
|
||||||
|
/// a, b
|
||||||
|
/// c, d
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct FMat2 {
|
||||||
|
/// row 1, column 1
|
||||||
|
pub a: f64,
|
||||||
|
/// row 1, column 2
|
||||||
|
pub b: f64,
|
||||||
|
/// row 2, column 1
|
||||||
|
pub c: f64,
|
||||||
|
/// row 2, column 2
|
||||||
|
pub d: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FMat2 {
|
||||||
|
/// Returns the inverse of the given matrix. (We assume the given matrix is always invertible.)
|
||||||
|
/// HINT: https://www.mathcentre.ac.uk/resources/uploaded/sigma-matrices7-2009-1.pdf
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// assert_eq!(
|
||||||
|
/// Mat2 { a: 1.0, b: 1.0, c: 2.0, d: 3.0 }.inverse(),
|
||||||
|
/// Mat2 { a: 3.0, b: -1.0, c: -2.0, d: 1.0}
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
pub fn inverse(self) -> Self {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/assignments/assignment02/vec_and_mat_grade.rs
Normal file
60
src/assignments/assignment02/vec_and_mat_grade.rs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::assignments::assignment02::vec_and_mat::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fibonacci() {
|
||||||
|
assert_eq!(fibonacci(0), 1);
|
||||||
|
assert_eq!(fibonacci(1), 1);
|
||||||
|
assert_eq!(fibonacci(2), 2);
|
||||||
|
assert_eq!(fibonacci(3), 3);
|
||||||
|
assert_eq!(fibonacci(4), 5);
|
||||||
|
assert_eq!(fibonacci(5), 8);
|
||||||
|
assert_eq!(fibonacci(6), 13);
|
||||||
|
assert_eq!(fibonacci(7), 21);
|
||||||
|
assert_eq!(fibonacci(50), 20365011074);
|
||||||
|
assert_eq!(fibonacci(92), 12200160415121876738);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equivalence between two floating-point matrices, as element-wise equivalence
|
||||||
|
use std::cmp::PartialEq;
|
||||||
|
impl PartialEq for FMat2 {
|
||||||
|
fn eq(&self, other: &FMat2) -> bool {
|
||||||
|
self.a == other.a && self.b == other.b && self.c == other.c && self.d == other.d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_inverse() {
|
||||||
|
assert_eq!(
|
||||||
|
FMat2 {
|
||||||
|
a: 1.0,
|
||||||
|
b: 1.0,
|
||||||
|
c: 2.0,
|
||||||
|
d: 3.0
|
||||||
|
}
|
||||||
|
.inverse(),
|
||||||
|
FMat2 {
|
||||||
|
a: 3.0,
|
||||||
|
b: -1.0,
|
||||||
|
c: -2.0,
|
||||||
|
d: 1.0
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
FMat2 {
|
||||||
|
a: 2.0,
|
||||||
|
b: 3.0,
|
||||||
|
c: 5.0,
|
||||||
|
d: 7.0
|
||||||
|
}
|
||||||
|
.inverse(),
|
||||||
|
FMat2 {
|
||||||
|
a: -7.0,
|
||||||
|
b: 3.0,
|
||||||
|
c: 5.0,
|
||||||
|
d: -2.0
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,303 +0,0 @@
|
|||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::super::assignment02::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_fahrenheit() {
|
|
||||||
assert_eq!(fahrenheit_to_celsius(32.0), 0.0);
|
|
||||||
assert_eq!(fahrenheit_to_celsius(212.0), 100.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_capitalize() {
|
|
||||||
assert_eq!(
|
|
||||||
capitalize(String::from("aAbbBcccCddddD❤한글과✓")),
|
|
||||||
String::from("AABBBCCCCDDDDD❤한글과✓"),
|
|
||||||
);
|
|
||||||
assert_eq!(capitalize(String::from("Tschüß")), String::from("TSCHüß"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_up3() {
|
|
||||||
assert_eq!(up3(0), 1);
|
|
||||||
assert_eq!(up3(1), 1);
|
|
||||||
assert_eq!(up3(6), 9);
|
|
||||||
assert_eq!(up3(9), 9);
|
|
||||||
assert_eq!(up3(10), 27);
|
|
||||||
assert_eq!(up3(1_000_000), 1_594_323);
|
|
||||||
assert_eq!(up3(3u64.pow(39).wrapping_add(1)), 3u64.pow(40));
|
|
||||||
assert_eq!(up3(3u64.pow(40)), 3u64.pow(40));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_gcd() {
|
|
||||||
assert_eq!(gcd(5, 1), 1);
|
|
||||||
assert_eq!(gcd(3, 3), 3);
|
|
||||||
assert_eq!(gcd(2, 6), 2);
|
|
||||||
assert_eq!(gcd(24, 18), 6);
|
|
||||||
assert_eq!(gcd(20, 63), 1);
|
|
||||||
assert_eq!(gcd(0, 33), 33);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_sum_array() {
|
|
||||||
assert_eq!(sum_array(&[]), 0);
|
|
||||||
assert_eq!(sum_array(&[1]), 1);
|
|
||||||
assert_eq!(sum_array(&[1, 2, 3, 4, 5, 100]), 115);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_chooses() {
|
|
||||||
assert_eq!(chooses(0), vec![1]);
|
|
||||||
assert_eq!(chooses(1), vec![1, 1]);
|
|
||||||
assert_eq!(chooses(5), vec![1, 5, 10, 10, 5, 1]);
|
|
||||||
assert_eq!(chooses(6), vec![1, 6, 15, 20, 15, 6, 1]);
|
|
||||||
assert_eq!(
|
|
||||||
chooses(67),
|
|
||||||
vec![
|
|
||||||
1,
|
|
||||||
67,
|
|
||||||
2211,
|
|
||||||
47905,
|
|
||||||
766480,
|
|
||||||
9657648,
|
|
||||||
99795696,
|
|
||||||
869648208,
|
|
||||||
6522361560,
|
|
||||||
42757703560,
|
|
||||||
247994680648,
|
|
||||||
1285063345176,
|
|
||||||
5996962277488,
|
|
||||||
25371763481680,
|
|
||||||
97862516286480,
|
|
||||||
345780890878896,
|
|
||||||
1123787895356412,
|
|
||||||
3371363686069236,
|
|
||||||
9364899127970100,
|
|
||||||
24151581961607100,
|
|
||||||
57963796707857040,
|
|
||||||
129728497393775280,
|
|
||||||
271250494550621040,
|
|
||||||
530707489338171600,
|
|
||||||
972963730453314600,
|
|
||||||
1673497616379701112,
|
|
||||||
2703342303382594104,
|
|
||||||
4105075349580976232,
|
|
||||||
5864393356544251760,
|
|
||||||
7886597962249166160,
|
|
||||||
9989690752182277136,
|
|
||||||
11923179284862717872,
|
|
||||||
13413576695470557606,
|
|
||||||
14226520737620288370,
|
|
||||||
14226520737620288370,
|
|
||||||
13413576695470557606,
|
|
||||||
11923179284862717872,
|
|
||||||
9989690752182277136,
|
|
||||||
7886597962249166160,
|
|
||||||
5864393356544251760,
|
|
||||||
4105075349580976232,
|
|
||||||
2703342303382594104,
|
|
||||||
1673497616379701112,
|
|
||||||
972963730453314600,
|
|
||||||
530707489338171600,
|
|
||||||
271250494550621040,
|
|
||||||
129728497393775280,
|
|
||||||
57963796707857040,
|
|
||||||
24151581961607100,
|
|
||||||
9364899127970100,
|
|
||||||
3371363686069236,
|
|
||||||
1123787895356412,
|
|
||||||
345780890878896,
|
|
||||||
97862516286480,
|
|
||||||
25371763481680,
|
|
||||||
5996962277488,
|
|
||||||
1285063345176,
|
|
||||||
247994680648,
|
|
||||||
42757703560,
|
|
||||||
6522361560,
|
|
||||||
869648208,
|
|
||||||
99795696,
|
|
||||||
9657648,
|
|
||||||
766480,
|
|
||||||
47905,
|
|
||||||
2211,
|
|
||||||
67,
|
|
||||||
1
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_zip() {
|
|
||||||
assert_eq!(zip(vec![1, 2], vec![4, 5]), vec![(1, 4), (2, 5)]);
|
|
||||||
assert_eq!(zip(vec![1, 2, 3], vec![4, 5]), vec![(1, 4), (2, 5)]);
|
|
||||||
assert_eq!(zip(vec![1, 2], vec![4, 5, 6]), vec![(1, 4), (2, 5)]);
|
|
||||||
assert_eq!(zip(vec![], vec![4, 5]), vec![]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_fibonacci() {
|
|
||||||
assert_eq!(fibonacci(0), 1);
|
|
||||||
assert_eq!(fibonacci(1), 1);
|
|
||||||
assert_eq!(fibonacci(2), 2);
|
|
||||||
assert_eq!(fibonacci(3), 3);
|
|
||||||
assert_eq!(fibonacci(4), 5);
|
|
||||||
assert_eq!(fibonacci(5), 8);
|
|
||||||
assert_eq!(fibonacci(6), 13);
|
|
||||||
assert_eq!(fibonacci(7), 21);
|
|
||||||
assert_eq!(fibonacci(50), 20365011074);
|
|
||||||
assert_eq!(fibonacci(92), 12200160415121876738);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equivalence between two floating-point matrices, as element-wise equivalence
|
|
||||||
use std::cmp::PartialEq;
|
|
||||||
impl PartialEq for FMat2 {
|
|
||||||
fn eq(&self, other: &FMat2) -> bool {
|
|
||||||
self.a == other.a && self.b == other.b && self.c == other.c && self.d == other.d
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_inverse() {
|
|
||||||
assert_eq!(
|
|
||||||
FMat2 {
|
|
||||||
a: 1.0,
|
|
||||||
b: 1.0,
|
|
||||||
c: 2.0,
|
|
||||||
d: 3.0
|
|
||||||
}
|
|
||||||
.inverse(),
|
|
||||||
FMat2 {
|
|
||||||
a: 3.0,
|
|
||||||
b: -1.0,
|
|
||||||
c: -2.0,
|
|
||||||
d: 1.0
|
|
||||||
}
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
FMat2 {
|
|
||||||
a: 2.0,
|
|
||||||
b: 3.0,
|
|
||||||
c: 5.0,
|
|
||||||
d: 7.0
|
|
||||||
}
|
|
||||||
.inverse(),
|
|
||||||
FMat2 {
|
|
||||||
a: -7.0,
|
|
||||||
b: 3.0,
|
|
||||||
c: 5.0,
|
|
||||||
d: -2.0
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_lyrics() {
|
|
||||||
assert_eq!(twelve_days_of_christmas_lyrics(), LYRICS)
|
|
||||||
}
|
|
||||||
|
|
||||||
const LYRICS: &str = r#"On the first day of Christmas, my true love sent to me
|
|
||||||
A partridge in a pear tree
|
|
||||||
|
|
||||||
On the second day of Christmas, my true love sent to me
|
|
||||||
Two turtledoves
|
|
||||||
And a partridge in a pear tree
|
|
||||||
|
|
||||||
On the third day of Christmas, my true love sent to me
|
|
||||||
Three French hens
|
|
||||||
Two turtledoves
|
|
||||||
And a partridge in a pear tree
|
|
||||||
|
|
||||||
On the fourth day of Christmas, my true love sent to me
|
|
||||||
Four calling birds
|
|
||||||
Three French hens
|
|
||||||
Two turtledoves
|
|
||||||
And a partridge in a pear tree
|
|
||||||
|
|
||||||
On the fifth day of Christmas, my true love sent to me
|
|
||||||
Five gold rings (five golden rings)
|
|
||||||
Four calling birds
|
|
||||||
Three French hens
|
|
||||||
Two turtledoves
|
|
||||||
And a partridge in a pear tree
|
|
||||||
|
|
||||||
On the sixth day of Christmas, my true love sent to me
|
|
||||||
Six geese a-laying
|
|
||||||
Five gold rings (five golden rings)
|
|
||||||
Four calling birds
|
|
||||||
Three French hens
|
|
||||||
Two turtledoves
|
|
||||||
And a partridge in a pear tree
|
|
||||||
|
|
||||||
On the seventh day of Christmas, my true love sent to me
|
|
||||||
Seven swans a-swimming
|
|
||||||
Six geese a-laying
|
|
||||||
Five gold rings (five golden rings)
|
|
||||||
Four calling birds
|
|
||||||
Three French hens
|
|
||||||
Two turtledoves
|
|
||||||
And a partridge in a pear tree
|
|
||||||
|
|
||||||
On the eighth day of Christmas, my true love sent to me
|
|
||||||
Eight maids a-milking
|
|
||||||
Seven swans a-swimming
|
|
||||||
Six geese a-laying
|
|
||||||
Five gold rings (five golden rings)
|
|
||||||
Four calling birds
|
|
||||||
Three French hens
|
|
||||||
Two turtledoves
|
|
||||||
And a partridge in a pear tree
|
|
||||||
|
|
||||||
On the ninth day of Christmas, my true love sent to me
|
|
||||||
Nine ladies dancing
|
|
||||||
Eight maids a-milking
|
|
||||||
Seven swans a-swimming
|
|
||||||
Six geese a-laying
|
|
||||||
Five gold rings (five golden rings)
|
|
||||||
Four calling birds
|
|
||||||
Three French hens
|
|
||||||
Two turtledoves
|
|
||||||
And a partridge in a pear tree
|
|
||||||
|
|
||||||
On the tenth day of Christmas, my true love sent to me
|
|
||||||
Ten lords a-leaping
|
|
||||||
Nine ladies dancing
|
|
||||||
Eight maids a-milking
|
|
||||||
Seven swans a-swimming
|
|
||||||
Six geese a-laying
|
|
||||||
Five gold rings (five golden rings)
|
|
||||||
Four calling birds
|
|
||||||
Three French hens
|
|
||||||
Two turtledoves
|
|
||||||
And a partridge in a pear tree
|
|
||||||
|
|
||||||
On the eleventh day of Christmas, my true love sent to me
|
|
||||||
I sent eleven pipers piping
|
|
||||||
Ten lords a-leaping
|
|
||||||
Nine ladies dancing
|
|
||||||
Eight maids a-milking
|
|
||||||
Seven swans a-swimming
|
|
||||||
Six geese a-laying
|
|
||||||
Five gold rings (five golden rings)
|
|
||||||
Four calling birds
|
|
||||||
Three French hens
|
|
||||||
Two turtledoves
|
|
||||||
And a partridge in a pear tree
|
|
||||||
|
|
||||||
On the twelfth day of Christmas, my true love sent to me
|
|
||||||
Twelve drummers drumming
|
|
||||||
Eleven pipers piping
|
|
||||||
Ten lords a-leaping
|
|
||||||
Nine ladies dancing
|
|
||||||
Eight maids a-milking
|
|
||||||
Seven swans a-swimming
|
|
||||||
Six geese a-laying
|
|
||||||
Five gold rings (five golden rings)
|
|
||||||
Four calling birds
|
|
||||||
Three French hens
|
|
||||||
Two turtledoves
|
|
||||||
And a partridge in a pear tree
|
|
||||||
|
|
||||||
And a partridge in a pear tree
|
|
||||||
"#;
|
|
||||||
}
|
|
||||||
@@ -1,288 +0,0 @@
|
|||||||
//! Assignment 3: Mastering common programming concepts (2/2)
|
|
||||||
//!
|
|
||||||
//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-03.sh` works fine.
|
|
||||||
//! See `assignment03_grade.rs` and `/scripts/grade-03.sh` for the test script.
|
|
||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
/// Day of week.
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum DayOfWeek {
|
|
||||||
/// Sunday.
|
|
||||||
Sun,
|
|
||||||
/// Monday.
|
|
||||||
Mon,
|
|
||||||
/// Tuesday.
|
|
||||||
Tue,
|
|
||||||
/// Wednesday.
|
|
||||||
Wed,
|
|
||||||
/// Thursday.
|
|
||||||
Thu,
|
|
||||||
/// Friday.
|
|
||||||
Fri,
|
|
||||||
/// Saturday.
|
|
||||||
Sat,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The next day of week.
|
|
||||||
///
|
|
||||||
/// `next_weekday(Thu)` is `Fri`; and `next_weekday(Fri)` is `Mon`.
|
|
||||||
pub fn next_weekday(day: DayOfWeek) -> DayOfWeek {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Custom option type.
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum MyOption<T> {
|
|
||||||
/// Some value of type `T`.
|
|
||||||
MySome(T),
|
|
||||||
/// No value.
|
|
||||||
MyNone,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Maps an `MyOption<T>` to `MyOption<U>` by applying a function to a contained value.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// Converts an `MyOption<String>` into an `MyOption<usize>`, consuming the original:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use cs220::assignments::assignment03::{my_map, MyOption};
|
|
||||||
///
|
|
||||||
/// fn len(s: String) -> usize {
|
|
||||||
/// s.len()
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// assert_eq!(my_map(MyOption::MySome(String::from("Hello, World!")), len), MyOption::MySome(13));
|
|
||||||
/// assert_eq!(my_map(MyOption::MyNone, len), MyOption::MyNone);
|
|
||||||
/// ```
|
|
||||||
pub fn my_map<T, U, F: FnOnce(T) -> U>(v: MyOption<T>, f: F) -> MyOption<U> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `MyNone` if the option is `MyNone`, otherwise calls `f` with the wrapped value and returns the result.
|
|
||||||
///
|
|
||||||
/// Some languages call this operation flatmap.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use cs220::assignments::assignment03::{MyOption, my_and_then};
|
|
||||||
///
|
|
||||||
/// fn pos_then_to_string(x: isize) -> MyOption<String> {
|
|
||||||
/// if x > 0 {
|
|
||||||
/// MyOption::MySome(x.to_string())
|
|
||||||
/// } else {
|
|
||||||
/// MyOption::MyNone
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// assert_eq!(my_and_then(MyOption::MySome(2), pos_then_to_string), MyOption::MySome(2.to_string()));
|
|
||||||
/// assert_eq!(my_and_then(MyOption::MySome(-3), pos_then_to_string), MyOption::MyNone);
|
|
||||||
/// assert_eq!(my_and_then(MyOption::MyNone, pos_then_to_string), MyOption::MyNone);
|
|
||||||
/// ```
|
|
||||||
pub fn my_and_then<T, U, F: FnOnce(T) -> MyOption<U>>(v: MyOption<T>, f: F) -> MyOption<U> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given a list of integers, returns its median (when sorted, the value in the middle position).
|
|
||||||
///
|
|
||||||
/// For a data set `x` of `n` elements, the median can be defined as follows:
|
|
||||||
///
|
|
||||||
/// - If `n` is odd, the median is `(n+1)/2`-th smallest element of `x`.
|
|
||||||
/// - If `n` is even, the median is `(n/2)+1`-th smallest element of `x`.
|
|
||||||
///
|
|
||||||
/// For example, the following list of seven numbers,
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// vec![1, 3, 3, 6, 7, 8, 9]
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// has the median of 6, which is the fourth value. And for this data set of eight numbers,
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// vec![1, 2, 3, 4, 5, 6, 8, 9]
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// it has the median of 5, which is the fifth value.
|
|
||||||
///
|
|
||||||
/// Returns `None` if the list is empty.
|
|
||||||
pub fn median(values: Vec<isize>) -> Option<isize> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given a list of integers, returns its smallest mode (the value that occurs most often; a hash map will be helpful here).
|
|
||||||
///
|
|
||||||
/// Returns `None` if the list is empty.
|
|
||||||
pub fn mode(values: Vec<isize>) -> Option<isize> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts the given string to Pig Latin. Use the rules below to translate normal English into Pig Latin.
|
|
||||||
///
|
|
||||||
/// 1. If a word starts with a consonant and a vowel, move the first letter of the word at the end of the word and add "ay".
|
|
||||||
///
|
|
||||||
/// Example: "happy" -> "appyh" + "ay" -> "appyhay"
|
|
||||||
///
|
|
||||||
/// 2. If a word starts with multiple consonants, move them to the end of the word and add "ay".
|
|
||||||
///
|
|
||||||
/// Example: "string" -> "ingstr" + "ay" -> "ingstray"
|
|
||||||
///
|
|
||||||
/// 3. If a word starts with a vowel, add the word "hay" at the end of the word.
|
|
||||||
///
|
|
||||||
/// Example: "explain" -> "explain" + "hay" -> "explainhay"
|
|
||||||
///
|
|
||||||
/// Keep in mind the details about UTF-8 encoding!
|
|
||||||
///
|
|
||||||
/// You may assume the string only contains lowercase alphabets, and it contains at least one vowel.
|
|
||||||
pub fn piglatin(input: String) -> String {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts HR commands to the organization table.
|
|
||||||
///
|
|
||||||
/// If the commands are as follows:
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// vec!["Add Amir to Engineering", "Add Sally to Sales", "Remove Jeehoon from Sales", "Move Amir from Engineering to Sales"]
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// The return value should be:
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// ["Sales" -> ["Amir", "Sally"]]
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// - The result is a map from department to the list of its employees.
|
|
||||||
/// - An empty department should not appear in the result.
|
|
||||||
/// - There are three commands: "Add {person} to {department}", "Remove {person} from {department}", and "Move {person} from {department} to {department}".
|
|
||||||
/// - If a command is not executable, then it's ignored.
|
|
||||||
/// - There is no space in the name of the person and department.
|
|
||||||
///
|
|
||||||
/// See the test function for more details.
|
|
||||||
pub fn organize(commands: Vec<String>) -> HashMap<String, HashSet<String>> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Custom operator: `option_op_or(v1, v2, f)`
|
|
||||||
/// If neither `v1` nor `v2` is `Some`, returns `None`.
|
|
||||||
/// If exactly one is `Some`, returns the same `Some` value.
|
|
||||||
/// If both are `Some`, apply the values inside `Some` to `f` and wrap the resulting value inside `Some`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// fn product(a: i32, b: i32) -> i32 {
|
|
||||||
/// a * b
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// assert_eq!(option_op_or(None, None, product), None);
|
|
||||||
/// assert_eq!(option_op_or(Some(3), None, product), Some(3));
|
|
||||||
/// assert_eq!(option_op_or(Some(3), Some(5), product), Some(15));
|
|
||||||
/// ```
|
|
||||||
pub fn option_op_or<T, F: FnOnce(T, T) -> T>(v1: Option<T>, v2: Option<T>, f: F) -> Option<T> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Events in a text editor.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum TypeEvent {
|
|
||||||
/// A character is typed.
|
|
||||||
Type(char),
|
|
||||||
/// The last character is removed.
|
|
||||||
Backspace,
|
|
||||||
/// The whole string is copied to the clipboard.
|
|
||||||
Copy,
|
|
||||||
/// The string in the clipboard is appended.
|
|
||||||
Paste,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Starting from an empty string and an empty clipboard,
|
|
||||||
/// processes the given `events` in order and returns the resulting string.
|
|
||||||
///
|
|
||||||
/// See the test function `test_editor` for examples.
|
|
||||||
pub fn use_editor(events: Vec<TypeEvent>) -> String {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse the string as a shell command.
|
|
||||||
///
|
|
||||||
/// Usually, a shell command is whitespace-separated array of strings.
|
|
||||||
/// ```text
|
|
||||||
/// cat file --> ["cat", "file"]
|
|
||||||
/// ```
|
|
||||||
/// But sometimes, you may want to include whitespaces in each argument.
|
|
||||||
/// In that case, you can use quotes.
|
|
||||||
/// ```text
|
|
||||||
/// ls 'VirtualBox VMs' --> ["ls", 'VirtualBox VMs']
|
|
||||||
/// ls VirtualBox' 'VMs --> ["ls", 'VirtualBox VMs']
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// For simplicity, you may assume that the string only contains alphanumeric characters, spaces
|
|
||||||
/// (" "), and single quotes ("'").
|
|
||||||
///
|
|
||||||
/// See `test_shell` for more examples.
|
|
||||||
pub fn parse_shell_command(command: &str) -> Vec<String> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents a JSON value. See https://en.wikipedia.org/wiki/JSON.
|
|
||||||
///
|
|
||||||
/// For simplicity, you may assume that numbers are of type `i64`, and strings do not contain
|
|
||||||
/// special characters that need to be escaped (e.g. '"', '\n', ...).
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
pub enum JsonValue {
|
|
||||||
/// null
|
|
||||||
Null,
|
|
||||||
/// true, false
|
|
||||||
Boolean(bool),
|
|
||||||
/// integers
|
|
||||||
Number(i64),
|
|
||||||
/// strings
|
|
||||||
String(String),
|
|
||||||
/// array of JSON values
|
|
||||||
Array(Vec<JsonValue>),
|
|
||||||
/// objects
|
|
||||||
Object(HashMap<String, JsonValue>),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse a string into a JSON value. Returns `Err(())` if it contains syntax errors.
|
|
||||||
///
|
|
||||||
/// See `test_json` for examples.
|
|
||||||
pub fn parse_json(json_string: &str) -> Result<JsonValue, String> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for JsonValue {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
JsonValue::Null => write!(f, "null"),
|
|
||||||
JsonValue::Boolean(b) => write!(f, "{}", b),
|
|
||||||
JsonValue::Number(n) => write!(f, "{}", n),
|
|
||||||
JsonValue::String(s) => write!(f, "\"{}\"", s),
|
|
||||||
JsonValue::Array(arr) => {
|
|
||||||
write!(f, "[")?;
|
|
||||||
let mut iter = arr.iter();
|
|
||||||
if let Some(item) = iter.next() {
|
|
||||||
write!(f, "{}", item)?;
|
|
||||||
for item in iter {
|
|
||||||
write!(f, ", {}", item)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
write!(f, "]")
|
|
||||||
}
|
|
||||||
JsonValue::Object(obj) => {
|
|
||||||
write!(f, "{{")?;
|
|
||||||
let mut iter = obj.iter();
|
|
||||||
if let Some((key, value)) = iter.next() {
|
|
||||||
write!(f, "\"{}\": {}", key, value)?;
|
|
||||||
for (key, value) in iter {
|
|
||||||
write!(f, ", \"{}\": {}", key, value)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
write!(f, "}}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
79
src/assignments/assignment03/custom_operators.rs
Normal file
79
src/assignments/assignment03/custom_operators.rs
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
//! You will implement a number of custom operators.
|
||||||
|
|
||||||
|
/// Custom option type.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum MyOption<T> {
|
||||||
|
/// Some value of type `T`.
|
||||||
|
MySome(T),
|
||||||
|
/// No value.
|
||||||
|
MyNone,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Maps an `MyOption<T>` to `MyOption<U>` by applying a function to a contained value.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Converts an `MyOption<String>` into an `MyOption<usize>`, consuming the original:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use cs220::assignments::assignment03::{my_map, MyOption};
|
||||||
|
///
|
||||||
|
/// fn len(s: String) -> usize {
|
||||||
|
/// s.len()
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// assert_eq!(my_map(MyOption::MySome(String::from("Hello, World!")), len), MyOption::MySome(13));
|
||||||
|
/// assert_eq!(my_map(MyOption::MyNone, len), MyOption::MyNone);
|
||||||
|
/// ```
|
||||||
|
pub fn my_map<T, U, F: FnOnce(T) -> U>(v: MyOption<T>, f: F) -> MyOption<U> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `MyNone` if the option is `MyNone`, otherwise calls `f` with the wrapped value and returns the result.
|
||||||
|
///
|
||||||
|
/// Some languages call this operation flatmap.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use cs220::assignments::assignment03::{MyOption, my_and_then};
|
||||||
|
///
|
||||||
|
/// fn pos_then_to_string(x: isize) -> MyOption<String> {
|
||||||
|
/// if x > 0 {
|
||||||
|
/// MyOption::MySome(x.to_string())
|
||||||
|
/// } else {
|
||||||
|
/// MyOption::MyNone
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// assert_eq!(my_and_then(MyOption::MySome(2), pos_then_to_string), MyOption::MySome(2.to_string()));
|
||||||
|
/// assert_eq!(my_and_then(MyOption::MySome(-3), pos_then_to_string), MyOption::MyNone);
|
||||||
|
/// assert_eq!(my_and_then(MyOption::MyNone, pos_then_to_string), MyOption::MyNone);
|
||||||
|
/// ```
|
||||||
|
pub fn my_and_then<T, U, F: FnOnce(T) -> MyOption<U>>(v: MyOption<T>, f: F) -> MyOption<U> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Custom operator: `option_op_or(v1, v2, f)`
|
||||||
|
/// If neither `v1` nor `v2` is `Some`, returns `None`.
|
||||||
|
/// If exactly one is `Some`, returns the same `Some` value.
|
||||||
|
/// If both are `Some`, apply the values inside `Some` to `f` and wrap the resulting value inside `Some`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// fn product(a: i32, b: i32) -> i32 {
|
||||||
|
/// a * b
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// assert_eq!(option_op_or(None, None, product), None);
|
||||||
|
/// assert_eq!(option_op_or(Some(3), None, product), Some(3));
|
||||||
|
/// assert_eq!(option_op_or(Some(3), Some(5), product), Some(15));
|
||||||
|
/// ```
|
||||||
|
pub fn my_option_op_or<T, F: FnOnce(T, T) -> T>(
|
||||||
|
v1: MyOption<T>,
|
||||||
|
v2: MyOption<T>,
|
||||||
|
f: F,
|
||||||
|
) -> MyOption<T> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
58
src/assignments/assignment03/custom_operators_grade.rs
Normal file
58
src/assignments/assignment03/custom_operators_grade.rs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::assignments::assignment03::custom_operators::{MyOption::*, *};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_my_map() {
|
||||||
|
fn len(s: &str) -> usize {
|
||||||
|
s.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn plus_one(x: isize) -> isize {
|
||||||
|
x + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_positive(x: f64) -> bool {
|
||||||
|
x > 0.0f64
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(my_map(MySome("Hello, World!"), len), MySome(13));
|
||||||
|
assert_eq!(my_map(MyNone, len), MyNone);
|
||||||
|
|
||||||
|
assert_eq!(my_map(MySome(1), plus_one), MySome(2));
|
||||||
|
assert_eq!(my_map(MyNone, plus_one), MyNone);
|
||||||
|
|
||||||
|
assert_eq!(my_map(MySome(5.0f64), is_positive), MySome(true));
|
||||||
|
assert_eq!(my_map(MySome(-3.0f64), is_positive), MySome(false));
|
||||||
|
assert_eq!(my_map(MyNone::<f64>, is_positive), MyNone);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_my_and_then() {
|
||||||
|
fn plus_one(x: isize) -> MyOption<isize> {
|
||||||
|
MySome(x + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn none(_: isize) -> MyOption<isize> {
|
||||||
|
MyNone
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(my_and_then(MySome(1), plus_one), MySome(2));
|
||||||
|
assert_eq!(my_and_then(MySome(1), none), MyNone);
|
||||||
|
|
||||||
|
assert_eq!(my_and_then(MyNone, plus_one), MyNone);
|
||||||
|
assert_eq!(my_and_then(MyNone, none), MyNone);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn product(a: i32, b: i32) -> i32 {
|
||||||
|
a * b
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_my_option_op_or() {
|
||||||
|
assert_eq!(my_option_op_or(MyNone, MyNone, product), MyNone);
|
||||||
|
assert_eq!(my_option_op_or(MySome(3), MyNone, product), MySome(3));
|
||||||
|
assert_eq!(my_option_op_or(MyNone, MySome(5), product), MySome(5));
|
||||||
|
assert_eq!(my_option_op_or(MySome(3), MySome(5), product), MySome(15));
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/assignments/assignment03/mod.rs
Normal file
13
src/assignments/assignment03/mod.rs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
//! Assignment 3: Mastering common programming concepts (2/2)
|
||||||
|
//!
|
||||||
|
//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-03.sh` works fine.
|
||||||
|
//! See `*_grade.rs` and `/scripts/grade-03.sh` for the test script.
|
||||||
|
|
||||||
|
pub mod small_problems;
|
||||||
|
mod small_problems_grade;
|
||||||
|
|
||||||
|
pub mod parse_shell;
|
||||||
|
mod parse_shell_grade;
|
||||||
|
|
||||||
|
pub mod custom_operators;
|
||||||
|
mod custom_operators_grade;
|
||||||
28
src/assignments/assignment03/parse_shell.rs
Normal file
28
src/assignments/assignment03/parse_shell.rs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
//! Parsing a shell command.
|
||||||
|
//!
|
||||||
|
//! Shell commands are text-based instructions that you can enter in a command-line interface (CLI)
|
||||||
|
//! to interact with operating systems (e.g. Linux) and others.
|
||||||
|
//! For example, you can use the `ls` command to list files in a directory.
|
||||||
|
//!
|
||||||
|
//! You will parse a given string consists of a small number of shell commands.
|
||||||
|
|
||||||
|
/// Parse the string as a shell command.
|
||||||
|
///
|
||||||
|
/// Usually, a shell command is whitespace-separated array of strings.
|
||||||
|
/// ```text
|
||||||
|
/// cat file --> ["cat", "file"]
|
||||||
|
/// ```
|
||||||
|
/// But sometimes, you may want to include whitespaces in each argument.
|
||||||
|
/// In that case, you can use quotes.
|
||||||
|
/// ```text
|
||||||
|
/// ls 'VirtualBox VMs' --> ["ls", 'VirtualBox VMs']
|
||||||
|
/// ls VirtualBox' 'VMs --> ["ls", 'VirtualBox VMs']
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// For simplicity, you may assume that the string only contains alphanumeric characters, spaces
|
||||||
|
/// (" "), and single quotes ("'").
|
||||||
|
///
|
||||||
|
/// See `test_shell` for more examples.
|
||||||
|
pub fn parse_shell_command(command: &str) -> Vec<String> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
38
src/assignments/assignment03/parse_shell_grade.rs
Normal file
38
src/assignments/assignment03/parse_shell_grade.rs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::assignments::assignment03::parse_shell::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_shell() {
|
||||||
|
assert_eq!(
|
||||||
|
parse_shell_command("cat file"),
|
||||||
|
vec!["cat".to_string(), "file".to_string()]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
parse_shell_command("ls 'VirtualBox VMs'"),
|
||||||
|
vec!["ls".to_string(), "VirtualBox VMs".to_string()]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
parse_shell_command("ls VirtualBox' 'VMs"),
|
||||||
|
vec!["ls".to_string(), "VirtualBox VMs".to_string()]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
parse_shell_command("echo once upon a midnight dreary"),
|
||||||
|
vec![
|
||||||
|
"echo".to_string(),
|
||||||
|
"once".to_string(),
|
||||||
|
"upon".to_string(),
|
||||||
|
"a".to_string(),
|
||||||
|
"midnight".to_string(),
|
||||||
|
"dreary".to_string(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
parse_shell_command("echo 'once upon a midnight dreary'"),
|
||||||
|
vec![
|
||||||
|
"echo".to_string(),
|
||||||
|
"once upon a midnight dreary".to_string(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
130
src/assignments/assignment03/small_problems.rs
Normal file
130
src/assignments/assignment03/small_problems.rs
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
//! Small problems.
|
||||||
|
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// Day of week.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum DayOfWeek {
|
||||||
|
/// Sunday.
|
||||||
|
Sun,
|
||||||
|
/// Monday.
|
||||||
|
Mon,
|
||||||
|
/// Tuesday.
|
||||||
|
Tue,
|
||||||
|
/// Wednesday.
|
||||||
|
Wed,
|
||||||
|
/// Thursday.
|
||||||
|
Thu,
|
||||||
|
/// Friday.
|
||||||
|
Fri,
|
||||||
|
/// Saturday.
|
||||||
|
Sat,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The next day of week.
|
||||||
|
///
|
||||||
|
/// `next_weekday(Thu)` is `Fri`; and `next_weekday(Fri)` is `Mon`.
|
||||||
|
pub fn next_weekday(day: DayOfWeek) -> DayOfWeek {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given a list of integers, returns its median (when sorted, the value in the middle position).
|
||||||
|
///
|
||||||
|
/// For a data set `x` of `n` elements, the median can be defined as follows:
|
||||||
|
///
|
||||||
|
/// - If `n` is odd, the median is `(n+1)/2`-th smallest element of `x`.
|
||||||
|
/// - If `n` is even, the median is `(n/2)+1`-th smallest element of `x`.
|
||||||
|
///
|
||||||
|
/// For example, the following list of seven numbers,
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// vec![1, 3, 3, 6, 7, 8, 9]
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// has the median of 6, which is the fourth value. And for this data set of eight numbers,
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// vec![1, 2, 3, 4, 5, 6, 8, 9]
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// it has the median of 5, which is the fifth value.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the list is empty.
|
||||||
|
pub fn median(values: Vec<isize>) -> Option<isize> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given a list of integers, returns its smallest mode (the value that occurs most often; a hash map will be helpful here).
|
||||||
|
///
|
||||||
|
/// Returns `None` if the list is empty.
|
||||||
|
pub fn mode(values: Vec<isize>) -> Option<isize> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts the given string to Pig Latin. Use the rules below to translate normal English into Pig Latin.
|
||||||
|
///
|
||||||
|
/// 1. If a word starts with a consonant and a vowel, move the first letter of the word at the end of the word and add "ay".
|
||||||
|
///
|
||||||
|
/// Example: "happy" -> "appyh" + "ay" -> "appyhay"
|
||||||
|
///
|
||||||
|
/// 2. If a word starts with multiple consonants, move them to the end of the word and add "ay".
|
||||||
|
///
|
||||||
|
/// Example: "string" -> "ingstr" + "ay" -> "ingstray"
|
||||||
|
///
|
||||||
|
/// 3. If a word starts with a vowel, add the word "hay" at the end of the word.
|
||||||
|
///
|
||||||
|
/// Example: "explain" -> "explain" + "hay" -> "explainhay"
|
||||||
|
///
|
||||||
|
/// Keep in mind the details about UTF-8 encoding!
|
||||||
|
///
|
||||||
|
/// You may assume the string only contains lowercase alphabets, and it contains at least one vowel.
|
||||||
|
pub fn piglatin(input: String) -> String {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts HR commands to the organization table.
|
||||||
|
///
|
||||||
|
/// If the commands are as follows:
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// vec!["Add Amir to Engineering", "Add Sally to Sales", "Remove Jeehoon from Sales", "Move Amir from Engineering to Sales"]
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The return value should be:
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// ["Sales" -> ["Amir", "Sally"]]
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// - The result is a map from department to the list of its employees.
|
||||||
|
/// - An empty department should not appear in the result.
|
||||||
|
/// - There are three commands: "Add {person} to {department}", "Remove {person} from {department}", and "Move {person} from {department} to {department}".
|
||||||
|
/// - If a command is not executable, then it's ignored.
|
||||||
|
/// - There is no space in the name of the person and department.
|
||||||
|
///
|
||||||
|
/// See the test function for more details.
|
||||||
|
pub fn organize(commands: Vec<String>) -> HashMap<String, HashSet<String>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Events in a text editor.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum TypeEvent {
|
||||||
|
/// A character is typed.
|
||||||
|
Type(char),
|
||||||
|
/// The last character is removed.
|
||||||
|
Backspace,
|
||||||
|
/// The whole string is copied to the clipboard.
|
||||||
|
Copy,
|
||||||
|
/// The string in the clipboard is appended.
|
||||||
|
Paste,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Starting from an empty string and an empty clipboard,
|
||||||
|
/// processes the given `events` in order and returns the resulting string.
|
||||||
|
///
|
||||||
|
/// See the test function `test_editor` for examples.
|
||||||
|
pub fn use_editor(events: Vec<TypeEvent>) -> String {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::super::assignment03::*;
|
use crate::assignments::assignment03::small_problems::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_next_weekday() {
|
fn test_next_weekday() {
|
||||||
@@ -13,52 +13,6 @@ mod test {
|
|||||||
assert_eq!(next_weekday(DayOfWeek::Sat), DayOfWeek::Mon);
|
assert_eq!(next_weekday(DayOfWeek::Sat), DayOfWeek::Mon);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_my_map() {
|
|
||||||
use MyOption::*;
|
|
||||||
|
|
||||||
fn len(s: &str) -> usize {
|
|
||||||
s.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn plus_one(x: isize) -> isize {
|
|
||||||
x + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_positive(x: f64) -> bool {
|
|
||||||
x > 0.0f64
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(my_map(MySome("Hello, World!"), len), MySome(13));
|
|
||||||
assert_eq!(my_map(MyNone, len), MyNone);
|
|
||||||
|
|
||||||
assert_eq!(my_map(MySome(1), plus_one), MySome(2));
|
|
||||||
assert_eq!(my_map(MyNone, plus_one), MyNone);
|
|
||||||
|
|
||||||
assert_eq!(my_map(MySome(5.0f64), is_positive), MySome(true));
|
|
||||||
assert_eq!(my_map(MySome(-3.0f64), is_positive), MySome(false));
|
|
||||||
assert_eq!(my_map(MyNone::<f64>, is_positive), MyNone);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_my_and_then() {
|
|
||||||
use MyOption::*;
|
|
||||||
|
|
||||||
fn plus_one(x: isize) -> MyOption<isize> {
|
|
||||||
MySome(x + 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn none(_: isize) -> MyOption<isize> {
|
|
||||||
MyNone
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(my_and_then(MySome(1), plus_one), MySome(2));
|
|
||||||
assert_eq!(my_and_then(MySome(1), none), MyNone);
|
|
||||||
|
|
||||||
assert_eq!(my_and_then(MyNone, plus_one), MyNone);
|
|
||||||
assert_eq!(my_and_then(MyNone, none), MyNone);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_median() {
|
fn test_median() {
|
||||||
assert_eq!(median(vec![]), None);
|
assert_eq!(median(vec![]), None);
|
||||||
@@ -166,18 +120,6 @@ mod test {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn product(a: i32, b: i32) -> i32 {
|
|
||||||
a * b
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_option_op_or() {
|
|
||||||
assert_eq!(option_op_or(None, None, product), None);
|
|
||||||
assert_eq!(option_op_or(Some(3), None, product), Some(3));
|
|
||||||
assert_eq!(option_op_or(None, Some(5), product), Some(5));
|
|
||||||
assert_eq!(option_op_or(Some(3), Some(5), product), Some(15));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_editor() {
|
fn test_editor() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -234,93 +176,4 @@ mod test {
|
|||||||
""
|
""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_shell() {
|
|
||||||
assert_eq!(
|
|
||||||
parse_shell_command("cat file"),
|
|
||||||
vec!["cat".to_string(), "file".to_string()]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
parse_shell_command("ls 'VirtualBox VMs'"),
|
|
||||||
vec!["ls".to_string(), "VirtualBox VMs".to_string()]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
parse_shell_command("ls VirtualBox' 'VMs"),
|
|
||||||
vec!["ls".to_string(), "VirtualBox VMs".to_string()]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
parse_shell_command("echo once upon a midnight dreary"),
|
|
||||||
vec![
|
|
||||||
"echo".to_string(),
|
|
||||||
"once".to_string(),
|
|
||||||
"upon".to_string(),
|
|
||||||
"a".to_string(),
|
|
||||||
"midnight".to_string(),
|
|
||||||
"dreary".to_string(),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
parse_shell_command("echo 'once upon a midnight dreary'"),
|
|
||||||
vec![
|
|
||||||
"echo".to_string(),
|
|
||||||
"once upon a midnight dreary".to_string(),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_json() {
|
|
||||||
use std::collections::HashMap;
|
|
||||||
let json_str = r#"{
|
|
||||||
"name": "John Doe",
|
|
||||||
"age": 30,
|
|
||||||
"city": "New York",
|
|
||||||
"active": true,
|
|
||||||
"address": {
|
|
||||||
"street": "123 Main St",
|
|
||||||
"zipCode": "10001"
|
|
||||||
},
|
|
||||||
"skills": ["Rust", "Python", "JavaScript"],
|
|
||||||
"organization": null
|
|
||||||
}"#;
|
|
||||||
println!("{}", parse_json(json_str).unwrap());
|
|
||||||
assert_eq!(
|
|
||||||
parse_json(json_str),
|
|
||||||
Ok(JsonValue::Object(HashMap::from([
|
|
||||||
(
|
|
||||||
"name".to_string(),
|
|
||||||
JsonValue::String("John Doe".to_string())
|
|
||||||
),
|
|
||||||
("age".to_string(), JsonValue::Number(30)),
|
|
||||||
(
|
|
||||||
"city".to_string(),
|
|
||||||
JsonValue::String("New York".to_string())
|
|
||||||
),
|
|
||||||
("active".to_string(), JsonValue::Boolean(true)),
|
|
||||||
(
|
|
||||||
"address".to_string(),
|
|
||||||
JsonValue::Object(HashMap::from([
|
|
||||||
(
|
|
||||||
"street".to_string(),
|
|
||||||
JsonValue::String("123 Main St".to_string())
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"zipCode".to_string(),
|
|
||||||
JsonValue::String("10001".to_string())
|
|
||||||
)
|
|
||||||
]))
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"skills".to_string(),
|
|
||||||
JsonValue::Array(vec![
|
|
||||||
JsonValue::String("Rust".to_string()),
|
|
||||||
JsonValue::String("Python".to_string()),
|
|
||||||
JsonValue::String("JavaScript".to_string())
|
|
||||||
])
|
|
||||||
),
|
|
||||||
("organization".to_string(), JsonValue::Null),
|
|
||||||
])))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -9,9 +9,7 @@
|
|||||||
pub mod assignment01;
|
pub mod assignment01;
|
||||||
mod assignment01_grade;
|
mod assignment01_grade;
|
||||||
pub mod assignment02;
|
pub mod assignment02;
|
||||||
mod assignment02_grade;
|
|
||||||
pub mod assignment03;
|
pub mod assignment03;
|
||||||
mod assignment03_grade;
|
|
||||||
pub mod assignment04;
|
pub mod assignment04;
|
||||||
pub mod assignment06;
|
pub mod assignment06;
|
||||||
pub mod assignment07;
|
pub mod assignment07;
|
||||||
|
|||||||
Reference in New Issue
Block a user