Compare commits
117 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
e8270de928 | ||
![]() |
776316e60b | ||
![]() |
efe2d19c69 | ||
![]() |
49c54fb075 | ||
![]() |
67f87a76c2 | ||
![]() |
dfdaf03d99 | ||
![]() |
5da194ba9c | ||
![]() |
8345e839b0 | ||
![]() |
6c23f2682e | ||
![]() |
19bd8745e4 | ||
![]() |
1ac46d7a42 | ||
![]() |
165cc199ca | ||
![]() |
e182d1f19d | ||
![]() |
09e2f37a50 | ||
![]() |
27db3112f9 | ||
![]() |
8cb2a5aa3c | ||
![]() |
c936c5e123 | ||
![]() |
5c2354a1bf | ||
![]() |
4dbd056100 | ||
![]() |
9ce4a7d6f0 | ||
![]() |
b484be9ac1 | ||
![]() |
a2a0a6e891 | ||
![]() |
e7eaa080b6 | ||
![]() |
ce0a6cc91c | ||
![]() |
c94eb33e44 | ||
![]() |
8f36619bd7 | ||
![]() |
aa74dde367 | ||
![]() |
9432c2b0fd | ||
![]() |
f4f8eb7ff1 | ||
![]() |
72e3d6ebdc | ||
![]() |
3c9c55df8e | ||
![]() |
376a839672 | ||
![]() |
ba2a9622c4 | ||
![]() |
2122c477a0 | ||
![]() |
7732cd7716 | ||
![]() |
564916db81 | ||
![]() |
84864d808f | ||
![]() |
7875a0f9aa | ||
![]() |
c0ff1b70c1 | ||
![]() |
f06c1f27d1 | ||
![]() |
ba4709b20f | ||
![]() |
e06cdc0b70 | ||
![]() |
86ac326885 | ||
![]() |
20919722ff | ||
![]() |
db21ab9855 | ||
![]() |
05589f8ba1 | ||
![]() |
223fc79e44 | ||
![]() |
69bc9a0723 | ||
![]() |
5f74c7f911 | ||
![]() |
2c44f3e4ff | ||
![]() |
92ea6718b2 | ||
![]() |
9bf7a84e56 | ||
![]() |
9ce889b438 | ||
![]() |
74a6e60e17 | ||
![]() |
23b11a7509 | ||
![]() |
66d08f1e1f | ||
![]() |
ec6f6c5870 | ||
![]() |
a3de4e3d0f | ||
![]() |
0d1c76a410 | ||
![]() |
8e6612a59d | ||
![]() |
95cfeaa606 | ||
![]() |
dabd9a5a0a | ||
![]() |
d65e3f3f9a | ||
![]() |
cdaa246131 | ||
![]() |
2b9e3da5c8 | ||
![]() |
2092f35127 | ||
![]() |
abed92c05e | ||
![]() |
5728ccc8eb | ||
![]() |
a87e7c895e | ||
![]() |
9844123dd1 | ||
![]() |
c8f081f3e8 | ||
![]() |
e3877321b6 | ||
![]() |
08cc60ba59 | ||
![]() |
6b46b26c22 | ||
![]() |
d0519d18fa | ||
![]() |
9e9cf40453 | ||
![]() |
6984345d0a | ||
![]() |
277304454a | ||
![]() |
9e48c9a339 | ||
![]() |
48b2032024 | ||
![]() |
55b2ac4c5f | ||
![]() |
099d0bba93 | ||
![]() |
8257ccb5c8 | ||
![]() |
4b1ae6117c | ||
![]() |
755911747f | ||
![]() |
fa22e861d5 | ||
![]() |
7bfd7adce8 | ||
![]() |
58dff3f504 | ||
![]() |
0d46acfa02 | ||
![]() |
15de3785a3 | ||
![]() |
7d23ddc1f6 | ||
![]() |
ba9447d2c6 | ||
![]() |
7a0cbb131f | ||
![]() |
528a8645f8 | ||
![]() |
b7dfa4cd1d | ||
![]() |
1ed03cf0a1 | ||
![]() |
1a001b9eb7 | ||
![]() |
e7c106ba3a | ||
![]() |
2fb7da53e7 | ||
![]() |
72e15c9ef3 | ||
![]() |
492e5f5c40 | ||
![]() |
5eafe16e97 | ||
![]() |
46e3a38dbc | ||
![]() |
f987a06ccc | ||
![]() |
b0511bb3c7 | ||
![]() |
7679f93f68 | ||
![]() |
b7015c2d9d | ||
![]() |
063a74c59a | ||
![]() |
f29c0692d5 | ||
![]() |
afe5511455 | ||
![]() |
cab5ee87bf | ||
![]() |
5a259a943f | ||
![]() |
55b58fea56 | ||
![]() |
08d294f2b8 | ||
![]() |
6446542867 | ||
![]() |
8a1fbea5c9 | ||
![]() |
633af411e6 |
88 changed files with 785 additions and 260 deletions
31
.devcontainer/devcontainer.json
Normal file
31
.devcontainer/devcontainer.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||
// README at: https://github.com/devcontainers/templates/tree/main/src/debian
|
||||
{
|
||||
"name": "Ziglings",
|
||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||
"image": "mcr.microsoft.com/devcontainers/base:bullseye",
|
||||
"features": {
|
||||
"ghcr.io/devcontainers-contrib/features/zig:1": {
|
||||
"version": "master"
|
||||
}
|
||||
},
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"ziglang.vscode-zig"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||
// "features": {},
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// "forwardPorts": [],
|
||||
|
||||
// Configure tool-specific properties.
|
||||
// "customizations": {},
|
||||
|
||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||
// "remoteUser": "root"
|
||||
}
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
|||
/zig-out/
|
||||
/answers/
|
||||
/patches/healed/
|
||||
/output/
|
||||
|
|
9
.woodpecker/eowyn.yaml
Normal file
9
.woodpecker/eowyn.yaml
Normal file
|
@ -0,0 +1,9 @@
|
|||
steps:
|
||||
- name: eowyn
|
||||
image: ziglings/ziglang:latest
|
||||
pull: true
|
||||
commands:
|
||||
- sh ./patches/eowyn.sh
|
||||
when:
|
||||
event: [push, cron]
|
||||
cron: daily*
|
|
@ -1,11 +0,0 @@
|
|||
steps:
|
||||
eowyn:
|
||||
image: ziglings/ziglang
|
||||
commands:
|
||||
- sh ./patches/eowyn.sh
|
||||
when:
|
||||
events:
|
||||
- push
|
||||
- pull-requests
|
||||
- cron
|
||||
cron: "Daily"
|
|
@ -54,13 +54,12 @@ Ziglings. Please file an issue...or make a pull request!
|
|||
|
||||
## Formatting
|
||||
|
||||
All exercises should conform to `zig fmt`. I often forget to do
|
||||
this.
|
||||
All exercises should conform to `zig fmt`.
|
||||
|
||||
|
||||
## Pull Request Workflow
|
||||
|
||||
Ziglings uses the "standard" Github workflow as guided by the Web
|
||||
Ziglings uses the "standard" Codeberg workflow as guided by the Web
|
||||
interface. Specifically:
|
||||
|
||||
* Fork this repository
|
||||
|
@ -71,7 +70,7 @@ interface. Specifically:
|
|||
`git push origin my-branch`
|
||||
* Create a pull request from your branch to `ziglings/main`
|
||||
* Your faithful Ziglings maintainers will take a look at your
|
||||
request ASAP (we don't talk about May-July 2022, LOL)
|
||||
request ASAP (we don't talk about May-July, LOL)
|
||||
* Once the changes are reviewed, your request will be merged and
|
||||
eternal Ziglings contributor glory is yours!
|
||||
|
||||
|
|
29
README.md
29
README.md
|
@ -1,12 +1,4 @@
|
|||
# Ziglings
|
||||
# ⚠️ Ziglings has moved from GitHub to Codeberg!
|
||||
|
||||
You are looking at the current Ziglings repo if you are viewing
|
||||
this at https://codeberg.org/ziglings/exercises/
|
||||
|
||||
You can also use the handy URL https://ziglings.org to get here!
|
||||
|
||||
***
|
||||
|
||||
Welcome to Ziglings! This project contains a series of tiny
|
||||
broken programs (and one nasty surprise). By fixing them, you'll
|
||||
|
@ -39,6 +31,7 @@ for more detail:
|
|||
* https://ziglang.org/learn/
|
||||
* https://ziglearn.org/
|
||||
* https://ziglang.org/documentation/master/
|
||||
* [Zig in Depth! (video series)](https://www.youtube.com/watch?v=MMtvGA1YhW4&list=PLtB7CL7EG7pCw7Xy1SQC53Gl8pI7aDg9t&pp=iAQB)
|
||||
|
||||
Also, the [Zig community](https://github.com/ziglang/zig/wiki/Community)
|
||||
is incredibly friendly and helpful!
|
||||
|
@ -53,7 +46,7 @@ Verify the installation and build number of `zig` like so:
|
|||
|
||||
```
|
||||
$ zig version
|
||||
0.12.0-dev.xxxx+xxxxxxxxx
|
||||
0.13.0-dev.xxxx+xxxxxxxxx
|
||||
```
|
||||
|
||||
Clone this repository with Git:
|
||||
|
@ -75,11 +68,14 @@ reading these.
|
|||
|
||||
## A Note About Versions
|
||||
|
||||
**Hint:** To check out Ziglings for a stable release of Zig, you can use
|
||||
the appropriate tag.
|
||||
|
||||
The Zig language is under very active development. In order to be
|
||||
current, Ziglings tracks **development** builds of the Zig
|
||||
compiler rather than versioned **release** builds. The last
|
||||
stable release was `0.11.0`, but Ziglings needs a dev build with
|
||||
pre-release version "0.12.0" and a build number at least as high
|
||||
stable release was `0.12.0`, but Ziglings needs a dev build with
|
||||
pre-release version "0.13.0" and a build number at least as high
|
||||
as that shown in the example version check above.
|
||||
|
||||
It is likely that you'll download a build which is _greater_ than
|
||||
|
@ -92,7 +88,13 @@ that if you update one, you may need to also update the other.
|
|||
|
||||
### Version Changes
|
||||
|
||||
Version-0.11.0-dev.4246+71dfce31b
|
||||
Version-0.12.0-dev.3518
|
||||
* *2024-03-21* zig 0.12.0-dev.3518 - change to @fieldParentPtr - see [#19470](https://github.com/ziglang/zig/pull/19470)
|
||||
* *2024-03-21* zig 0.12.0-dev.3397 - rename std.os to std.posix - see [#5019](https://github.com/ziglang/zig/issues/5019)
|
||||
* *2024-03-14* zig 0.12.0-dev.3302 - changes in `std.fmt` - floating-point formatting implementation - see [#19229](https://github.com/ziglang/zig/pull/19229)
|
||||
* *2024-02-05* zig 0.12.0-dev.2618 - changes in `build system` - from `Step.zig_exe` to `Step.graph.zig_exe` - see [#18778](https://github.com/ziglang/zig/issues/18778)
|
||||
* *2024-01-05* zig 0.12.0-dev.2043 - rename of `std.Build.FileSource` to `std.Build.LazyPath` - see [#16353](https://github.com/ziglang/zig/issues/16353)
|
||||
* *2023-10-24* zig 0.12.0-dev.1243 - changes in `std.ChildProcess`: renamed exec to run - see [#5853](https://github.com/ziglang/zig/issues/5853)
|
||||
* *2023-06-26* zig 0.11.0-dev.4246 - changes in compile step (now it can be null)
|
||||
* *2023-06-26* zig 0.11.0-dev.3853 - removal of destination type from all cast builtins
|
||||
* *2023-06-20* zig 0.11.0-dev.3747 - `@enumToInt` is now `@intFromEnum` and `@intToFloat` is now `@floatFromInt`
|
||||
|
@ -209,13 +211,14 @@ Zig Core Language
|
|||
* [X] Interfaces
|
||||
* [X] Bit manipulation
|
||||
* [X] Working with C
|
||||
* [ ] Interfaces part 2
|
||||
* [X] Threading
|
||||
|
||||
Zig Standard Library
|
||||
|
||||
* [X] String formatting
|
||||
* [X] Testing
|
||||
* [X] Tokenization
|
||||
* [X] File handling
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
60
build.zig
60
build.zig
|
@ -15,7 +15,7 @@ const print = std.debug.print;
|
|||
// 1) Getting Started
|
||||
// 2) Version Changes
|
||||
comptime {
|
||||
const required_zig = "0.11.0-dev.4246";
|
||||
const required_zig = "0.12.0-dev.3518";
|
||||
const current_zig = builtin.zig_version;
|
||||
const min_zig = std.SemanticVersion.parse(required_zig) catch unreachable;
|
||||
if (current_zig.order(min_zig) == .lt) {
|
||||
|
@ -119,7 +119,7 @@ pub const logo =
|
|||
;
|
||||
|
||||
pub fn build(b: *Build) !void {
|
||||
if (!validate_exercises()) std.os.exit(2);
|
||||
if (!validate_exercises()) std.process.exit(2);
|
||||
|
||||
use_color_escapes = false;
|
||||
if (std.io.getStdErr().supportsAnsiEscapeCodes()) {
|
||||
|
@ -172,7 +172,7 @@ pub fn build(b: *Build) !void {
|
|||
// Named build mode: verifies a single exercise.
|
||||
if (n == 0 or n > exercises.len - 1) {
|
||||
print("unknown exercise number: {}\n", .{n});
|
||||
std.os.exit(2);
|
||||
std.process.exit(2);
|
||||
}
|
||||
const ex = exercises[n - 1];
|
||||
|
||||
|
@ -247,7 +247,7 @@ const ZiglingStep = struct {
|
|||
fn make(step: *Step, prog_node: *std.Progress.Node) !void {
|
||||
// NOTE: Using exit code 2 will prevent the Zig compiler to print the message:
|
||||
// "error: the following build command failed with exit code 1:..."
|
||||
const self = @fieldParentPtr(ZiglingStep, "step", step);
|
||||
const self: *ZiglingStep = @alignCast(@fieldParentPtr("step", step));
|
||||
|
||||
if (self.exercise.skip) {
|
||||
print("Skipping {s}\n\n", .{self.exercise.main_file});
|
||||
|
@ -262,7 +262,7 @@ const ZiglingStep = struct {
|
|||
print("\n{s}Ziglings hint: {s}{s}", .{ bold_text, hint, reset_text });
|
||||
|
||||
self.help();
|
||||
std.os.exit(2);
|
||||
std.process.exit(2);
|
||||
};
|
||||
|
||||
self.run(exe_path.?, prog_node) catch {
|
||||
|
@ -272,7 +272,7 @@ const ZiglingStep = struct {
|
|||
print("\n{s}Ziglings hint: {s}{s}", .{ bold_text, hint, reset_text });
|
||||
|
||||
self.help();
|
||||
std.os.exit(2);
|
||||
std.process.exit(2);
|
||||
};
|
||||
|
||||
// Print possible warning/debug messages.
|
||||
|
@ -281,14 +281,14 @@ const ZiglingStep = struct {
|
|||
|
||||
fn run(self: *ZiglingStep, exe_path: []const u8, _: *std.Progress.Node) !void {
|
||||
resetLine();
|
||||
print("Checking {s}...\n", .{self.exercise.main_file});
|
||||
print("Checking: {s}\n", .{self.exercise.main_file});
|
||||
|
||||
const b = self.step.owner;
|
||||
|
||||
// Allow up to 1 MB of stdout capture.
|
||||
const max_output_bytes = 1 * 1024 * 1024;
|
||||
|
||||
var result = Child.exec(.{
|
||||
const result = Child.run(.{
|
||||
.allocator = b.allocator,
|
||||
.argv = &.{exe_path},
|
||||
.cwd = b.build_root.path.?,
|
||||
|
@ -306,7 +306,7 @@ const ZiglingStep = struct {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_output(self: *ZiglingStep, result: Child.ExecResult) !void {
|
||||
fn check_output(self: *ZiglingStep, result: Child.RunResult) !void {
|
||||
const b = self.step.owner;
|
||||
|
||||
// Make sure it exited cleanly.
|
||||
|
@ -355,7 +355,7 @@ const ZiglingStep = struct {
|
|||
print("{s}PASSED:\n{s}{s}\n\n", .{ green_text, output, reset_text });
|
||||
}
|
||||
|
||||
fn check_test(self: *ZiglingStep, result: Child.ExecResult) !void {
|
||||
fn check_test(self: *ZiglingStep, result: Child.RunResult) !void {
|
||||
switch (result.term) {
|
||||
.Exited => |code| {
|
||||
if (code != 0) {
|
||||
|
@ -376,7 +376,7 @@ const ZiglingStep = struct {
|
|||
}
|
||||
|
||||
fn compile(self: *ZiglingStep, prog_node: *std.Progress.Node) !?[]const u8 {
|
||||
print("Compiling {s}...\n", .{self.exercise.main_file});
|
||||
print("Compiling: {s}\n", .{self.exercise.main_file});
|
||||
|
||||
const b = self.step.owner;
|
||||
const exercise_path = self.exercise.main_file;
|
||||
|
@ -386,7 +386,7 @@ const ZiglingStep = struct {
|
|||
var zig_args = std.ArrayList([]const u8).init(b.allocator);
|
||||
defer zig_args.deinit();
|
||||
|
||||
zig_args.append(b.zig_exe) catch @panic("OOM");
|
||||
zig_args.append(b.graph.zig_exe) catch @panic("OOM");
|
||||
|
||||
const cmd = switch (self.exercise.kind) {
|
||||
.exe => "build-exe",
|
||||
|
@ -495,8 +495,7 @@ const PrintStep = struct {
|
|||
}
|
||||
|
||||
fn make(step: *Step, _: *std.Progress.Node) !void {
|
||||
const self = @fieldParentPtr(PrintStep, "step", step);
|
||||
|
||||
const self: *PrintStep = @alignCast(@fieldParentPtr("step", step));
|
||||
print("{s}", .{self.message});
|
||||
}
|
||||
};
|
||||
|
@ -839,7 +838,7 @@ const exercises = [_]Exercise{
|
|||
},
|
||||
.{
|
||||
.main_file = "060_floats.zig",
|
||||
.output = "Shuttle liftoff weight: 1995796kg",
|
||||
.output = "Shuttle liftoff weight: 2032092kg",
|
||||
},
|
||||
.{
|
||||
.main_file = "061_coercions.zig",
|
||||
|
@ -939,7 +938,7 @@ const exercises = [_]Exercise{
|
|||
.{
|
||||
.main_file = "082_anonymous_structs3.zig",
|
||||
.output =
|
||||
\\"0"(bool):true "1"(bool):false "2"(i32):42 "3"(f32):3.14159202e+00
|
||||
\\"0"(bool):true "1"(bool):false "2"(i32):42 "3"(f32):3.141592e0
|
||||
,
|
||||
.hint = "This one is a challenge! But you have everything you need.",
|
||||
},
|
||||
|
@ -1103,6 +1102,35 @@ const exercises = [_]Exercise{
|
|||
\\This little poem has 15 words!
|
||||
,
|
||||
},
|
||||
.{
|
||||
.main_file = "104_threading.zig",
|
||||
.output =
|
||||
\\Starting work...
|
||||
\\thread 1: started.
|
||||
\\thread 2: started.
|
||||
\\thread 3: started.
|
||||
\\Some weird stuff, after starting the threads.
|
||||
\\thread 2: finished.
|
||||
\\thread 1: finished.
|
||||
\\thread 3: finished.
|
||||
\\Zig is cool!
|
||||
,
|
||||
},
|
||||
.{
|
||||
.main_file = "105_threading2.zig",
|
||||
.output = "PI ≈ 3.14159265",
|
||||
},
|
||||
.{
|
||||
.main_file = "106_files.zig",
|
||||
.output = "Successfully wrote 18 bytes.",
|
||||
},
|
||||
.{
|
||||
.main_file = "107_files2.zig",
|
||||
.output =
|
||||
\\AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
\\Successfully Read 18 bytes: It's zigling time!
|
||||
,
|
||||
},
|
||||
.{
|
||||
.main_file = "999_the_end.zig",
|
||||
.output =
|
||||
|
|
25
ci/compat.sh
25
ci/compat.sh
|
@ -1,25 +0,0 @@
|
|||
#!/bin/bash
|
||||
# This script checks that `zig build` will return an useful error message when
|
||||
# the Zig compiler is not compatible, instead of failing due to a syntax error.
|
||||
#
|
||||
# This script should be run on an UNIX system.
|
||||
|
||||
zig_version=$(zig version)
|
||||
|
||||
zig build -Dn=1 -Dhealed &> /dev/null 2>&1
|
||||
zig_ret=$?
|
||||
|
||||
if [ "$zig_ret" -eq 0 ]; then
|
||||
printf "zig %s unexpectedly succeeded\n" "$zig_version"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
zig_error=$(zig build -Dn=1 -Dhealed 2>&1)
|
||||
|
||||
echo "$zig_error" | grep -q "it looks like your version of zig is too old"
|
||||
zig_ret=$?
|
||||
|
||||
if [ "$zig_ret" -ne 0 ]; then
|
||||
printf "zig %s is not compatible\n" "$zig_version"
|
||||
exit 1
|
||||
fi
|
|
@ -16,6 +16,6 @@
|
|||
//
|
||||
const std = @import("std");
|
||||
|
||||
fn main() void {
|
||||
pub fn main() void {
|
||||
std.debug.print("Hello world!\n", .{});
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// Please complete the import below:
|
||||
//
|
||||
|
||||
??? = @import("std");
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() void {
|
||||
std.debug.print("Standard Library.\n", .{});
|
||||
|
|
|
@ -34,12 +34,12 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn main() void {
|
||||
const n: u8 = 50;
|
||||
var n: u8 = 50;
|
||||
n = n + 5;
|
||||
|
||||
const pi: u8 = 314159;
|
||||
const pi: u32 = 314159;
|
||||
|
||||
const negative_eleven: u8 = -11;
|
||||
const negative_eleven: i8 = -11;
|
||||
|
||||
// There are no errors in the next line, just explanation:
|
||||
// Perhaps you noticed before that the print function takes two
|
||||
|
|
|
@ -27,7 +27,7 @@ pub fn main() void {
|
|||
// (Problem 1)
|
||||
// This "const" is going to cause a problem later - can you see what it is?
|
||||
// How do we fix it?
|
||||
const some_primes = [_]u8{ 1, 3, 5, 7, 11, 13, 17, 19 };
|
||||
var some_primes = [_]u8{ 1, 3, 5, 7, 11, 13, 17, 19 };
|
||||
|
||||
// Individual values can be set with '[]' notation.
|
||||
// Example: This line changes the first prime to 2 (which is correct):
|
||||
|
@ -40,11 +40,11 @@ pub fn main() void {
|
|||
// (Problem 2)
|
||||
// Looks like we need to complete this expression. Use the example
|
||||
// above to set "fourth" to the fourth element of the some_primes array:
|
||||
const fourth = some_primes[???];
|
||||
const fourth = some_primes[3];
|
||||
|
||||
// (Problem 3)
|
||||
// Use the len property to get the length of the array:
|
||||
const length = some_primes.???;
|
||||
const length = some_primes.len;
|
||||
|
||||
std.debug.print("First: {}, Fourth: {}, Length: {}\n", .{
|
||||
first, fourth, length,
|
||||
|
|
|
@ -25,12 +25,12 @@ pub fn main() void {
|
|||
// (Problem 1)
|
||||
// Please set this array concatenating the two arrays above.
|
||||
// It should result in: 1 3 3 7
|
||||
const leet = ???;
|
||||
const leet = le ++ et;
|
||||
|
||||
// (Problem 2)
|
||||
// Please set this array using repetition.
|
||||
// It should result in: 1 0 0 1 1 0 0 1 1 0 0 1
|
||||
const bit_pattern = [_]u8{ ??? } ** 3;
|
||||
const bit_pattern = [_]u8{ 1, 0, 0, 1 } ** 3;
|
||||
|
||||
// Okay, that's all of the problems. Let's see the results.
|
||||
//
|
||||
|
|
|
@ -24,18 +24,18 @@ pub fn main() void {
|
|||
// (Problem 1)
|
||||
// Use array square bracket syntax to get the letter 'd' from
|
||||
// the string "stardust" above.
|
||||
const d: u8 = ziggy[???];
|
||||
const d: u8 = ziggy[4];
|
||||
|
||||
// (Problem 2)
|
||||
// Use the array repeat '**' operator to make "ha ha ha ".
|
||||
const laugh = "ha " ???;
|
||||
const laugh = "ha " ** 3;
|
||||
|
||||
// (Problem 3)
|
||||
// Use the array concatenation '++' operator to make "Major Tom".
|
||||
// (You'll need to add a space as well!)
|
||||
const major = "Major";
|
||||
const tom = "Tom";
|
||||
const major_tom = major ??? tom;
|
||||
const major_tom = major ++ " " ++ tom;
|
||||
|
||||
// That's all the problems. Let's see our results:
|
||||
std.debug.print("d={u} {s}{s}\n", .{ d, laugh, major_tom });
|
||||
|
|
|
@ -15,9 +15,9 @@ const std = @import("std");
|
|||
|
||||
pub fn main() void {
|
||||
const lyrics =
|
||||
Ziggy played guitar
|
||||
Jamming good with Andrew Kelley
|
||||
And the Spiders from Mars
|
||||
\\Ziggy played guitar
|
||||
\\Jamming good with Andrew Kelley
|
||||
\\And the Spiders from Mars
|
||||
;
|
||||
|
||||
std.debug.print("{s}\n", .{lyrics});
|
||||
|
|
|
@ -19,7 +19,7 @@ pub fn main() void {
|
|||
// the idiomatic type to use for array indexing.
|
||||
//
|
||||
// There IS a problem on this line, but 'usize' isn't it.
|
||||
const x: usize = 1;
|
||||
var x: usize = 1;
|
||||
|
||||
// Note: When you want to declare memory (an array in this
|
||||
// case) without putting anything in it, you can set it to
|
||||
|
@ -33,10 +33,10 @@ pub fn main() void {
|
|||
lang[0] = letters[x];
|
||||
|
||||
x = 3;
|
||||
lang[???] = letters[x];
|
||||
lang[1] = letters[x];
|
||||
|
||||
x = ???;
|
||||
lang[2] = letters[???];
|
||||
x = 5;
|
||||
lang[2] = letters[x];
|
||||
|
||||
// We want to "Program in Zig!" of course:
|
||||
std.debug.print("Program in {s}!\n", .{lang});
|
||||
|
|
|
@ -24,7 +24,7 @@ pub fn main() void {
|
|||
const foo = 1;
|
||||
|
||||
// Please fix this condition:
|
||||
if (foo) {
|
||||
if (foo == 1) {
|
||||
// We want our program to print this message!
|
||||
std.debug.print("Foo is 1!\n", .{});
|
||||
} else {
|
||||
|
|
|
@ -10,7 +10,7 @@ pub fn main() void {
|
|||
|
||||
// Please use an if...else expression to set "price".
|
||||
// If discount is true, the price should be $17, otherwise $20:
|
||||
const price: u8 = if ???;
|
||||
const price: u8 = if (discount) 17 else 20;
|
||||
|
||||
std.debug.print("With the discount, the price is ${}.\n", .{price});
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ pub fn main() void {
|
|||
var n: u32 = 2;
|
||||
|
||||
// Please use a condition that is true UNTIL "n" reaches 1024:
|
||||
while (???) {
|
||||
while (n < 1024) {
|
||||
// Print the current number
|
||||
std.debug.print("{} ", .{n});
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ pub fn main() void {
|
|||
|
||||
// Please set the continue expression so that we get the desired
|
||||
// results in the print statement below.
|
||||
while (n < 1000) : ??? {
|
||||
while (n < 1000) : (n *= 2) {
|
||||
// Print the current number
|
||||
std.debug.print("{} ", .{n});
|
||||
}
|
||||
|
|
|
@ -24,8 +24,8 @@ pub fn main() void {
|
|||
while (n <= 20) : (n += 1) {
|
||||
// The '%' symbol is the "modulo" operator and it
|
||||
// returns the remainder after division.
|
||||
if (n % 3 == 0) ???;
|
||||
if (n % 5 == 0) ???;
|
||||
if (n % 3 == 0) continue;
|
||||
if (n % 5 == 0) continue;
|
||||
std.debug.print("{} ", .{n});
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ pub fn main() void {
|
|||
// Oh dear! This while loop will go forever?!
|
||||
// Please fix this so the print statement below gives the desired output.
|
||||
while (true) : (n += 1) {
|
||||
if (???) ???;
|
||||
if (n > 3) break;
|
||||
}
|
||||
|
||||
// Result: we want n=4
|
||||
|
|
|
@ -15,7 +15,7 @@ pub fn main() void {
|
|||
|
||||
std.debug.print("A Dramatic Story: ", .{});
|
||||
|
||||
for (???) |???| {
|
||||
for (story) |scene| {
|
||||
if (scene == 'h') std.debug.print(":-) ", .{});
|
||||
if (scene == 's') std.debug.print(":-( ", .{});
|
||||
if (scene == 'n') std.debug.print(":-| ", .{});
|
||||
|
|
|
@ -25,7 +25,7 @@ pub fn main() void {
|
|||
// the value of the place as a power of two for each bit.
|
||||
//
|
||||
// See if you can figure out the missing pieces:
|
||||
for (bits, ???) |bit, ???| {
|
||||
for (bits, 0..) |bit, i| {
|
||||
// Note that we convert the usize i to a u32 with
|
||||
// @intCast(), a builtin function just like @import().
|
||||
// We'll learn about these properly in a later exercise.
|
||||
|
|
|
@ -9,18 +9,18 @@
|
|||
// Let's go from 1 to 16. This has been started for you, but there
|
||||
// are some problems. :-(
|
||||
//
|
||||
const std = import standard library;
|
||||
const std = @import("std");
|
||||
|
||||
function main() void {
|
||||
pub fn main() void {
|
||||
var i: u8 = 1;
|
||||
const stop_at: u8 = 16;
|
||||
|
||||
// What kind of loop is this? A 'for' or a 'while'?
|
||||
??? (i <= stop_at) : (i += 1) {
|
||||
while (i <= stop_at) : (i += 1) {
|
||||
if (i % 3 == 0) std.debug.print("Fizz", .{});
|
||||
if (i % 5 == 0) std.debug.print("Buzz", .{});
|
||||
if (!(i % 3 == 0) and !(i % 5 == 0)) {
|
||||
std.debug.print("{}", .{???});
|
||||
std.debug.print("{}", .{i});
|
||||
}
|
||||
std.debug.print(", ", .{});
|
||||
}
|
||||
|
|
|
@ -25,6 +25,6 @@ pub fn main() void {
|
|||
// We're just missing a couple things. One thing we're NOT missing is the
|
||||
// keyword "pub", which is not needed here. Can you guess why?
|
||||
//
|
||||
??? deepThought() ??? {
|
||||
fn deepThought() u8 {
|
||||
return 42; // Number courtesy Douglas Adams
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ pub fn main() void {
|
|||
// You'll need to figure out the parameter name and type that we're
|
||||
// expecting. The output type has already been specified for you.
|
||||
//
|
||||
fn twoToThe(???) u32 {
|
||||
fn twoToThe(my_number: u8) u32 {
|
||||
return std.math.pow(u32, 2, my_number);
|
||||
// std.math.pow(type, a, b) takes a numeric type and two
|
||||
// numbers of that type (or that can coerce to that type) and
|
||||
|
|
|
@ -21,8 +21,8 @@ pub fn main() void {
|
|||
//
|
||||
// This function prints, but does not return anything.
|
||||
//
|
||||
fn printPowersOfTwo(numbers: [4]u16) ??? {
|
||||
loop (numbers) |n| {
|
||||
fn printPowersOfTwo(numbers: [4]u16) void {
|
||||
for (numbers) |n| {
|
||||
std.debug.print("{} ", .{twoToThe(n)});
|
||||
}
|
||||
}
|
||||
|
@ -31,13 +31,13 @@ fn printPowersOfTwo(numbers: [4]u16) ??? {
|
|||
// exercise. But don't be fooled! This one does the math without the aid
|
||||
// of the standard library!
|
||||
//
|
||||
fn twoToThe(number: u16) ??? {
|
||||
fn twoToThe(number: u16) u32 {
|
||||
var n: u16 = 0;
|
||||
var total: u16 = 1;
|
||||
|
||||
loop (n < number) : (n += 1) {
|
||||
while (n < number) : (n += 1) {
|
||||
total *= 2;
|
||||
}
|
||||
|
||||
return ???;
|
||||
return total;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// "TooSmall". Please add it where needed!
|
||||
const MyNumberError = error{
|
||||
TooBig,
|
||||
???,
|
||||
TooSmall,
|
||||
TooFour,
|
||||
};
|
||||
|
||||
|
@ -26,7 +26,7 @@ pub fn main() void {
|
|||
if (number_error == MyNumberError.TooBig) {
|
||||
std.debug.print(">4. ", .{});
|
||||
}
|
||||
if (???) {
|
||||
if (number_error == MyNumberError.TooSmall) {
|
||||
std.debug.print("<4. ", .{});
|
||||
}
|
||||
if (number_error == MyNumberError.TooFour) {
|
||||
|
|
|
@ -19,7 +19,7 @@ const std = @import("std");
|
|||
const MyNumberError = error{TooSmall};
|
||||
|
||||
pub fn main() void {
|
||||
var my_number: ??? = 5;
|
||||
var my_number: MyNumberError!u8 = 5;
|
||||
|
||||
// Looks like my_number will need to either store a number OR
|
||||
// an error. Can you set the type correctly above?
|
||||
|
|
|
@ -12,14 +12,14 @@ const MyNumberError = error{TooSmall};
|
|||
|
||||
pub fn main() void {
|
||||
const a: u32 = addTwenty(44) catch 22;
|
||||
const b: u32 = addTwenty(4) ??? 22;
|
||||
const b: u32 = addTwenty(4) catch 22;
|
||||
|
||||
std.debug.print("a={}, b={}\n", .{ a, b });
|
||||
}
|
||||
|
||||
// Please provide the return type from this function.
|
||||
// Hint: it'll be an error union.
|
||||
fn addTwenty(n: u32) ??? {
|
||||
fn addTwenty(n: u32) MyNumberError!u32 {
|
||||
if (n < 5) {
|
||||
return MyNumberError.TooSmall;
|
||||
} else {
|
||||
|
|
|
@ -59,7 +59,12 @@ fn fixTooSmall(n: u32) MyNumberError!u32 {
|
|||
// If we get a TooSmall error, we should return 10.
|
||||
// If we get any other error, we should return that error.
|
||||
// Otherwise, we return the u32 number.
|
||||
return detectProblems(n) ???;
|
||||
return detectProblems(n) catch |err| {
|
||||
if (err == MyNumberError.TooSmall) {
|
||||
return 10;
|
||||
}
|
||||
return err;
|
||||
};
|
||||
}
|
||||
|
||||
fn detectProblems(n: u32) MyNumberError!u32 {
|
||||
|
|
|
@ -26,7 +26,7 @@ fn addFive(n: u32) MyNumberError!u32 {
|
|||
// This function needs to return any error which might come back from detect().
|
||||
// Please use a "try" statement rather than a "catch".
|
||||
//
|
||||
var x = detect(n);
|
||||
const x = try detect(n);
|
||||
|
||||
return x + 5;
|
||||
}
|
||||
|
|
|
@ -23,5 +23,5 @@ pub fn main() !void {
|
|||
// to be able to pass it up as a return value of main().
|
||||
//
|
||||
// We just learned of a single statement which can accomplish this.
|
||||
stdout.print("Hello world!\n", .{});
|
||||
try stdout.print("Hello world!\n", .{});
|
||||
}
|
||||
|
|
|
@ -20,6 +20,6 @@ const std = @import("std");
|
|||
pub fn main() void {
|
||||
// Without changing anything else, please add a 'defer' statement
|
||||
// to this code so that our program prints "One Two\n":
|
||||
std.debug.print("Two\n", .{});
|
||||
defer std.debug.print("Two\n", .{});
|
||||
std.debug.print("One ", .{});
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ pub fn main() void {
|
|||
fn printAnimal(animal: u8) void {
|
||||
std.debug.print("(", .{});
|
||||
|
||||
std.debug.print(") ", .{}); // <---- how?!
|
||||
defer std.debug.print(") ", .{}); // <---- how?!
|
||||
|
||||
if (animal == 'g') {
|
||||
std.debug.print("Goat", .{});
|
||||
|
|
|
@ -21,8 +21,8 @@ const MyErr = error{ GetFail, IncFail };
|
|||
|
||||
pub fn main() void {
|
||||
// We simply quit the entire program if we fail to get a number:
|
||||
var a: u32 = makeNumber() catch return;
|
||||
var b: u32 = makeNumber() catch return;
|
||||
const a: u32 = makeNumber() catch return;
|
||||
const b: u32 = makeNumber() catch return;
|
||||
|
||||
std.debug.print("Numbers: {}, {}\n", .{ a, b });
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ fn makeNumber() MyErr!u32 {
|
|||
|
||||
// Please make the "failed" message print ONLY if the makeNumber()
|
||||
// function exits with an error:
|
||||
std.debug.print("failed!\n", .{});
|
||||
errdefer std.debug.print("failed!\n", .{});
|
||||
|
||||
var num = try getNumber(); // <-- This could fail!
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ pub fn main() void {
|
|||
// match for every possible value). Please add an "else"
|
||||
// to this switch to print a question mark "?" when c is
|
||||
// not one of the existing matches.
|
||||
else => std.debug.print("?", .{}),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ pub fn main() void {
|
|||
26 => 'Z',
|
||||
// As in the last exercise, please add the 'else' clause
|
||||
// and this time, have it return an exclamation mark '!'.
|
||||
else => '!',
|
||||
};
|
||||
|
||||
std.debug.print("{c}", .{real_char});
|
||||
|
|
|
@ -35,6 +35,7 @@ pub fn main() void {
|
|||
3 => {
|
||||
current_value *= current_value;
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
std.debug.print("{} ", .{current_value});
|
||||
|
|
|
@ -39,7 +39,7 @@ pub fn main() void {
|
|||
std.debug.print("={}. ", .{value});
|
||||
} else |err| switch (err) {
|
||||
MyNumberError.TooBig => std.debug.print(">4. ", .{}),
|
||||
// Please add a match for TooSmall here and have it print: "<4. "
|
||||
MyNumberError.TooSmall => std.debug.print("<4. ", .{}),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,14 +6,11 @@
|
|||
// my_num=42
|
||||
//
|
||||
const std = @import("std");
|
||||
|
||||
const NumError = error{IllegalNumber};
|
||||
|
||||
pub fn main() void {
|
||||
pub fn main() !void {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
|
||||
const my_num: u32 = getNumber();
|
||||
|
||||
const my_num: u32 = try getNumber();
|
||||
try stdout.print("my_num={}\n", .{my_num});
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
const std = @import("std");
|
||||
|
||||
// Please complete the enum!
|
||||
const Ops = enum { ??? };
|
||||
const Ops = enum { inc, dec, pow };
|
||||
|
||||
pub fn main() void {
|
||||
const operations = [_]Ops{
|
||||
|
|
|
@ -31,7 +31,7 @@ const std = @import("std");
|
|||
const Color = enum(u32) {
|
||||
red = 0xff0000,
|
||||
green = 0x00ff00,
|
||||
blue = ???,
|
||||
blue = 0x0000ff,
|
||||
};
|
||||
|
||||
pub fn main() void {
|
||||
|
@ -53,12 +53,12 @@ pub fn main() void {
|
|||
\\<p>
|
||||
\\ <span style="color: #{x:0>6}">Red</span>
|
||||
\\ <span style="color: #{x:0>6}">Green</span>
|
||||
\\ <span style="color: #{}">Blue</span>
|
||||
\\ <span style="color: #{x:0>6}">Blue</span>
|
||||
\\</p>
|
||||
\\
|
||||
, .{
|
||||
@intFromEnum(Color.red),
|
||||
@intFromEnum(Color.green),
|
||||
@intFromEnum(???), // Oops! We're missing something!
|
||||
@intFromEnum(Color.blue), // Oops! We're missing something!
|
||||
});
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ const std = @import("std");
|
|||
|
||||
pub fn main() void {
|
||||
var num1: u8 = 5;
|
||||
var num1_pointer: *u8 = &num1;
|
||||
const num1_pointer: *u8 = &num1;
|
||||
|
||||
var num2: u8 = undefined;
|
||||
|
||||
|
|
|
@ -51,8 +51,6 @@ fn visitElephants(first_elephant: *Elephant) void {
|
|||
// We should stop once we encounter a tail that
|
||||
// does NOT point to another element. What can
|
||||
// we put here to make that happen?
|
||||
if (e.tail == null) ???;
|
||||
|
||||
e = e.tail.?;
|
||||
e = e.tail ???
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ const Elephant = struct {
|
|||
|
||||
pub fn print(self: *Elephant) void {
|
||||
// Prints elephant letter and [v]isited
|
||||
var v: u8 = if (self.visited) 'v' else ' ';
|
||||
const v: u8 = if (self.visited) 'v' else ' ';
|
||||
std.debug.print("{u}{u} ", .{ self.letter, v });
|
||||
}
|
||||
};
|
||||
|
|
|
@ -37,7 +37,7 @@ const Elephant = struct {
|
|||
|
||||
pub fn print(self: *Elephant) void {
|
||||
// Prints elephant letter and [v]isited
|
||||
var v: u8 = if (self.visited) 'v' else ' ';
|
||||
const v: u8 = if (self.visited) 'v' else ' ';
|
||||
std.debug.print("{u}{u} ", .{ self.letter, v });
|
||||
}
|
||||
};
|
||||
|
|
|
@ -141,9 +141,20 @@ pub fn main() void {
|
|||
//
|
||||
// Moving along...
|
||||
//
|
||||
// Passing arguments to functions is pretty much exactly like
|
||||
// making an assignment to a const (since Zig enforces that ALL
|
||||
// function parameters are const).
|
||||
// When arguments are passed to a function,
|
||||
// they are ALWAYS passed as constants within the function,
|
||||
// regardless of how they were declared in the calling function.
|
||||
//
|
||||
// Example:
|
||||
// fn foo(arg: u8) void {
|
||||
// arg = 42; // Error, 'arg' is const!
|
||||
// }
|
||||
//
|
||||
// fn bar() void {
|
||||
// var arg: u8 = 12;
|
||||
// foo(arg);
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// Knowing this, see if you can make levelUp() work as expected -
|
||||
// it should add the specified amount to the supplied character's
|
||||
|
|
|
@ -53,8 +53,8 @@ const AntOrBee = enum { a, b };
|
|||
|
||||
pub fn main() void {
|
||||
// We'll just make one bee and one ant to test them out:
|
||||
var ant = Insect{ .still_alive = true };
|
||||
var bee = Insect{ .flowers_visited = 15 };
|
||||
const ant = Insect{ .still_alive = true };
|
||||
const bee = Insect{ .flowers_visited = 15 };
|
||||
|
||||
std.debug.print("Insect report! ", .{});
|
||||
|
||||
|
|
|
@ -38,8 +38,8 @@ const Insect = union(InsectStat) {
|
|||
};
|
||||
|
||||
pub fn main() void {
|
||||
var ant = Insect{ .still_alive = true };
|
||||
var bee = Insect{ .flowers_visited = 16 };
|
||||
const ant = Insect{ .still_alive = true };
|
||||
const bee = Insect{ .flowers_visited = 16 };
|
||||
|
||||
std.debug.print("Insect report! ", .{});
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@ const Insect = union(InsectStat) {
|
|||
};
|
||||
|
||||
pub fn main() void {
|
||||
var ant = Insect{ .still_alive = true };
|
||||
var bee = Insect{ .flowers_visited = 17 };
|
||||
const ant = Insect{ .still_alive = true };
|
||||
const bee = Insect{ .flowers_visited = 17 };
|
||||
|
||||
std.debug.print("Insect report! ", .{});
|
||||
|
||||
|
|
|
@ -273,7 +273,7 @@ const HermitsNotebook = struct {
|
|||
// distance) than the one we'd noted before. If it is, we
|
||||
// overwrite the old entry with the new one.
|
||||
fn checkNote(self: *HermitsNotebook, note: NotebookEntry) void {
|
||||
var existing_entry = self.getEntry(note.place);
|
||||
const existing_entry = self.getEntry(note.place);
|
||||
|
||||
if (existing_entry == null) {
|
||||
self.entries[self.end_of_entries] = note;
|
||||
|
@ -386,7 +386,7 @@ pub fn main() void {
|
|||
// "start" entry we just added) until we run out, at which point
|
||||
// we'll have checked every reachable Place.
|
||||
while (notebook.hasNextEntry()) {
|
||||
var place_entry = notebook.getNextEntry();
|
||||
const place_entry = notebook.getNextEntry();
|
||||
|
||||
// For every Path that leads FROM the current Place, create a
|
||||
// new note (in the form of a NotebookEntry) with the
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
// Zig lets you express integer literals in several convenient
|
||||
// formats. These are all the same value:
|
||||
//
|
||||
// const a1: u8 = 65; // decimal
|
||||
// const a2: u8 = 0x41; // hexadecimal
|
||||
// const a3: u8 = 0o101; // octal
|
||||
// const a4: u8 = 0b1000001; // binary
|
||||
// const a5: u8 = 'A'; // ASCII code point literal
|
||||
// const a6: u16 = 'Ȁ'; // Unicode code points can take up to 21 bits
|
||||
// const a1: u8 = 65; // decimal
|
||||
// const a2: u8 = 0x41; // hexadecimal
|
||||
// const a3: u8 = 0o101; // octal
|
||||
// const a4: u8 = 0b1000001; // binary
|
||||
// const a5: u8 = 'A'; // ASCII code point literal
|
||||
// const a6: u16 = '\u{0041}'; // Unicode code points can take up to 21 bits
|
||||
//
|
||||
// You can also place underscores in numbers to aid readability:
|
||||
//
|
||||
|
|
|
@ -39,11 +39,11 @@ const print = @import("std").debug.print;
|
|||
|
||||
pub fn main() void {
|
||||
// The approximate weight of the Space Shuttle upon liftoff
|
||||
// (including boosters and fuel tank) was 2,200 tons.
|
||||
// (including boosters and fuel tank) was 4,480,000 lb.
|
||||
//
|
||||
// We'll convert this weight from tons to kilograms at a
|
||||
// conversion of 907.18kg to the ton.
|
||||
const shuttle_weight: f16 = 907.18 * 2200;
|
||||
// We'll convert this weight from pound to kilograms at a
|
||||
// conversion of 0.453592kg to the pound.
|
||||
const shuttle_weight: f16 = 0.453592 * 4480e6;
|
||||
|
||||
// By default, float values are formatted in scientific
|
||||
// notation. Try experimenting with '{d}' and '{d:.3}' to see
|
||||
|
|
|
@ -58,7 +58,7 @@ pub fn main() void {
|
|||
// There is a difference between
|
||||
// - a value, that overflowed at some point and is now corrupted
|
||||
// - a single operation that overflows and maybe causes subsequent errors
|
||||
// In practise we usually notice the overflowed value first and have to work
|
||||
// In practice we usually notice the overflowed value first and have to work
|
||||
// our way backwards to the operation that caused the overflow.
|
||||
//
|
||||
// If there was no overflow at all while adding 5 to a, what value would
|
||||
|
|
|
@ -38,16 +38,16 @@ pub fn main() void {
|
|||
var count = 0;
|
||||
|
||||
count += 1;
|
||||
var a1: [count]u8 = .{'A'} ** count;
|
||||
const a1: [count]u8 = .{'A'} ** count;
|
||||
|
||||
count += 1;
|
||||
var a2: [count]u8 = .{'B'} ** count;
|
||||
const a2: [count]u8 = .{'B'} ** count;
|
||||
|
||||
count += 1;
|
||||
var a3: [count]u8 = .{'C'} ** count;
|
||||
const a3: [count]u8 = .{'C'} ** count;
|
||||
|
||||
count += 1;
|
||||
var a4: [count]u8 = .{'D'} ** count;
|
||||
const a4: [count]u8 = .{'D'} ** count;
|
||||
|
||||
print("{s} {s} {s} {s}\n", .{ a1, a2, a3, a4 });
|
||||
|
||||
|
|
|
@ -83,19 +83,19 @@ const DuctError = error{UnmatchedDiameters};
|
|||
|
||||
pub fn main() void {
|
||||
// This is a real duck!
|
||||
var ducky1 = Duck{
|
||||
const ducky1 = Duck{
|
||||
.eggs = 0,
|
||||
.loudness = 3,
|
||||
};
|
||||
|
||||
// This is not a real duck, but it has quack() and waddle()
|
||||
// abilities, so it's still a "duck".
|
||||
var ducky2 = RubberDuck{
|
||||
const ducky2 = RubberDuck{
|
||||
.in_bath = false,
|
||||
};
|
||||
|
||||
// This is not even remotely a duck.
|
||||
var ducky3 = Duct{
|
||||
const ducky3 = Duct{
|
||||
.diameter = 17,
|
||||
.length = 165,
|
||||
.galvanized = true,
|
||||
|
|
|
@ -39,7 +39,7 @@ pub fn main() void {
|
|||
|
||||
// This gets the digit from the "instruction". Can you
|
||||
// figure out why we subtract '0' from it?
|
||||
comptime var digit = instructions[i + 1] - '0';
|
||||
const digit = instructions[i + 1] - '0';
|
||||
|
||||
// This 'switch' statement contains the actual work done
|
||||
// at runtime. At first, this doesn't seem exciting...
|
||||
|
|
|
@ -110,7 +110,7 @@ const HermitsNotebook = struct {
|
|||
}
|
||||
|
||||
fn checkNote(self: *HermitsNotebook, note: NotebookEntry) void {
|
||||
var existing_entry = self.getEntry(note.place);
|
||||
const existing_entry = self.getEntry(note.place);
|
||||
|
||||
if (existing_entry == null) {
|
||||
self.entries[self.end_of_entries] = note;
|
||||
|
@ -180,7 +180,7 @@ pub fn main() void {
|
|||
notebook.checkNote(working_note);
|
||||
|
||||
while (notebook.hasNextEntry()) {
|
||||
var place_entry = notebook.getNextEntry();
|
||||
const place_entry = notebook.getNextEntry();
|
||||
|
||||
for (place_entry.place.paths) |*path| {
|
||||
working_note = NotebookEntry{
|
||||
|
|
|
@ -46,7 +46,7 @@ pub fn main() void {
|
|||
var nums = [_:0]u32{ 1, 2, 3, 4, 5, 6 };
|
||||
|
||||
// And here's a zero-terminated many-item pointer:
|
||||
var ptr: [*:0]u32 = &nums;
|
||||
const ptr: [*:0]u32 = &nums;
|
||||
|
||||
// For fun, let's replace the value at position 3 with the
|
||||
// sentinel value 0. This seems kind of naughty.
|
||||
|
@ -74,8 +74,8 @@ pub fn main() void {
|
|||
fn printSequence(my_seq: anytype) void {
|
||||
const my_typeinfo = @typeInfo(@TypeOf(my_seq));
|
||||
|
||||
// The TypeInfo contained in my_type is a union. We use a
|
||||
// switch to handle printing the Array or Pointer fields,
|
||||
// The TypeInfo contained in my_typeinfo is a union. We use
|
||||
// a switch to handle printing the Array or Pointer fields,
|
||||
// depending on which type of my_seq was passed in:
|
||||
switch (my_typeinfo) {
|
||||
.Array => {
|
||||
|
|
|
@ -48,13 +48,13 @@ pub fn main() void {
|
|||
// * circle1 should hold i32 integers
|
||||
// * circle2 should hold f32 floats
|
||||
//
|
||||
var circle1 = ??? {
|
||||
const circle1 = ??? {
|
||||
.center_x = 25,
|
||||
.center_y = 70,
|
||||
.radius = 15,
|
||||
};
|
||||
|
||||
var circle2 = ??? {
|
||||
const circle2 = ??? {
|
||||
.center_x = 25.234,
|
||||
.center_y = 70.999,
|
||||
.radius = 15.714,
|
||||
|
|
|
@ -96,7 +96,7 @@ const Insect = union(enum) {
|
|||
};
|
||||
|
||||
pub fn main() !void {
|
||||
var my_insects = [_]Insect{
|
||||
const my_insects = [_]Insect{
|
||||
Insect{ .ant = Ant{ .still_alive = true } },
|
||||
Insect{ .bee = Bee{ .flowers_visited = 17 } },
|
||||
Insect{ .grasshopper = Grasshopper{ .distance_hopped = 32 } },
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
// our well-known "import" for Zig
|
||||
const std = @import("std");
|
||||
|
||||
// and here the new the import for C
|
||||
// and here the new import for C
|
||||
const c = @cImport({
|
||||
@cInclude("unistd.h");
|
||||
});
|
||||
|
|
|
@ -1,19 +1,26 @@
|
|||
//
|
||||
// Often, C functions are used where no equivalent Zig function exists
|
||||
// yet. Since the integration of a C function is very simple, as already
|
||||
// yet. Okay, that's getting less and less. ;-)
|
||||
//
|
||||
// Since the integration of a C function is very simple, as already
|
||||
// seen in the last exercise, it naturally offers itself to use the
|
||||
// very large variety of C functions for our own programs.
|
||||
// As an example:
|
||||
//
|
||||
// Let's say we have a given angle of 765.2 degrees. If we want to
|
||||
// normalize that, it means that we have to subtract X * 360 degrees
|
||||
// to get the correct angle. How could we do that? A good method is
|
||||
// to use the modulo function. But if we write "765.2 % 360", it won't
|
||||
// work, because the standard modulo function works only with integer
|
||||
// values. In the C library "math", there is a function called "fmod";
|
||||
// the "f" stands for floating and means that we can solve modulo for
|
||||
// real numbers. With this function, it should be possible to normalize
|
||||
// our angle. Let's go.
|
||||
// to get the correct angle.
|
||||
// How could we do that? A good method is to use the modulo function.
|
||||
// But if we write "765.2 % 360", it only works with float values
|
||||
// that are known at compile time.
|
||||
// In Zig, we would use @mod(a, b) instead.
|
||||
//
|
||||
// Let us now assume that we cannot do this in Zig, but only with
|
||||
// a C function from the standard library. In the library "math",
|
||||
// there is a function called "fmod"; the "f" stands for floating
|
||||
// and means that we can solve modulo for real numbers. With this
|
||||
// function, it should be possible to normalize our angle.
|
||||
// Let's go.
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
|
|
|
@ -30,9 +30,9 @@
|
|||
// std.debug.print("slice_ptr={*}\n", .{slice_ptr});
|
||||
// }
|
||||
|
||||
// Instead of a simple integer or a constant sized slice, this
|
||||
// program requires a slice to be allocated that is the same size as
|
||||
// an input array.
|
||||
// Instead of a simple integer or a slice with a constant size,
|
||||
// this program requires allocating a slice that is the same size
|
||||
// as an input array.
|
||||
|
||||
// Given a series of numbers, take the running average. In other
|
||||
// words, each item N should contain the average of the last N
|
||||
|
@ -52,7 +52,7 @@ fn runningAverage(arr: []const f64, avg: []f64) void {
|
|||
|
||||
pub fn main() !void {
|
||||
// pretend this was defined by reading in user input
|
||||
var arr: []const f64 = &[_]f64{ 0.3, 0.2, 0.1, 0.1, 0.4 };
|
||||
const arr: []const f64 = &[_]f64{ 0.3, 0.2, 0.1, 0.1, 0.4 };
|
||||
|
||||
// initialize the allocator
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
|
@ -64,7 +64,7 @@ pub fn main() !void {
|
|||
const allocator = arena.allocator();
|
||||
|
||||
// allocate memory for this array
|
||||
var avg: []f64 = ???;
|
||||
const avg: []f64 = ???;
|
||||
|
||||
runningAverage(arr, avg);
|
||||
std.debug.print("Running Average: ", .{});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Bit manipulations is a very powerful tool just also from Zig.
|
||||
// Bit manipulation is a very powerful tool, also from Zig.
|
||||
// Since the dawn of the computer age, numerous algorithms have been
|
||||
// developed that solve tasks solely by moving, setting, or logically
|
||||
// combining bits.
|
||||
|
@ -8,10 +8,10 @@
|
|||
// functions where possible. And it is often possible with calculations
|
||||
// based on integers.
|
||||
//
|
||||
// Often it is not easy to understand at first glance what exactly these
|
||||
// At first glance, it is often not easy to understand what exactly these
|
||||
// algorithms do when only "numbers" in memory areas change outwardly.
|
||||
// But it must never be forgotten that the numbers only represent the
|
||||
// interpretation of the bit sequences.
|
||||
// However, it should never be forgotten that the numbers only represent
|
||||
// the interpretation of the bit sequences.
|
||||
//
|
||||
// Quasi the reversed case we have otherwise, namely that we represent
|
||||
// numbers in bit sequences.
|
||||
|
@ -20,8 +20,8 @@
|
|||
//
|
||||
// Zig provides all the necessary functions to change the bits inside
|
||||
// a variable. It is distinguished whether the bit change leads to an
|
||||
// overflow or not.The details are in the Zig documentation in section
|
||||
// 10.1 "Table of Operators".
|
||||
// overflow or not. The details are in the Zig documentation in section
|
||||
// "Table of Operators".
|
||||
//
|
||||
// Here are some examples of how the bits of variables can be changed:
|
||||
//
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Another useful practice for bit manipulation is setting bits as flags.
|
||||
// Another useful application for bit manipulation is setting bits as flags.
|
||||
// This is especially useful when processing lists of something and storing
|
||||
// the states of the entries, e.g. a list of numbers and for each prime
|
||||
// number a flag is set.
|
||||
|
@ -19,9 +19,9 @@
|
|||
// For example, you could take an array of bool and set the value to 'true'
|
||||
// for each letter in the order of the alphabet (a=0; b=1; etc.) found in
|
||||
// the sentence. However, this is neither memory efficient nor particularly
|
||||
// fast. Instead we take a simpler way, very similar in principle, we define
|
||||
// a variable with at least 26 bits (e.g. u32) and also set the bit for each
|
||||
// letter found at the corresponding position.
|
||||
// fast. Instead we choose a simpler approach that is very similar in principle:
|
||||
// We define a variable with at least 26 bits (e.g. u32) and set the bit for
|
||||
// each letter that is found in the corresponding position.
|
||||
//
|
||||
// Zig provides functions for this in the standard library, but we prefer to
|
||||
// solve it without these extras, after all we want to learn something.
|
||||
|
@ -39,7 +39,7 @@ fn isPangram(str: []const u8) bool {
|
|||
// first we check if the string has at least 26 characters
|
||||
if (str.len < 26) return false;
|
||||
|
||||
// we uses a 32 bit variable of which we need 26 bits
|
||||
// we use a 32 bit variable of which we need 26 bits
|
||||
var bits: u32 = 0;
|
||||
|
||||
// loop about all characters in the string
|
||||
|
@ -49,7 +49,7 @@ fn isPangram(str: []const u8) bool {
|
|||
// then we set the bit at the position
|
||||
//
|
||||
// to do this, we use a little trick:
|
||||
// since the letters in the ASCI table start at 65
|
||||
// since the letters in the ASCII table start at 65
|
||||
// and are numbered sequentially, we simply subtract the
|
||||
// first letter (in this case the 'a') from the character
|
||||
// found, and thus get the position of the desired bit
|
||||
|
|
|
@ -19,10 +19,10 @@
|
|||
// https://github.com/ziglang/zig/blob/master/lib/std/fmt.zig#L29
|
||||
//
|
||||
// Zig already has a very nice selection of formatting options.
|
||||
// These can be used in different ways, but typically to convert
|
||||
// numerical values into various text representations. The
|
||||
// results can be used for direct output to a terminal or stored
|
||||
// for later use or written to a file. The latter is useful when
|
||||
// These can be used in different ways, but generally to convert
|
||||
// numerical values into various text representations. The results
|
||||
// can be used for direct output to a terminal or stored for
|
||||
// later use or written to a file. The latter is useful when
|
||||
// large amounts of data are to be processed by other programs.
|
||||
//
|
||||
// In Ziglings, we are concerned with the output to the console.
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
//
|
||||
// The functionality of the standard library is becoming increasingly
|
||||
// important in Zig. On the one hand, it is helpful to look at how
|
||||
// important in Zig. First of all, it is helpful to take a look at how
|
||||
// the individual functions are implemented. Because this is wonderfully
|
||||
// suitable as a template for your own functions. On the other hand,
|
||||
// these standard functions are part of the basic equipment of Zig.
|
||||
// suitable as a template for your own functions. In addition these
|
||||
// standard functions are part of the basic configuration of Zig.
|
||||
//
|
||||
// This means that they are always available on every system.
|
||||
// Therefore it is worthwhile to deal with them also in Ziglings.
|
||||
|
|
134
exercises/104_threading.zig
Normal file
134
exercises/104_threading.zig
Normal file
|
@ -0,0 +1,134 @@
|
|||
//
|
||||
// Whenever there is a lot to calculate, the question arises as to how
|
||||
// tasks can be carried out simultaneously. We have already learned about
|
||||
// one possibility, namely asynchronous processes, in Exercises 84-91.
|
||||
//
|
||||
// However, the computing power of the processor is only distributed to
|
||||
// the started and running tasks, which always reaches its limits when
|
||||
// pure computing power is called up.
|
||||
//
|
||||
// For example, in blockchains based on proof of work, the miners have
|
||||
// to find a nonce for a certain character string so that the first m bits
|
||||
// in the hash of the character string and the nonce are zeros.
|
||||
// As the miner who can solve the task first receives the reward, everyone
|
||||
// tries to complete the calculations as quickly as possible.
|
||||
//
|
||||
// This is where multithreading comes into play, where tasks are actually
|
||||
// distributed across several cores of the CPU or GPU, which then really
|
||||
// means a multiplication of performance.
|
||||
//
|
||||
// The following diagram roughly illustrates the difference between the
|
||||
// various types of process execution.
|
||||
// The 'Overall Time' column is intended to illustrate how the time is
|
||||
// affected if, instead of one core as in synchronous and asynchronous
|
||||
// processing, a second core now helps to complete the work in multithreading.
|
||||
//
|
||||
// In the ideal case shown, execution takes only half the time compared
|
||||
// to the synchronous single thread. And even asynchronous processing
|
||||
// is only slightly faster in comparison.
|
||||
//
|
||||
//
|
||||
// Synchronous Asynchronous
|
||||
// Processing Processing Multithreading
|
||||
// ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||
// │ Thread 1 │ │ Thread 1 │ │ Thread 1 │ │ Thread 2 │
|
||||
// ├──────────┤ ├──────────┤ ├──────────┤ ├──────────┤ Overall Time
|
||||
// └──┼┼┼┼┼───┴─┴──┼┼┼┼┼───┴──┴──┼┼┼┼┼───┴─┴──┼┼┼┼┼───┴──┬───────┬───────┬──
|
||||
// ├───┤ ├───┤ ├───┤ ├───┤ │ │ │
|
||||
// │ T │ │ T │ │ T │ │ T │ │ │ │
|
||||
// │ a │ │ a │ │ a │ │ a │ │ │ │
|
||||
// │ s │ │ s │ │ s │ │ s │ │ │ │
|
||||
// │ k │ │ k │ │ k │ │ k │ │ │ │
|
||||
// │ │ │ │ │ │ │ │ │ │ │
|
||||
// │ 1 │ │ 1 │ │ 1 │ │ 3 │ │ │ │
|
||||
// └─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘ │ │ │
|
||||
// │ │ │ │ 5 Sec │ │
|
||||
// ┌────┴───┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ │ │ │
|
||||
// │Blocking│ │ T │ │ T │ │ T │ │ │ │
|
||||
// └────┬───┘ │ a │ │ a │ │ a │ │ │ │
|
||||
// │ │ s │ │ s │ │ s │ │ 8 Sec │
|
||||
// ┌─┴─┐ │ k │ │ k │ │ k │ │ │ │
|
||||
// │ T │ │ │ │ │ │ │ │ │ │
|
||||
// │ a │ │ 2 │ │ 2 │ │ 4 │ │ │ │
|
||||
// │ s │ └─┬─┘ ├───┤ ├───┤ │ │ │
|
||||
// │ k │ │ │┼┼┼│ │┼┼┼│ ▼ │ 10 Sec
|
||||
// │ │ ┌─┴─┐ └───┴────────┴───┴───────── │ │
|
||||
// │ 1 │ │ T │ │ │
|
||||
// └─┬─┘ │ a │ │ │
|
||||
// │ │ s │ │ │
|
||||
// ┌─┴─┐ │ k │ │ │
|
||||
// │ T │ │ │ │ │
|
||||
// │ a │ │ 1 │ │ │
|
||||
// │ s │ ├───┤ │ │
|
||||
// │ k │ │┼┼┼│ ▼ │
|
||||
// │ │ └───┴──────────────────────────────────────────── │
|
||||
// │ 2 │ │
|
||||
// ├───┤ │
|
||||
// │┼┼┼│ ▼
|
||||
// └───┴────────────────────────────────────────────────────────────────
|
||||
//
|
||||
//
|
||||
// The diagram was modeled on the one in a blog in which the differences
|
||||
// between asynchronous processing and multithreading are explained in detail:
|
||||
// https://blog.devgenius.io/multi-threading-vs-asynchronous-programming-what-is-the-difference-3ebfe1179a5
|
||||
//
|
||||
// Our exercise is essentially about clarifying the approach in Zig and
|
||||
// therefore we try to keep it as simple as possible.
|
||||
// Multithreading in itself is already difficult enough. ;-)
|
||||
//
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() !void {
|
||||
// This is where the preparatory work takes place
|
||||
// before the parallel processing begins.
|
||||
std.debug.print("Starting work...\n", .{});
|
||||
|
||||
// These curly brackets are very important, they are necessary
|
||||
// to enclose the area where the threads are called.
|
||||
// Without these brackets, the program would not wait for the
|
||||
// end of the threads and they would continue to run beyond the
|
||||
// end of the program.
|
||||
{
|
||||
// Now we start the first thread, with the number as parameter
|
||||
const handle = try std.Thread.spawn(.{}, thread_function, .{1});
|
||||
|
||||
// Waits for the thread to complete,
|
||||
// then deallocates any resources created on `spawn()`.
|
||||
defer handle.join();
|
||||
|
||||
// Second thread
|
||||
const handle2 = try std.Thread.spawn(.{}, thread_function, .{-4}); // that can't be right?
|
||||
defer handle2.join();
|
||||
|
||||
// Third thread
|
||||
const handle3 = try std.Thread.spawn(.{}, thread_function, .{3});
|
||||
defer ??? // <-- something is missing
|
||||
|
||||
// After the threads have been started,
|
||||
// they run in parallel and we can still do some work in between.
|
||||
std.time.sleep(1500 * std.time.ns_per_ms);
|
||||
std.debug.print("Some weird stuff, after starting the threads.\n", .{});
|
||||
}
|
||||
// After we have left the closed area, we wait until
|
||||
// the threads have run through, if this has not yet been the case.
|
||||
std.debug.print("Zig is cool!\n", .{});
|
||||
}
|
||||
|
||||
// This function is started with every thread that we set up.
|
||||
// In our example, we pass the number of the thread as a parameter.
|
||||
fn thread_function(num: usize) !void {
|
||||
std.time.sleep(200 * num * std.time.ns_per_ms);
|
||||
std.debug.print("thread {d}: {s}\n", .{ num, "started." });
|
||||
|
||||
// This timer simulates the work of the thread.
|
||||
const work_time = 3 * ((5 - num % 3) - 2);
|
||||
std.time.sleep(work_time * std.time.ns_per_s);
|
||||
|
||||
std.debug.print("thread {d}: {s}\n", .{ num, "finished." });
|
||||
}
|
||||
// This is the easiest way to run threads in parallel.
|
||||
// In general, however, more management effort is required,
|
||||
// e.g. by setting up a pool and allowing the threads to communicate
|
||||
// with each other using semaphores.
|
||||
//
|
||||
// But that's a topic for another exercise.
|
107
exercises/105_threading2.zig
Normal file
107
exercises/105_threading2.zig
Normal file
|
@ -0,0 +1,107 @@
|
|||
//
|
||||
// Now that we are familiar with the principles of multi-threading,
|
||||
// let's boldly venture into a practical example from mathematics.
|
||||
// We will determine the circle number PI with sufficient accuracy.
|
||||
//
|
||||
// There are different methods for this, and some of them are several
|
||||
// hundred years old. For us, the dusty procedures are surprisingly well
|
||||
// suited to our exercise. Because the mathematicians of the time didn't
|
||||
// have fancy computers with which we can calculate something like this
|
||||
// in seconds today.
|
||||
// Whereby, of course, it depends on the accuracy, i.e. how many digits
|
||||
// after the decimal point we are interested in.
|
||||
// But these old procedures can still be tackled with paper and pencil,
|
||||
// which is why they are easier for us to understand.
|
||||
// At least for me. ;-)
|
||||
//
|
||||
// So let's take a mental leap back a few years.
|
||||
// Around 1672 (if you want to know and read about it in detail, you can
|
||||
// do so on Wikipedia, for example), various mathematicians once again
|
||||
// discovered a method of approaching the circle number PI.
|
||||
// There were the Scottish mathematician Gregory and the German
|
||||
// mathematician Leibniz, and even a few hundred years earlier the Indian
|
||||
// mathematician Madhava. All of them independently developed the same
|
||||
// formula, which was published by Leibnitz in 1682 in the journal
|
||||
// "Acta Eruditorum".
|
||||
// This is why this method has become known as the "Leibnitz series",
|
||||
// although the other names are also often used today.
|
||||
// We will not go into the formula and its derivation in detail, but
|
||||
// will deal with the series straight away:
|
||||
//
|
||||
// 4 4 4 4 4
|
||||
// PI = --- - --- + --- - --- + --- ...
|
||||
// 1 3 5 7 9
|
||||
//
|
||||
// As you can clearly see, the series starts with the whole number 4 and
|
||||
// approaches the circle number by subtracting and adding smaller and
|
||||
// smaller parts of 4. Pretty much everyone has learned PI = 3.14 at school,
|
||||
// but very few people remember other digits, and this is rarely necessary
|
||||
// in practice. Because either you don't need the precision, or you use a
|
||||
// calculator in which the number is stored as a very precise constant.
|
||||
// But at some point this constant was calculated and we are doing the same
|
||||
// now.The question at this point is, how many partial values do we have
|
||||
// to calculate for which accuracy?
|
||||
//
|
||||
// The answer is chewing, to get 8 digits after the decimal point we need
|
||||
// 1,000,000,000 partial values. And for each additional digit we have to
|
||||
// add a zero.
|
||||
// Even fast computers - and I mean really fast computers - get a bit warmer
|
||||
// on the CPU when it comes to really many digits. But the 8 digits are
|
||||
// enough for us for now, because we want to understand the principle and
|
||||
// nothing more, right?
|
||||
//
|
||||
// As we have already discovered, the Leibnitz series is a series with a
|
||||
// fixed distance of 2 between the individual partial values. This makes
|
||||
// it easy to apply a simple loop to it, because if we start with n = 1
|
||||
// (which is not necessarily useful now) we always have to add 2 in each
|
||||
// round.
|
||||
// But wait! The partial values are alternately added and subtracted.
|
||||
// This could also be achieved with one loop, but not very elegantly.
|
||||
// It also makes sense to split this between two CPUs, one calculates
|
||||
// the positive values and the other the negative values. And so we can
|
||||
// simply start two threads and add everything up at the end and we're
|
||||
// done.
|
||||
// We just have to remember that if only the positive or negative values
|
||||
// are calculated, the distances are twice as large, i.e. 4.
|
||||
//
|
||||
// So that the whole thing has a real learning effect, the first thread
|
||||
// call is specified and you have to make the second.
|
||||
// But don't worry, it will work out. :-)
|
||||
//
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() !void {
|
||||
const count = 1_000_000_000;
|
||||
var pi_plus: f64 = 0;
|
||||
var pi_minus: f64 = 0;
|
||||
|
||||
{
|
||||
// First thread to calculate the plus numbers.
|
||||
const handle1 = try std.Thread.spawn(.{}, thread_pi, .{ &pi_plus, 5, count });
|
||||
defer handle1.join();
|
||||
|
||||
// Second thread to calculate the minus numbers.
|
||||
???
|
||||
|
||||
}
|
||||
// Here we add up the results.
|
||||
std.debug.print("PI ≈ {d:.8}\n", .{4 + pi_plus - pi_minus});
|
||||
}
|
||||
|
||||
fn thread_pi(pi: *f64, begin: u64, end: u64) !void {
|
||||
var n: u64 = begin;
|
||||
while (n < end) : (n += 4) {
|
||||
pi.* += 4 / @as(f64, @floatFromInt(n));
|
||||
}
|
||||
}
|
||||
// If you wish, you can increase the number of loop passes, which
|
||||
// improves the number of digits.
|
||||
//
|
||||
// But be careful:
|
||||
// In order for parallel processing to really show its strengths,
|
||||
// the compiler must be given the "-O ReleaseFast" flag when it
|
||||
// is created. Otherwise the debug functions slow down the speed
|
||||
// to such an extent that seconds become minutes during execution.
|
||||
//
|
||||
// And you should remove the formatting restriction in "print",
|
||||
// otherwise you will not be able to see the additional digits.
|
92
exercises/106_files.zig
Normal file
92
exercises/106_files.zig
Normal file
|
@ -0,0 +1,92 @@
|
|||
//
|
||||
// Until now, we've only been printing our output in the console,
|
||||
// which is good enough for fighting alien and hermit bookkeeping.
|
||||
//
|
||||
// However, many other task require some interaction with the file system,
|
||||
// which is the underlying structure for organizing files on your computer.
|
||||
//
|
||||
// The File System provide a hierarchical structure for storing files
|
||||
// by organizing files into directories, which hold files and other directories,
|
||||
// thus creating a tree structure for navigating.
|
||||
//
|
||||
// Fortunately, zig standard library provide a simple api for interacting
|
||||
// with the file system, see the detail documentation here
|
||||
//
|
||||
// https://ziglang.org/documentation/master/std/#std.fs
|
||||
//
|
||||
// In this exercise, we'll try to
|
||||
// - create a new directory
|
||||
// - open a file in the directory
|
||||
// - write to the file.
|
||||
//
|
||||
// import std as always
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() !void {
|
||||
// first we get the current working directory
|
||||
const cwd: std.fs.Dir = std.fs.cwd();
|
||||
|
||||
// then we'll try to make a new directory /output/
|
||||
// to put our output files.
|
||||
cwd.makeDir("output") catch |e| switch (e) {
|
||||
// there are chance you might want to run this
|
||||
// program more than once and the path might already
|
||||
// been created, so we'll have to handle this error
|
||||
// by doing nothing
|
||||
//
|
||||
// we want to catch error.PathAlreadyExists and do nothing
|
||||
??? => {},
|
||||
// if is any other unexpected error we just propagate it through
|
||||
else => return e,
|
||||
};
|
||||
|
||||
// then we'll try to open our freshly created directory
|
||||
// wait a minute
|
||||
// opening a directory might fail!
|
||||
// what should we do here?
|
||||
var output_dir: std.fs.Dir = cwd.openDir("output", .{});
|
||||
defer output_dir.close();
|
||||
|
||||
// we try to open the file `zigling.txt`,
|
||||
// and propagate the error up if there are any errors
|
||||
const file: std.fs.File = try output_dir.createFile("zigling.txt", .{});
|
||||
// it is a good habit to close a file after you are done with it
|
||||
// so that other programs can read it and prevent data corruption
|
||||
// but here we are not yet done writing to the file
|
||||
// if only there were a keyword in zig that
|
||||
// allows you "defer" code execute to the end of scope...
|
||||
file.close();
|
||||
|
||||
// !you are not allowed to switch these two lines above the file closing line!
|
||||
const byte_written = try file.write("It's zigling time!");
|
||||
std.debug.print("Successfully wrote {d} bytes.\n", .{byte_written});
|
||||
}
|
||||
// to check if you actually write to the file, you can either,
|
||||
// 1. open the file on your text editor, or
|
||||
// 2. print the content of the file in the console with the following command
|
||||
// >> cat ./output/zigling.txt
|
||||
//
|
||||
//
|
||||
// More on Creating files
|
||||
//
|
||||
// notice in:
|
||||
// ... try output_dir.createFile("zigling.txt", .{});
|
||||
// ^^^
|
||||
// we passed this anonymous struct to the function call
|
||||
//
|
||||
// this is the struct `CreateFlag` with default fields
|
||||
// {
|
||||
// read: bool = false,
|
||||
// truncate: bool = true,
|
||||
// exclusive: bool = false,
|
||||
// lock: Lock = .none,
|
||||
// lock_nonblocking: bool = false,
|
||||
// mode: Mode = default_mode
|
||||
// }
|
||||
//
|
||||
// Question:
|
||||
// - what should you do if you want to also read the file after opening it?
|
||||
// - go to documentation of the struct `std.fs.Dir` here
|
||||
// https://ziglang.org/documentation/master/std/#std.fs.Dir
|
||||
// - can you find a function for opening a file? how about deleting a file?
|
||||
// - what kind of options can you use with those functions?
|
52
exercises/107_files2.zig
Normal file
52
exercises/107_files2.zig
Normal file
|
@ -0,0 +1,52 @@
|
|||
//
|
||||
// Prerequisite :
|
||||
// - exercise/106_files.zig, or
|
||||
// - create a file {project_root}/output/zigling.txt
|
||||
// with content `It's zigling time!`(18 byte total)
|
||||
//
|
||||
// Now there no point in writing to a file if we don't read from it am I right?
|
||||
// let's write a program to read the content of the file that we just created.
|
||||
//
|
||||
// I am assuming that you've created the appropriate files for this to work.
|
||||
//
|
||||
// Alright, bud, lean in close here's the game plan.
|
||||
// - First, we open the {project_root}/output/ directory
|
||||
// - Secondly, we open file `zigling.txt` in that directory
|
||||
// - then, we initalize an array of characters with all letter 'A', and print it
|
||||
// - After that, we read the content of the file to the array
|
||||
// - Finally, we print out the read content
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() !void {
|
||||
// Get the current working directory
|
||||
const cwd = std.fs.cwd();
|
||||
|
||||
// try to open ./output assuming you did your 106_files exercise
|
||||
var output_dir = try cwd.openDir("output", .{});
|
||||
defer output_dir.close();
|
||||
|
||||
// try to open the file
|
||||
const file = try output_dir.openFile("zigling.txt", .{});
|
||||
defer file.close();
|
||||
|
||||
// initalize an array of u8 with all letter 'A'.
|
||||
// we need to pick the size of the array, 64 seems like a good number.
|
||||
// fix the initalization below
|
||||
var content = ['A']*64;
|
||||
// this should print out : `AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA`
|
||||
std.debug.print("{s}\n", .{content});
|
||||
|
||||
// okay, seems like a threat of violence is not the answer in this case
|
||||
// can you go here to find a way to read the content ?
|
||||
// https://ziglang.org/documentation/master/std/#std.fs.File
|
||||
// hint: you might find two answers that are both vaild in this case
|
||||
const bytes_read = zig_read_the_file_or_i_will_fight_you(&content);
|
||||
|
||||
// Woah, too screamy, I know you're excited for zigling time but tone it down a bit
|
||||
// Can you print only what we read from the file ?
|
||||
std.debug.print("Successfully Read {d} bytes: {s}\n", .{
|
||||
bytes_read,
|
||||
content, // change this line only
|
||||
});
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
--- exercises/025_errors5.zig 2023-10-03 22:15:22.122241138 +0200
|
||||
+++ answers/025_errors5.zig 2023-10-05 20:04:06.952764946 +0200
|
||||
--- exercises/025_errors5.zig 2023-11-21 14:22:48.159250165 +0100
|
||||
+++ answers/025_errors5.zig 2023-11-21 14:25:01.338277886 +0100
|
||||
@@ -26,7 +26,7 @@
|
||||
// This function needs to return any error which might come back from detect().
|
||||
// Please use a "try" statement rather than a "catch".
|
||||
//
|
||||
- var x = detect(n);
|
||||
+ var x = try detect(n);
|
||||
- const x = detect(n);
|
||||
+ const x = try detect(n);
|
||||
|
||||
return x + 5;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
--- exercises/046_optionals2.zig 2023-10-03 22:15:22.122241138 +0200
|
||||
+++ answers/046_optionals2.zig 2023-10-05 20:04:07.049433424 +0200
|
||||
--- exercises/046_optionals2.zig 2024-05-10 23:11:25.796632478 +0200
|
||||
+++ answers/046_optionals2.zig 2024-05-10 23:10:16.115335668 +0200
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
const Elephant = struct {
|
||||
|
@ -9,12 +9,11 @@
|
|||
visited: bool = false,
|
||||
};
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
@@ -51,6 +51,6 @@
|
||||
// We should stop once we encounter a tail that
|
||||
// does NOT point to another element. What can
|
||||
// we put here to make that happen?
|
||||
- if (e.tail == null) ???;
|
||||
+ if (e.tail == null) break;
|
||||
|
||||
e = e.tail.?;
|
||||
- e = e.tail ???
|
||||
+ e = e.tail orelse break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
--- exercises/051_values.zig 2023-10-03 22:15:22.122241138 +0200
|
||||
+++ answers/051_values.zig 2023-10-05 20:04:07.072767194 +0200
|
||||
--- exercises/051_values.zig 2024-03-14 23:25:42.695020607 +0100
|
||||
+++ answers/051_values.zig 2024-03-14 23:28:34.525109174 +0100
|
||||
@@ -87,7 +87,7 @@
|
||||
// Let's assign the std.debug.print function to a const named
|
||||
// "print" so that we can use this new name later!
|
||||
|
@ -9,7 +9,7 @@
|
|||
|
||||
// Now let's look at assigning and pointing to values in Zig.
|
||||
//
|
||||
@@ -152,13 +152,13 @@
|
||||
@@ -163,13 +163,13 @@
|
||||
print("XP before:{}, ", .{glorp.experience});
|
||||
|
||||
// Fix 1 of 2 goes here:
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
--- exercises/060_floats.zig 2023-10-03 22:15:22.125574535 +0200
|
||||
+++ answers/060_floats.zig 2023-10-05 20:04:07.112767942 +0200
|
||||
--- exercises/060_floats.zig 2023-11-06 19:45:03.609687304 +0100
|
||||
+++ answers/060_floats.zig 2023-11-06 19:44:49.249419994 +0100
|
||||
@@ -43,7 +43,7 @@
|
||||
//
|
||||
// We'll convert this weight from tons to kilograms at a
|
||||
// conversion of 907.18kg to the ton.
|
||||
- const shuttle_weight: f16 = 907.18 * 2200;
|
||||
+ const shuttle_weight: f32 = 907.18 * 2200.0;
|
||||
// We'll convert this weight from pound to kilograms at a
|
||||
// conversion of 0.453592kg to the pound.
|
||||
- const shuttle_weight: f16 = 0.453592 * 4480e6;
|
||||
+ const shuttle_weight: f32 = 0.453592 * 4.480e6;
|
||||
|
||||
// By default, float values are formatted in scientific
|
||||
// notation. Try experimenting with '{d}' and '{d:.3}' to see
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
--- exercises/067_comptime2.zig 2023-10-03 22:15:22.125574535 +0200
|
||||
+++ answers/067_comptime2.zig 2023-10-05 20:04:07.146101899 +0200
|
||||
--- exercises/067_comptime2.zig 2023-11-21 14:36:12.080295365 +0100
|
||||
+++ answers/067_comptime2.zig 2023-11-21 15:11:50.814098876 +0100
|
||||
@@ -35,7 +35,7 @@
|
||||
// In this contrived example, we've decided to allocate some
|
||||
// arrays using a variable count! But something's missing...
|
||||
|
@ -8,4 +8,4 @@
|
|||
+ comptime var count = 0;
|
||||
|
||||
count += 1;
|
||||
var a1: [count]u8 = .{'A'} ** count;
|
||||
const a1: [count]u8 = .{'A'} ** count;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
--- exercises/075_quiz8.zig 2023-10-03 22:15:22.125574535 +0200
|
||||
+++ answers/075_quiz8.zig 2023-10-05 20:04:07.182769252 +0200
|
||||
--- exercises/075_quiz8.zig 2023-11-21 14:48:15.440702720 +0100
|
||||
+++ answers/075_quiz8.zig 2023-11-21 14:50:23.453311616 +0100
|
||||
@@ -49,7 +49,11 @@
|
||||
//
|
||||
// Please fill in the body of this function!
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
--- exercises/080_anonymous_structs.zig 2023-10-03 22:15:22.125574535 +0200
|
||||
+++ answers/080_anonymous_structs.zig 2023-10-05 20:04:07.202769626 +0200
|
||||
--- exercises/080_anonymous_structs.zig 2023-11-21 14:52:54.312749682 +0100
|
||||
+++ answers/080_anonymous_structs.zig 2023-11-21 14:52:43.909225238 +0100
|
||||
@@ -48,13 +48,13 @@
|
||||
// * circle1 should hold i32 integers
|
||||
// * circle2 should hold f32 floats
|
||||
//
|
||||
- var circle1 = ??? {
|
||||
+ var circle1 = Circle(i32){
|
||||
- const circle1 = ??? {
|
||||
+ const circle1 = Circle(i32){
|
||||
.center_x = 25,
|
||||
.center_y = 70,
|
||||
.radius = 15,
|
||||
};
|
||||
|
||||
- var circle2 = ??? {
|
||||
+ var circle2 = Circle(f32){
|
||||
- const circle2 = ??? {
|
||||
+ const circle2 = Circle(f32){
|
||||
.center_x = 25.234,
|
||||
.center_y = 70.999,
|
||||
.radius = 15.714,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
--- exercises/094_c_math.zig 2023-10-22 14:00:02.909379696 +0200
|
||||
+++ answers/094_c_math.zig 2023-10-22 14:02:46.709025235 +0200
|
||||
@@ -19,7 +19,7 @@
|
||||
--- exercises/094_c_math.zig 2024-02-28 12:50:35.789939935 +0100
|
||||
+++ answers/094_c_math.zig 2024-02-28 12:53:57.910309471 +0100
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
const c = @cImport({
|
||||
// What do we need here?
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
--- exercises/096_memory_allocation.zig 2023-10-03 22:15:22.125574535 +0200
|
||||
+++ answers/096_memory_allocation.zig 2023-10-05 20:04:07.276104333 +0200
|
||||
--- exercises/096_memory_allocation.zig 2023-11-21 14:55:33.805678390 +0100
|
||||
+++ answers/096_memory_allocation.zig 2023-11-21 14:56:00.236163484 +0100
|
||||
@@ -64,7 +64,7 @@
|
||||
const allocator = arena.allocator();
|
||||
|
||||
// allocate memory for this array
|
||||
- var avg: []f64 = ???;
|
||||
+ var avg: []f64 = try allocator.alloc(f64, arr.len);
|
||||
- const avg: []f64 = ???;
|
||||
+ const avg: []f64 = try allocator.alloc(f64, arr.len);
|
||||
|
||||
runningAverage(arr, avg);
|
||||
std.debug.print("Running Average: ", .{});
|
||||
|
|
17
patches/patches/104_threading.patch
Normal file
17
patches/patches/104_threading.patch
Normal file
|
@ -0,0 +1,17 @@
|
|||
--- exercises/104_threading.zig 2024-04-10 19:12:29.878856370 +0200
|
||||
+++ answers/104_threading.zig 2024-04-10 19:11:22.304265713 +0200
|
||||
@@ -97,12 +97,12 @@
|
||||
defer handle.join();
|
||||
|
||||
// Second thread
|
||||
- const handle2 = try std.Thread.spawn(.{}, thread_function, .{-4}); // that can't be right?
|
||||
+ const handle2 = try std.Thread.spawn(.{}, thread_function, .{2});
|
||||
defer handle2.join();
|
||||
|
||||
// Third thread
|
||||
const handle3 = try std.Thread.spawn(.{}, thread_function, .{3});
|
||||
- defer ??? // <-- something is missing
|
||||
+ defer handle3.join();
|
||||
|
||||
// After the threads have been started,
|
||||
// they run in parallel and we can still do some work in between.
|
13
patches/patches/105_threading2.patch
Normal file
13
patches/patches/105_threading2.patch
Normal file
|
@ -0,0 +1,13 @@
|
|||
--- exercises/105_threading2.zig 2024-03-23 16:35:14.754540802 +0100
|
||||
+++ answers/105_threading2.zig 2024-03-23 16:38:00.577539733 +0100
|
||||
@@ -81,8 +81,8 @@
|
||||
defer handle1.join();
|
||||
|
||||
// Second thread to calculate the minus numbers.
|
||||
- ???
|
||||
-
|
||||
+ const handle2 = try std.Thread.spawn(.{}, thread_pi, .{ &pi_minus, 3, count });
|
||||
+ defer handle2.join();
|
||||
}
|
||||
// Here we add up the results.
|
||||
std.debug.print("PI ≈ {d:.8}\n", .{4 + pi_plus - pi_minus});
|
29
patches/patches/106_files.patch
Normal file
29
patches/patches/106_files.patch
Normal file
|
@ -0,0 +1,29 @@
|
|||
--- exercises/106_files.zig 2024-05-05 00:48:25.808548611 +0200
|
||||
+++ answers/106_files.zig 2024-05-05 01:00:40.742969819 +0200
|
||||
@@ -35,7 +35,7 @@
|
||||
// by doing nothing
|
||||
//
|
||||
// we want to catch error.PathAlreadyExists and do nothing
|
||||
- ??? => {},
|
||||
+ error.PathAlreadyExists => {},
|
||||
// if is any other unexpected error we just propagate it through
|
||||
else => return e,
|
||||
};
|
||||
@@ -44,7 +44,7 @@
|
||||
// wait a minute
|
||||
// opening a directory might fail!
|
||||
// what should we do here?
|
||||
- var output_dir: std.fs.Dir = cwd.openDir("output", .{});
|
||||
+ var output_dir: std.fs.Dir = try cwd.openDir("output", .{});
|
||||
defer output_dir.close();
|
||||
|
||||
// we try to open the file `zigling.txt`,
|
||||
@@ -55,7 +55,7 @@
|
||||
// but here we are not yet done writing to the file
|
||||
// if only there were a keyword in zig that
|
||||
// allows you "defer" code execute to the end of scope...
|
||||
- file.close();
|
||||
+ defer file.close();
|
||||
|
||||
// !you are not allowed to switch these two lines above the file closing line!
|
||||
const byte_written = try file.write("It's zigling time!");
|
26
patches/patches/107_files2.patch
Normal file
26
patches/patches/107_files2.patch
Normal file
|
@ -0,0 +1,26 @@
|
|||
--- exercises/107_files2.zig 2024-05-05 00:48:25.808548611 +0200
|
||||
+++ answers/107_files2.zig 2024-05-05 01:14:03.866062288 +0200
|
||||
@@ -33,7 +33,7 @@
|
||||
// initalize an array of u8 with all letter 'A'.
|
||||
// we need to pick the size of the array, 64 seems like a good number.
|
||||
// fix the initalization below
|
||||
- var content = ['A']*64;
|
||||
+ var content = [_]u8{'A'} ** 64;
|
||||
// this should print out : `AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA`
|
||||
std.debug.print("{s}\n", .{content});
|
||||
|
||||
@@ -41,12 +41,12 @@
|
||||
// can you go here to find a way to read the content ?
|
||||
// https://ziglang.org/documentation/master/std/#std.fs.File
|
||||
// hint: you might find two answers that are both vaild in this case
|
||||
- const bytes_read = zig_read_the_file_or_i_will_fight_you(&content);
|
||||
+ const bytes_read = try file.read(&content);
|
||||
|
||||
// Woah, too screamy, I know you're excited for zigling time but tone it down a bit
|
||||
// Can you print only what we read from the file ?
|
||||
std.debug.print("Successfully Read {d} bytes: {s}\n", .{
|
||||
bytes_read,
|
||||
- content, // change this line only
|
||||
+ content[0..bytes_read], // change this line only
|
||||
});
|
||||
}
|
|
@ -8,8 +8,8 @@ const mem = std.mem;
|
|||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Child = std.process.Child;
|
||||
const Build = std.build;
|
||||
const FileSource = std.Build.FileSource;
|
||||
const Build = std.Build;
|
||||
const LazyPath = std.Build.LazyPath;
|
||||
const Reader = fs.File.Reader;
|
||||
const RunStep = std.Build.RunStep;
|
||||
const Step = Build.Step;
|
||||
|
@ -33,7 +33,7 @@ pub fn addCliTests(b: *std.Build, exercises: []const Exercise) *Step {
|
|||
const n = ex.number();
|
||||
|
||||
const cmd = b.addSystemCommand(&.{
|
||||
b.zig_exe,
|
||||
b.graph.zig_exe,
|
||||
"build",
|
||||
"-Dhealed",
|
||||
b.fmt("-Dhealed-path={s}", .{tmp_path}),
|
||||
|
@ -69,7 +69,7 @@ pub fn addCliTests(b: *std.Build, exercises: []const Exercise) *Step {
|
|||
|
||||
// TODO: when an exercise is modified, the cache is not invalidated.
|
||||
const cmd = b.addSystemCommand(&.{
|
||||
b.zig_exe,
|
||||
b.graph.zig_exe,
|
||||
"build",
|
||||
"-Dhealed",
|
||||
b.fmt("-Dhealed-path={s}", .{tmp_path}),
|
||||
|
@ -99,7 +99,7 @@ pub fn addCliTests(b: *std.Build, exercises: []const Exercise) *Step {
|
|||
const n = ex.number();
|
||||
|
||||
const cmd = b.addSystemCommand(&.{
|
||||
b.zig_exe,
|
||||
b.graph.zig_exe,
|
||||
"build",
|
||||
b.fmt("-Dn={}", .{n}),
|
||||
});
|
||||
|
@ -132,9 +132,9 @@ fn createCase(b: *Build, name: []const u8) *Step {
|
|||
const CheckNamedStep = struct {
|
||||
step: Step,
|
||||
exercise: Exercise,
|
||||
stderr: FileSource,
|
||||
stderr: LazyPath,
|
||||
|
||||
pub fn create(owner: *Build, exercise: Exercise, stderr: FileSource) *CheckNamedStep {
|
||||
pub fn create(owner: *Build, exercise: Exercise, stderr: LazyPath) *CheckNamedStep {
|
||||
const self = owner.allocator.create(CheckNamedStep) catch @panic("OOM");
|
||||
self.* = .{
|
||||
.step = Step.init(.{
|
||||
|
@ -152,7 +152,7 @@ const CheckNamedStep = struct {
|
|||
|
||||
fn make(step: *Step, _: *std.Progress.Node) !void {
|
||||
const b = step.owner;
|
||||
const self = @fieldParentPtr(CheckNamedStep, "step", step);
|
||||
const self: *CheckNamedStep = @alignCast(@fieldParentPtr("step", step));
|
||||
const ex = self.exercise;
|
||||
|
||||
const stderr_file = try fs.cwd().openFile(
|
||||
|
@ -180,12 +180,12 @@ const CheckNamedStep = struct {
|
|||
const CheckStep = struct {
|
||||
step: Step,
|
||||
exercises: []const Exercise,
|
||||
stderr: FileSource,
|
||||
stderr: LazyPath,
|
||||
|
||||
pub fn create(
|
||||
owner: *Build,
|
||||
exercises: []const Exercise,
|
||||
stderr: FileSource,
|
||||
stderr: LazyPath,
|
||||
) *CheckStep {
|
||||
const self = owner.allocator.create(CheckStep) catch @panic("OOM");
|
||||
self.* = .{
|
||||
|
@ -204,7 +204,7 @@ const CheckStep = struct {
|
|||
|
||||
fn make(step: *Step, _: *std.Progress.Node) !void {
|
||||
const b = step.owner;
|
||||
const self = @fieldParentPtr(CheckStep, "step", step);
|
||||
const self: *CheckStep = @alignCast(@fieldParentPtr("step", step));
|
||||
const exercises = self.exercises;
|
||||
|
||||
const stderr_file = try fs.cwd().openFile(
|
||||
|
@ -327,7 +327,7 @@ const FailStep = struct {
|
|||
|
||||
fn make(step: *Step, _: *std.Progress.Node) !void {
|
||||
const b = step.owner;
|
||||
const self = @fieldParentPtr(FailStep, "step", step);
|
||||
const self: *FailStep = @alignCast(@fieldParentPtr("step", step));
|
||||
|
||||
try step.result_error_msgs.append(b.allocator, self.error_msg);
|
||||
return error.MakeFailed;
|
||||
|
@ -370,7 +370,7 @@ const HealStep = struct {
|
|||
|
||||
fn make(step: *Step, _: *std.Progress.Node) !void {
|
||||
const b = step.owner;
|
||||
const self = @fieldParentPtr(HealStep, "step", step);
|
||||
const self: *HealStep = @alignCast(@fieldParentPtr("step", step));
|
||||
|
||||
return heal(b.allocator, self.exercises, self.work_path);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue