summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDave Gauer <dave@ratfactor.com>2021-04-30 21:35:56 -0400
committerDave Gauer <dave@ratfactor.com>2021-04-30 21:35:56 -0400
commit4760c62d628aac89a5568066bd9fbf10a004550f (patch)
treeb729e7741c8b67b4deebd10c2ba3603345e49eda
parent060e2b9789fe1dab38aacdd47e9423d0d1a3bb2c (diff)
Added ex075 Quiz 8
-rw-r--r--README.md22
-rw-r--r--build.zig9
-rw-r--r--exercises/075_quiz8.zig208
-rw-r--r--patches/patches/075_quiz8.patch8
4 files changed, 237 insertions, 10 deletions
diff --git a/README.md b/README.md
index 3a874d2..a6792fd 100644
--- a/README.md
+++ b/README.md
@@ -117,6 +117,8 @@ the learning resource I wished for. There will be tons of room for improvement:
Planned exercises:
+Core Language
+
* [x] Hello world (main needs to be public)
* [x] Importing standard library
* [x] Assignment
@@ -142,18 +144,24 @@ Planned exercises:
* [x] Labelled blocks and loops
* [x] Loops as expressions
* [x] Builtins
-* [ ] Comptime (!)
-* [ ] Inline loops
+* [x] Inline loops
+* [x] Comptime
* [ ] Anonymous structs
* [ ] Sentinel termination
-* [ ] Vectors
+* [ ] Suspend / Resume
+* [ ] Async / Await
+* [ ] Nosuspend
+* [ ] Async Frames, Suspend Blocks
+* [ ] Working with C?
+
+Modules and the Zig Standard Library
+
* [ ] Imports
* [ ] Allocators
* [ ] Arraylist
* [ ] Filesystem
* [ ] Readers and Writers
* [ ] Formatting
-* [ ] JSON
* [ ] Random Numbers
* [ ] Crypto
* [ ] Threads
@@ -161,12 +169,6 @@ Planned exercises:
* [ ] Stacks
* [ ] Sorting
* [ ] Iterators
-* [ ] Formatting specifiers
-* [ ] Advanced Formatting
-* [ ] Suspend / Resume
-* [ ] Async / Await
-* [ ] Nosuspend
-* [ ] Async Frames, Suspend Blocks
The initial topics for these exercises were unabashedly cribbed from
[ziglearn.org](https://ziglearn.org/). I've since moved things around
diff --git a/build.zig b/build.zig
index 9581e17..f427b98 100644
--- a/build.zig
+++ b/build.zig
@@ -370,6 +370,15 @@ const exercises = [_]Exercise{
.main_file = "073_comptime8.zig",
.output = "My llama value is 25.",
},
+ .{
+ .main_file = "074_comptime9.zig",
+ .output = "My llama value is 2.",
+ },
+ .{
+ .main_file = "075_quiz8.zig",
+ .output = "Archer's Point--2->Bridge--1->Dogwood Grove--3->Cottage--2->East Pond--1->Fox Pond",
+ .hint = "Roll up those sleeves. You get to WRITE some code for this one.",
+ },
};
/// Check the zig version to make sure it can compile the examples properly.
diff --git a/exercises/075_quiz8.zig b/exercises/075_quiz8.zig
new file mode 100644
index 0000000..14fab18
--- /dev/null
+++ b/exercises/075_quiz8.zig
@@ -0,0 +1,208 @@
+//
+// Quiz Time!
+//
+// Let's revisit the Hermit's Map from Quiz 7.
+//
+// Oh, don't worry, it's not nearly as big without all the
+// explanatory comments. And we're only going to change one part
+// of it.
+//
+const print = @import("std").debug.print;
+
+const TripError = error{ Unreachable, EatenByAGrue };
+
+const Place = struct {
+ name: []const u8,
+ paths: []const Path = undefined,
+};
+
+var a = Place{ .name = "Archer's Point" };
+var b = Place{ .name = "Bridge" };
+var c = Place{ .name = "Cottage" };
+var d = Place{ .name = "Dogwood Grove" };
+var e = Place{ .name = "East Pond" };
+var f = Place{ .name = "Fox Pond" };
+
+// Remember how we didn't have to declare the numeric type of the
+// place_count because it is only used at compile time? That
+// probably makes a lot more sense now. :-)
+const place_count = 6;
+
+const Path = struct {
+ from: *const Place,
+ to: *const Place,
+ dist: u8,
+};
+
+// Okay, so as you may recall, we had to create each Path struct
+// by hand and each one took 5 lines of code to define:
+//
+// Path{
+// .from = &a, // from: Archer's Point
+// .to = &b, // to: Bridge
+// .dist = 2,
+// },
+//
+// Well, armed with the knowledge that we can run code at compile
+// time, we can perhaps shorten this a bit with a simple function
+// instead.
+//
+// Please fill in the body of this function!
+fn makePath(from: *Place, to: *Place, dist: u8) Path {
+
+}
+
+// Using our new function, these path definitions take up considerably less
+// space in our program now!
+const a_paths = [_]Path{ makePath(&a, &b, 2) };
+const b_paths = [_]Path{ makePath(&b, &a, 2), makePath(&b, &d, 1) };
+const c_paths = [_]Path{ makePath(&c, &d, 3), makePath(&c, &e, 2) };
+const d_paths = [_]Path{ makePath(&d, &b, 1), makePath(&d, &c, 3), makePath(&d, &f, 7) };
+const e_paths = [_]Path{ makePath(&e, &c, 2), makePath(&e, &f, 1) };
+const f_paths = [_]Path{ makePath(&f, &d, 7) };
+//
+// But is it more readable? That could be argued either way.
+//
+// We've seen that it is possible to parse strings at compile
+// time, so the sky's really the limit on how fancy we could get
+// with this.
+//
+// For example, we could create our own "path language" and
+// create Paths from that. Something like this, perhaps:
+//
+// a -> (b[2])
+// b -> (a[2] d[1])
+// c -> (d[3] e[2])
+// ...
+//
+// Feel free to implement something like that as a SUPER BONUS EXERCISE!
+
+const TripItem = union(enum) {
+ place: *const Place,
+ path: *const Path,
+
+ fn print(self: TripItem) void {
+ switch (self) {
+ .place => |p| print("{s}", .{p.name}),
+ .path => |p| print("--{}->", .{p.dist}),
+ }
+ }
+};
+
+const NotebookEntry = struct {
+ place: *const Place,
+ coming_from: ?*const Place,
+ via_path: ?*const Path,
+ dist_to_reach: u16,
+};
+
+const HermitsNotebook = struct {
+ entries: [place_count]?NotebookEntry = .{null} ** place_count,
+ next_entry: u8 = 0,
+ end_of_entries: u8 = 0,
+
+ fn getEntry(self: *HermitsNotebook, place: *const Place) ?*NotebookEntry {
+ for (self.entries) |*entry, i| {
+ if (i >= self.end_of_entries) break;
+ if (place == entry.*.?.place) return &entry.*.?;
+ }
+ return null;
+ }
+
+ fn checkNote(self: *HermitsNotebook, note: NotebookEntry) void {
+ var existing_entry = self.getEntry(note.place);
+
+ if (existing_entry == null) {
+ self.entries[self.end_of_entries] = note;
+ self.end_of_entries += 1;
+ } else if (note.dist_to_reach < existing_entry.?.dist_to_reach) {
+ existing_entry.?.* = note;
+ }
+ }
+
+ fn hasNextEntry(self: *HermitsNotebook) bool {
+ return self.next_entry < self.end_of_entries;
+ }
+
+ fn getNextEntry(self: *HermitsNotebook) *const NotebookEntry {
+ defer self.next_entry += 1;
+ return &self.entries[self.next_entry].?;
+ }
+
+ fn getTripTo(self: *HermitsNotebook, trip: []?TripItem, dest: *Place) TripError!void {
+ const destination_entry = self.getEntry(dest);
+
+ if (destination_entry == null) {
+ return TripError.Unreachable;
+ }
+
+ var current_entry = destination_entry.?;
+ var i: u8 = 0;
+
+ while (true) : (i += 2) {
+ trip[i] = TripItem{ .place = current_entry.place };
+ if (current_entry.coming_from == null) break;
+ trip[i + 1] = TripItem{ .path = current_entry.via_path.? };
+ const previous_entry = self.getEntry(current_entry.coming_from.?);
+ if (previous_entry == null) return TripError.EatenByAGrue;
+ current_entry = previous_entry.?;
+ }
+ }
+};
+
+pub fn main() void {
+ const start = &a; // Archer's Point
+ const destination = &f; // Fox Pond
+
+ // TODO: can we neaten this up????
+ a.paths = a_paths[0..];
+ b.paths = b_paths[0..];
+ c.paths = c_paths[0..];
+ d.paths = d_paths[0..];
+ e.paths = e_paths[0..];
+ f.paths = f_paths[0..];
+
+ var notebook = HermitsNotebook{};
+ var working_note = NotebookEntry{
+ .place = start,
+ .coming_from = null,
+ .via_path = null,
+ .dist_to_reach = 0,
+ };
+ notebook.checkNote(working_note);
+
+ while (notebook.hasNextEntry()) {
+ var place_entry = notebook.getNextEntry();
+
+ for (place_entry.place.paths) |*path| {
+ working_note = NotebookEntry{
+ .place = path.to,
+ .coming_from = place_entry.place,
+ .via_path = path,
+ .dist_to_reach = place_entry.dist_to_reach + path.dist,
+ };
+ notebook.checkNote(working_note);
+ }
+ }
+
+ var trip = [_]?TripItem{null} ** (place_count * 2);
+
+ notebook.getTripTo(trip[0..], destination) catch |err| {
+ print("Oh no! {}\n", .{err});
+ return;
+ };
+
+ printTrip(trip[0..]);
+}
+
+fn printTrip(trip: []?TripItem) void {
+ var i: u8 = @intCast(u8, trip.len);
+
+ while (i > 0) {
+ i -= 1;
+ if (trip[i] == null) continue;
+ trip[i].?.print();
+ }
+
+ print("\n", .{});
+}
diff --git a/patches/patches/075_quiz8.patch b/patches/patches/075_quiz8.patch
new file mode 100644
index 0000000..ce6a2d8
--- /dev/null
+++ b/patches/patches/075_quiz8.patch
@@ -0,0 +1,8 @@
+52c52,56
+<
+---
+> return Path{
+> .from = from,
+> .to = to,
+> .dist = dist,
+> };