From 27f0b78a2ca3c20fd8622e0a5252d360c0501b9b Mon Sep 17 00:00:00 2001 From: Minseong Jang Date: Wed, 14 Sep 2022 02:14:58 +0900 Subject: [PATCH] Add assignment 3 --- scripts/grade-03.sh | 34 ++++++ src/assignments/assignment03.rs | 133 ++++++++++++++++++++ src/assignments/assignment03_grade.rs | 168 ++++++++++++++++++++++++++ src/assignments/mod.rs | 2 + 4 files changed, 337 insertions(+) create mode 100755 scripts/grade-03.sh create mode 100644 src/assignments/assignment03.rs create mode 100644 src/assignments/assignment03_grade.rs diff --git a/scripts/grade-03.sh b/scripts/grade-03.sh new file mode 100755 index 0000000..4223bcb --- /dev/null +++ b/scripts/grade-03.sh @@ -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 diff --git a/src/assignments/assignment03.rs b/src/assignments/assignment03.rs new file mode 100644 index 0000000..93e1b10 --- /dev/null +++ b/src/assignments/assignment03.rs @@ -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 { + /// 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 U>(v: MyOption, f: F) -> MyOption { + 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 MyOption>(v: MyOption, f: F) -> MyOption { + 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) -> Option { + 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) -> Option { + 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 to ", "Remove from ", and "Move from to ". +/// - 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) -> HashMap> { + todo!() +} diff --git a/src/assignments/assignment03_grade.rs b/src/assignments/assignment03_grade.rs new file mode 100644 index 0000000..f72f64b --- /dev/null +++ b/src/assignments/assignment03_grade.rs @@ -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::, is_positive), MyNone); + } + + #[test] + fn test_my_and_then() { + use MyOption::*; + + fn plus_one(x: isize) -> MyOption { + MySome(x + 1) + } + + fn none(_: isize) -> MyOption { + 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() + ); + } +} diff --git a/src/assignments/mod.rs b/src/assignments/mod.rs index 06c633a..a80e628 100644 --- a/src/assignments/mod.rs +++ b/src/assignments/mod.rs @@ -7,3 +7,5 @@ pub mod assignment01; mod assignment01_grade; pub mod assignment02; mod assignment02_grade; +pub mod assignment03; +mod assignment03_grade;