Add assignment 3

This commit is contained in:
Minseong Jang
2022-09-14 02:14:58 +09:00
parent 7b519daf3a
commit 27f0b78a2c
4 changed files with 337 additions and 0 deletions

34
scripts/grade-03.sh Executable file
View File

@@ -0,0 +1,34 @@
#!/usr/bin/env bash
set -e
set -uo pipefail
IFS=$'\n\t'
# Imports library.
BASEDIR=$(dirname "$0")
source $BASEDIR/grade-utils.sh
RUNNERS=(
"cargo"
"cargo --release"
"cargo_asan"
"cargo_asan --release"
"cargo_tsan"
"cargo_tsan --release"
)
# Lints.
cargo fmt --check
cargo clippy
# Executes test for each runner.
for RUNNER in "${RUNNERS[@]}"; do
echo "Running with $RUNNER..."
TESTS=("--lib assignment03_grade")
if [ $(run_tests) -ne 0 ]; then
exit 1
fi
done
exit 0

View File

@@ -0,0 +1,133 @@
//! Assignment 3: Mastering common programming concepts (2/2).
//!
//! The primary goal of this assignment is to re-learn the common programming concepts in Rust, especially those in the Rust Book chapters 6, 7, 8, and 9.
//! 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-03.sh` works fine.
//! See `assignment03_grade.rs` and `/scripts/grade-03.sh` for the test script.
use std::collections::{HashMap, HashSet};
/// 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 the inner value if the given value is `MySome`; returns `MyNone` otherwise.
pub fn my_map<T, U, F: FnOnce(T) -> U>(v: MyOption<T>, f: F) -> MyOption<U> {
todo!()
}
/// Maps the inner value if the given value is `MySome`, but with a different type of function; returns `MyNone` otherwise.
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,
///
/// ```
/// 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,
///
/// ```
/// 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:
///
/// ```
/// vec!["Add Amir to Engineering", "Add Sally to Sales", "Remove Jeehoon from Sales", "Move Amir from Engineering to Sales"]
/// ```
///
/// The return value should be:
///
/// ```
/// ["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!()
}

View File

@@ -0,0 +1,168 @@
#[cfg(test)]
mod test {
use super::super::assignment03::*;
#[test]
fn test_next_weekday() {
assert_eq!(next_weekday(DayOfWeek::Sun), DayOfWeek::Mon);
assert_eq!(next_weekday(DayOfWeek::Mon), DayOfWeek::Tue);
assert_eq!(next_weekday(DayOfWeek::Tue), DayOfWeek::Wed);
assert_eq!(next_weekday(DayOfWeek::Wed), DayOfWeek::Thu);
assert_eq!(next_weekday(DayOfWeek::Thu), DayOfWeek::Fri);
assert_eq!(next_weekday(DayOfWeek::Fri), 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]
fn test_median() {
assert_eq!(median(vec![]), None);
assert_eq!(median(vec![1]), Some(1));
assert_eq!(median(vec![1, 2]), Some(2));
assert_eq!(median(vec![2, 4, 5, 1, 3]), Some(3));
assert_eq!(median(vec![2, 3, 5, 7, 11, 13]), Some(7));
assert_eq!(median(vec![1, 3, 3, 6, 7, 8, 9]), Some(6));
assert_eq!(median(vec![6, 7, 3, 1, 9, 3, 8]), Some(6));
assert_eq!(median(vec![1, 2, 3, 4, 5, 6, 8, 9]), Some(5));
assert_eq!(median(vec![3, 4, 8, 9, 1, 6, 5, 2]), Some(5));
}
#[test]
fn test_mode() {
assert_eq!(mode(vec![]), None);
assert_eq!(mode(vec![3]), Some(3));
assert_eq!(mode(vec![2, 1, 2, 3]), Some(2));
assert_eq!(mode(vec![2, 3, 1, 2, 2, 3, 3]), Some(2));
assert_eq!(mode(vec![1, 1, 2, 2, 3, 3]), Some(1));
}
#[test]
fn test_piglatin() {
assert_eq!(piglatin("pig".to_string()), "igpay".to_string());
assert_eq!(piglatin("latin".to_string()), "atinlay".to_string());
assert_eq!(piglatin("banana".to_string()), "ananabay".to_string());
assert_eq!(piglatin("will".to_string()), "illway".to_string());
assert_eq!(piglatin("butler".to_string()), "utlerbay".to_string());
assert_eq!(piglatin("happy".to_string()), "appyhay".to_string());
assert_eq!(piglatin("duck".to_string()), "uckday".to_string());
assert_eq!(piglatin("me".to_string()), "emay".to_string());
assert_eq!(piglatin("bagel".to_string()), "agelbay".to_string());
assert_eq!(piglatin("history".to_string()), "istoryhay".to_string());
assert_eq!(piglatin("smile".to_string()), "ilesmay".to_string());
assert_eq!(piglatin("string".to_string()), "ingstray".to_string());
assert_eq!(piglatin("stupid".to_string()), "upidstay".to_string());
assert_eq!(piglatin("glove".to_string()), "oveglay".to_string());
assert_eq!(piglatin("trash".to_string()), "ashtray".to_string());
assert_eq!(piglatin("floor".to_string()), "oorflay".to_string());
assert_eq!(piglatin("store".to_string()), "orestay".to_string());
assert_eq!(piglatin("eat".to_string()), "eathay".to_string());
assert_eq!(piglatin("omelet".to_string()), "omelethay".to_string());
assert_eq!(piglatin("are".to_string()), "arehay".to_string());
assert_eq!(piglatin("egg".to_string()), "egghay".to_string());
assert_eq!(piglatin("explain".to_string()), "explainhay".to_string());
assert_eq!(piglatin("ends".to_string()), "endshay".to_string());
assert_eq!(piglatin("amulet".to_string()), "amulethay".to_string());
}
#[test]
fn test_organize() {
assert_eq!(
organize(vec![
"Add Amir to Engineering".to_string(),
"Add Sally to Sales".to_string(),
"Remove Jeehoon from Sales".to_string(),
"Move Amir from Engineering to Sales".to_string(),
]),
[(
"Sales".to_string(),
["Amir".to_string(), "Sally".to_string()].into()
)]
.into()
);
assert_eq!(
organize(vec![
"Add Jeehoon to Mathematics".to_string(),
"Add Minseong to Mathematics".to_string(),
"Add Seungmin to Computer-Science".to_string(),
"Move Jeehoon from Mathematics to Computer-Science".to_string(),
"Remove Minseong from Mathematics".to_string(),
"Add Minseong to Computer-Science".to_string(),
]),
[(
"Computer-Science".to_string(),
[
"Seungmin".to_string(),
"Jeehoon".to_string(),
"Minseong".to_string()
]
.into()
)]
.into()
);
assert_eq!(
organize(vec![
"Move P1 from D1 to D2".to_string(),
"Remove P2 from D2".to_string(),
"Add P3 to D3".to_string(),
"Add P4 to D1".to_string(),
"Add P3 to D4".to_string(),
"Move P3 from D4 to D2".to_string(),
]),
[
("D1".to_string(), ["P4".to_string()].into()),
("D2".to_string(), ["P3".to_string()].into()),
("D3".to_string(), ["P3".to_string()].into())
]
.into()
);
}
}

View File

@@ -7,3 +7,5 @@ pub mod assignment01;
mod assignment01_grade;
pub mod assignment02;
mod assignment02_grade;
pub mod assignment03;
mod assignment03_grade;