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:
AnHaechan
2023-08-21 07:13:27 +00:00
parent 24dc47a7cf
commit d28bca2b18
27 changed files with 863 additions and 938 deletions

View File

@@ -19,4 +19,4 @@ module BinarySearch
= =
(* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) (* IMPORTANT: DON'T MODIFY THE ABOVE LINES *)
0 (* TODO *) 0 (* TODO *)
end end

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View 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

View 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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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!()
}

View 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;

View 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!()
}

View 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![]);
}
}

View 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!()
}
}

View 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
}
);
}
}

View File

@@ -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
"#;
}

View File

@@ -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, "}}")
}
}
}
}

View 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!()
}

View 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));
}
}

View 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;

View 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!()
}

View 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(),
]
);
}
}

View 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!()
}

View File

@@ -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),
])))
);
}
} }

View File

@@ -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;