Skip to content

Commit be3d363

Browse files
committed
release: assignment 6
1 parent 09f12cc commit be3d363

File tree

6 files changed

+1143
-0
lines changed

6 files changed

+1143
-0
lines changed

assignment6/README.md

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# Assignment 6: Explore Courses
2+
3+
Due Saturday, November 22nd at 11:59PM
4+
5+
## Overview
6+
7+
In this assignment you will be exercising your understanding of `std::optional`. We'll be making use of the same `courses.csv` from assignment 1. You are tasked to write one function for this assignment, which attempts to find the a `Course` in the `CourseDatabase` object, and return it.
8+
You'll also explore the monadic operations that come with the `std::optional` class. Take a look at the code and review the `CourseDatabase` class to understand the interface.
9+
10+
## Running your code
11+
12+
To run your code, first you'll need to compile it. Open up a terminal (if you are using VSCode, hit <kbd>Ctrl+\`</kbd> or go to **Terminal > New Terminal** at the top). Then make sure that you are in the `assignment6/` directory and run:
13+
14+
```sh
15+
g++ -std=c++23 main.cpp -o main
16+
```
17+
18+
Assuming that your code compiles without any compiler errors, you can now do:
19+
20+
```sh
21+
./main
22+
```
23+
24+
which will actually run the `main` function in `main.cpp`.
25+
26+
As you are following the instructions below, we recommend intermittently compiling/testing with the autograder as a way to make sure you're on the right track!
27+
28+
> [!NOTE]
29+
>
30+
> ### Note for Windows
31+
>
32+
> On Windows, you may need to compile your code using
33+
>
34+
> ```sh
35+
> g++ -static-libstdc++ -std=c++23 main.cpp -o main
36+
> ```
37+
>
38+
> in order to see output. Also, the output executable may be called `main.exe`, in which case you'll run your code with:
39+
>
40+
> ```sh
41+
> ./main.exe
42+
> ```
43+
44+
## Part 0: Include `<optional>`
45+
46+
At the top of the `main.cpp` include `<optional>`, we're going to make use of `std::optional` in this assignment!
47+
48+
## Part 1: Write the `find_course` function
49+
50+
This function takes in a string `course_title`, and the function should try to find the `course` inside of the private `courses` member of the `CourseDatabase` object. What should the return type be? (hint: there may or may not be a `Course` for the `course_title` passed in)
51+
52+
> [!NOTE]
53+
> You need to change the type returned by `find_course` which is currenty `FillMeIn`.
54+
55+
## Part 2: Modifying the `main` function
56+
57+
Notice that we call the `find_course` here in the `main` function:
58+
59+
```cpp
60+
auto course = db.find_course(argv[1]);
61+
```
62+
63+
Now, you need to make use of the [monadic operations](https://en.cppreference.com/w/cpp/utility/optional) to populate the `output` string properly. Let's walk through how to do this.
64+
65+
Here's the behavior that you want to recreate, **without using any conditionals** like `if` statements:
66+
```cpp
67+
if (course.has_value()) {
68+
std::cout << "Found course: " << course->title << ","
69+
<< course->number_of_units << "," << course->quarter << "\n";
70+
} else {
71+
std::cout << "Course not found.\n";
72+
}
73+
```
74+
75+
Very simply, if there is a course then the line at the bottom of `main`
76+
77+
```cpp
78+
std::cout << output << std::end;
79+
```
80+
81+
Should produce:
82+
```bash
83+
Found course: <title>,<number_of_units>,<quarter>
84+
```
85+
86+
if there is no course then
87+
88+
```cpp
89+
std::cout << output << std::end;
90+
```
91+
92+
Should produce:
93+
```bash
94+
Course not found.
95+
```
96+
97+
### Monadic Operations
98+
99+
There are three monadic operations: [`and_then`](https://en.cppreference.com/w/cpp/utility/optional/and_then), [`transform`](https://en.cppreference.com/w/cpp/utility/optional/transform), and [`or_else`](https://en.cppreference.com/w/cpp/utility/optional/or_else). Read the description of each of them in the lecture slides, and take a look at [the standard library documentation](https://en.cppreference.com/w/cpp/utility/optional). You will only need to use 2 of the mondadic operations.
100+
101+
Your code should end up looking something like this:
102+
103+
```cpp
104+
std::string output = course
105+
./* monadic function one */ (/* ... */)
106+
./* monadic function two */ (/* ... */)
107+
.value(); // OR `.value_or(...)`, see below
108+
```
109+
110+
It can help to **think about what the type of `output` is and work backwards from there**. Pay attention to what each of the monadic functions does, as described in the hint below.
111+
112+
> [!NOTE]
113+
> Recall what the role is of each of the monadic functions. The official C++ library doesn't do a good job explaining this, so we have included a short reference here. Suppose `T` and `U` are arbitrary types.
114+
>
115+
> ```cpp
116+
> /**
117+
> * tl;dr;
118+
> * Calls a function to produce a new optional if there is a value; otherwise, returns nothing.
119+
> *
120+
> * The function passed to `and_then` takes a non-optional instance of type `T` and returns a `std::optional<U>`.
121+
> * If the optional has a value, `and_then` applies the function to its value and returns the result.
122+
> * If the optional doesn't have a value (i.e. it is `std::nullopt`), it returns `std::nullopt`.
123+
> */
124+
> template <typename U>
125+
> std::optional<U> std::optional<T>::and_then(std::function<std::optional<U>(T)> func);
126+
>
127+
> /**
128+
> * tl;dr;
129+
> * Applies a function to the stored value if present, wrapping the result in an optional, or returns nothing otherwise.
130+
> *
131+
> * The function passed to `transform` takes a non-optional instance of type `T` and returns a non-optional instance of type `U`.
132+
> * If the optional has a value, `transform` applies the function to its value and returns the result wrapped in an `std::optional<U>`.
133+
> * If the optional doesn't have a value (i.e. it is `std::nullopt`), it returns `std::nullopt`.
134+
> */
135+
> template <typename U>
136+
> std::optional<U> std::optional<T>::transform(std::function<U(T)> func);
137+
>
138+
> /**
139+
> * tl;dr;
140+
> * Returns the optional itself if it has a value; otherwise, it calls a function to produce a new optional.
141+
> *
142+
> * The opposite of `and_then`.
143+
> * The function passed to `or_else` takes in no arguments and returns a `std::optional<U>`.
144+
> * If the optional has a value, `or_else` returns it.
145+
> * If the optional doesn't have a value (i.e. it is `std::nullopt`), `or_else invokes the function and returns the result.
146+
> */
147+
> template <typename U>
148+
> std::optional<U> std::optional<T>::or_else(std::function<std::optional<U>(T)> func);
149+
> ```
150+
>
151+
> For example, given a `std::optional<T> opt` object, the monadic operations could be invoked as follows:
152+
>
153+
> ```cpp
154+
> opt
155+
> .and_then([](T value) -> std::optional<U> { return /* ... */; })
156+
> .transform([](T value) -> U { return /* ... */; });
157+
> .or_else([]() -> std::optional<U> { return /* ... */; })
158+
> ```
159+
>
160+
> <sup>Note that the `->` notation in the lambda function is a way of explicitly writing out the return type of the function!</sup>
161+
>
162+
> Notice that since each method returns an `std::optional`, you can chain them together. If you are certain that the optional will have a value at the end of the chain, you could call [`.value()`](https://en.cppreference.com/w/cpp/utility/optional/value) to get the value. Otherwise, you could call [`.value_or(fallback)`](https://en.cppreference.com/w/cpp/utility/optional/value_or) to get the result or some other `fallback` value if the optional doesn't have a value.
163+
164+
165+
166+
## 🚀 Submission Instructions
167+
168+
If you pass all tests, you are ready to submit! To submit the assignment:
169+
1. Please complete the feedback form [at this link](https://forms.gle/aGuFqLyhB18mNoPKA).
170+
2. Submit your assignment on [Paperless](https://paperless.stanford.edu)!
171+
172+
Your deliverable should be:
173+
174+
- `main.cpp`
175+
176+
You may resubmit as many times as you'd like before the deadline.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
from utils import Autograder, ASSIGNMENT_DIR
2+
from typing import List
3+
4+
import os
5+
import subprocess
6+
7+
8+
def get_main_exe_path() -> os.PathLike:
9+
main_path = os.path.join(ASSIGNMENT_DIR, "main")
10+
if not os.path.isfile(main_path):
11+
main_path = os.path.join(ASSIGNMENT_DIR, "main.exe")
12+
if not os.path.isfile(main_path):
13+
raise RuntimeError(
14+
"Could not find a main executable. Did you compile your code with the command in the README?"
15+
)
16+
return main_path
17+
18+
19+
def verify_output(courses: List[str], found: bool):
20+
main_path = get_main_exe_path()
21+
22+
course_names = [course.split(",")[0] for course in courses]
23+
for course_name, course in zip(course_names, courses):
24+
result = subprocess.run(
25+
[main_path, course_name],
26+
stdout=subprocess.PIPE,
27+
stderr=subprocess.PIPE,
28+
text=True,
29+
)
30+
31+
if result.returncode != 0:
32+
raise RuntimeError(result.stderr)
33+
34+
actual = result.stdout.strip()
35+
36+
expected = f"Found course: {course}" if found else "Course not found."
37+
38+
if actual != expected:
39+
raise RuntimeError(
40+
f"For course {course_name}, expected output:\n\t{expected}\nbut got:\n\t{actual}"
41+
)
42+
43+
44+
if __name__ == "__main__":
45+
grader = Autograder()
46+
grader.add_part(
47+
"Present Courses",
48+
lambda: verify_output(
49+
[
50+
"Introduction to Mobile Augmented Reality Design and Development,1,2023-2024 Spring",
51+
"Design for Play (SYMSYS 195G),4,2023-2024 Spring",
52+
"Practical Machine Learning,4,null",
53+
"Human-Centered AI,3,null",
54+
"Seminar in Artificial Intelligence in Healthcare,1,2023-2024 Autumn",
55+
"Introduction to Python Programming,1,2023-2024 Autumn",
56+
"Machine Learning for Discrete Optimization (MS&E 236),3,2023-2024 Spring",
57+
"AI for Social Good,2,2023-2024 Spring",
58+
"Software Project Experience with Corporate Partners,4,2023-2024 Winter",
59+
"The Future of Mechanical Engineering (ME 228),1,null",
60+
],
61+
True,
62+
),
63+
)
64+
65+
grader.add_part(
66+
"Missing Courses",
67+
lambda: verify_output(
68+
[
69+
"Introduction to Quantum Mechanics for Engineers",
70+
"Fundamentals of Blockchain and Cryptography",
71+
"Applied Data Science for Social Impact",
72+
"Advanced Robotics and Autonomous Systems",
73+
"Neural Networks and Deep Learning Fundamentals",
74+
"Exploring the Future of Artificial General Intelligence",
75+
"Data Ethics and Privacy in the Digital Age",
76+
"Introduction to Cloud Computing with AWS",
77+
"Creative Coding for Interactive Media",
78+
"Virtual Reality and Augmented Reality for Healthcare",
79+
],
80+
False,
81+
),
82+
)
83+
84+
grader.run(),

0 commit comments

Comments
 (0)