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

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

@@ -0,0 +1,179 @@
#[cfg(test)]
mod test {
use crate::assignments::assignment03::small_problems::*;
#[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_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()
);
}
#[test]
fn test_editor() {
assert_eq!(
use_editor(vec![
TypeEvent::Type('a'),
TypeEvent::Backspace,
TypeEvent::Backspace,
TypeEvent::Type('b'),
TypeEvent::Type('c')
]),
"bc"
);
assert_eq!(
use_editor(vec![
TypeEvent::Type('a'),
TypeEvent::Copy,
TypeEvent::Paste,
TypeEvent::Paste,
TypeEvent::Type('b'),
TypeEvent::Copy,
TypeEvent::Paste
]),
"aaabaaab"
);
assert_eq!(
use_editor(vec![
TypeEvent::Paste, // clipboard starts empty
TypeEvent::Type('a'),
TypeEvent::Type('n'),
TypeEvent::Copy,
TypeEvent::Backspace,
TypeEvent::Backspace,
TypeEvent::Type('b'),
TypeEvent::Paste,
TypeEvent::Paste,
TypeEvent::Paste,
TypeEvent::Backspace
]),
"banana"
);
assert_eq!(
use_editor(vec![
TypeEvent::Copy,
TypeEvent::Backspace,
TypeEvent::Backspace,
TypeEvent::Paste,
TypeEvent::Paste,
TypeEvent::Copy,
TypeEvent::Backspace
]),
""
);
}
}