467 Commits

Author SHA1 Message Date
Chris Boesch
b7ff71cb9e Merge pull request 'Fix exercises 65, 71, 82 due to the build system update' (#443) from mark2185/exercises:fix-build-update into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/443
2026-06-03 18:37:25 +02:00
Chris Boesch
a403436fe8 Merge branch 'main' into fix-build-update 2026-06-03 17:39:58 +02:00
Chris Boesch
beeca8d510 Merge pull request 'Elrond has moved to Rivendell (where he lives)' (#447) from rivendell into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/447
2026-06-02 20:26:16 +02:00
Chris Boesch
01ad296114 Elrond has moved to Rivendell (where he lives) 2026-06-02 20:17:48 +02:00
Chris Boesch
9b87962595 Merge pull request 'fixed patch file path' (#446) from contribute-fix into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/446
2026-06-02 20:05:42 +02:00
Chris Boesch
9d6ef1f5ba fixed patch file path 2026-06-02 20:03:18 +02:00
Chris Boesch
fadd2ea4c7 Merge pull request 'fixed minor issues' (#444) from elrond-fixes into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/444
2026-06-02 12:10:11 +02:00
Chris Boesch
e69a865ce3 fixed minor issues 2026-06-02 11:56:34 +02:00
Chris Boesch
f6dda8181a Merge pull request 'Add another defer exercise' (#438) from mark2185/exercises:defer3 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/438
2026-06-02 08:56:50 +02:00
Luka Markušić
bd55c4ac5a fixup! Add another defer exercise 2026-06-02 06:12:06 +02:00
Luka Markušić
e61bedaa25 Add another defer exercise 2026-06-01 22:32:11 +02:00
Chris Boesch
ac9f96459c Merge pull request 'fix removed array multiplication' (#436) from mark2185/exercises:array_mult into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/436
2026-06-01 20:50:08 +02:00
Luka Markušić
014560c3f5 fix removed array multiplication 2026-06-01 16:05:36 +02:00
Luka Markušić
3b865a0c17 Fix 082_anonymous_structs3.zig because of new build system 2026-06-01 16:00:27 +02:00
Luka Markušić
63c798637c Fix 071_comptime6.zig because of new build system 2026-06-01 15:37:05 +02:00
Luka Markušić
4480762e83 Fix 065_builtins2.zig because of new build system 2026-06-01 15:34:01 +02:00
Chris Boesch
4ce3ed23f3 Merge pull request 'updated version in history' (#439) from build-system-fix into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/439
2026-06-01 00:23:49 +02:00
Chris Boesch
8db82ef84e updated version in history 2026-06-01 00:22:32 +02:00
Chris Boesch
6d23c876d6 Merge pull request 'started fix for new build system' (#437) from build-system-fix into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/437
2026-06-01 00:20:31 +02:00
Chris Boesch
fa36a4520f removed ziglings logic from build file 2026-05-31 23:54:20 +02:00
Chris Boesch
7889d15b84 moved ziglings logic to elrond 2026-05-31 23:48:17 +02:00
Chris Boesch
8a0077e83b Merge pull request 'fix typos' (#435) from mark2185/exercises:main into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/435
2026-05-31 21:12:39 +02:00
Chris Boesch
762d8b8fa5 started fix for new build system 2026-05-31 20:00:50 +02:00
Luka Markušić
7300e87028 fix contributing instructions for patches 2026-05-31 19:10:30 +02:00
Luka Markušić
1c3238d619 fix typos 2026-05-31 19:10:30 +02:00
Chris Boesch
000e9448d5 Merge pull request '051: add a comma' (#429) from xiaolizhi/exercises:comma-fix into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/429
2026-05-25 12:49:37 +02:00
xiaolizhi
f434dbfc01 051: add a comma 2026-05-25 10:37:05 +02:00
Chris Boesch
8468040a8e Merge pull request 'added expalantion for const pointer' (#428) from pointer into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/428
2026-05-22 22:27:15 +02:00
Chris Boesch
1d965491c1 added expalantion for const pointer 2026-05-22 21:58:19 +02:00
Chris Boesch
926fc04d81 Merge pull request 'Instruct user not to worry about sentinel syntax in 065_builtins2' (#425) from nickgrim/exercises:sentinel_warning into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/425
2026-05-18 19:50:18 +02:00
Chris Boesch
6b8bbfd980 Merge pull request 'Minor grammar fix to comment in 005_arrays2' (#426) from nickgrim/exercises:main into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/426
2026-05-18 19:49:52 +02:00
Nick Grimshaw
e96ce4da8e Minor grammar fix to comment in 005_arrays2 2026-05-18 17:38:04 +01:00
Nick Grimshaw
42a417f9a5 Instruct user not to worry about sentinel syntax in 065_builtins2 2026-05-18 17:29:17 +01:00
Chris Boesch
dde51b3126 Merge pull request 'fixed removed array multiplication' (#423) from array_mult into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/423
2026-05-04 17:30:31 +02:00
Chris Boesch
8af3372cf2 fixed removed array multiplication 2026-05-04 17:15:30 +02:00
Chris Boesch
1ba1e301a8 Merge pull request 'adjusted comment to zig 0.16' (#422) from i421 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/422
2026-05-02 23:08:18 +02:00
Chris Boesch
1c897e1951 adjusted comment to zig 0.16 2026-05-02 19:25:52 +02:00
Chris Boesch
6048e6ef21 Merge pull request 'fixed compileError printing' (#419) from i418 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/419
2026-04-30 19:53:56 +02:00
Chris Boesch
3a782a96d5 fixed compileError printing 2026-04-30 19:30:27 +02:00
Chris Boesch
4bdcf195b9 Merge pull request 'docs: update wrong comment reference to prior exercise in 110_files2' (#416) from kwyse/exercises:fix-110_files2 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/416
2026-04-23 10:20:48 +02:00
kwyse
656d6824d9 docs: update wrong reference to prior exercise
The comment should reference exercise 109, not 106.
2026-04-22 22:49:10 +02:00
Chris Boesch
0d9652d867 Merge pull request 'fix: move exercise 100 celebration comment to the right file' (#413) from Frost-Phoenix/exercises:fix_comment into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/413
2026-04-21 22:25:41 +02:00
Chris Boesch
945d9b84b0 Merge branch 'main' into fix_comment 2026-04-21 22:13:57 +02:00
Chris Boesch
c7afea6ef5 Merge pull request 'added skip to the C exercises' (#414) from fixing_cimport into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/414
2026-04-20 20:20:14 +02:00
Chris Boesch
6c2531b824 added skip to the C exercises 2026-04-20 19:38:31 +02:00
Chris Boesch
42db1f05a7 Merge pull request 'docs: fix wrong prerequisite in 110_files2.zig' (#412) from Kercy/exercises:main into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/412
2026-04-20 19:28:22 +02:00
Frost-Phoenix
333ca33e78 fix: move exercise 100 celebration comment to the right file 2026-04-20 17:40:49 +02:00
KercyDing
5eb9a30abe docs: fix wrong prerequisite in 110_files2.zig 2026-04-20 04:22:21 +08:00
Chris Boesch
0603b66cc7 Merge pull request 'fixed readme' (#411) from readme into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/411
2026-04-19 21:29:03 +02:00
Chris Boesch
a79e923768 fixed readme 2026-04-19 21:26:05 +02:00
Chris Boesch
234e829b15 Merge pull request 'fixed readme' (#409) from readme into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/409
2026-04-19 15:01:03 +02:00
Chris Boesch
823b4987f7 fixed readme 2026-04-19 14:49:29 +02:00
Chris Boesch
ca8aee84ad Merge pull request 'Demonstrate the benefit of a mutex' (#408) from MatthijsBlom/ziglings:matthijsblom-patch-1 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/408
2026-04-19 14:21:24 +02:00
MatthijsBlom
c4cb76ea8e Update patches/patches/091_async7.patch 2026-04-18 23:50:13 +02:00
MatthijsBlom
e0470c4f45 demonstrate the benefit of the mutex 2026-04-18 23:46:59 +02:00
Chris Boesch
f35c9419d2 Merge pull request 'fix: mutex unlock call in async example' (#407) from gabelluardo/ziglings:fix-async91 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/407
2026-04-18 21:50:49 +02:00
Gabriele Belluardo
656e1ba1e7 fix: mutex unlock call in async example 2026-04-18 11:55:49 +02:00
Chris Boesch
8e2cbf7b5a Merge pull request 'Some deprecated functions removed and a progress bar added.' (#403) from fixes_v016 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/403
2026-04-15 18:39:30 +02:00
Chris Boesch
d918dbae59 Some deprecated functions removed and a progress bar added. 2026-04-15 18:21:21 +02:00
Chris Boesch
4746ccc1c8 v0.16 2026-04-15 14:33:47 +02:00
Chris Boesch
c6f18ba448 Merge pull request '102: Fix formatting reference link' (#402) from tjk/ziglings-exercises:102-link into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/402
2026-04-15 11:44:57 +02:00
Tom
cb0489904e Fix formatting reference link 2026-04-14 21:36:06 -07:00
Chris Boesch
d4a3bad19c fixed merge conflict 2026-04-14 22:23:33 +02:00
Chris Boesch
e412619d88 added cancelation if nothing found 2026-04-14 22:07:57 +02:00
Chris Boesch
3f11ad1253 Merge pull request '093_async9: small fixes' (#400) from tjk/ziglings-exercises:93-async9 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/400
2026-04-14 17:56:35 +02:00
Tom
2afd0f9709 093_async9: small fixes 2026-04-14 08:32:50 -07:00
Chris Boesch
a4efd69e11 Merge pull request '095_quiz_async: Add missing Bug 4' (#396) from tjk/ziglings-exercises:95-bug4 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/396
2026-04-14 12:53:03 +02:00
Chris Boesch
f10c3d4e7a Merge branch 'main' into 95-bug4 2026-04-14 12:43:29 +02:00
Chris Boesch
152f3a6113 Merge pull request 'new example for concurrency' (#398) from improving_ansync9 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/398
2026-04-14 11:41:15 +02:00
Chris Boesch
ab3c498226 new example for concurrency 2026-04-14 11:07:13 +02:00
Chris Boesch
8c08482452 Merge pull request 'added result for 12 digits' (#397) from pi_precision into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/397
2026-04-14 08:22:30 +02:00
Chris Boesch
5eadcdc9f9 added result for 12 digits 2026-04-14 08:17:16 +02:00
Tom
b8a639e798 095_quiz_async: Add missing Bug 4 2026-04-13 19:11:39 -07:00
Chris Boesch
b9cbe199ab Merge pull request 'typo' (#394) from typo_async9 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/394
2026-04-13 18:36:22 +02:00
Chris Boesch
e71175e4f8 typo 2026-04-13 18:06:01 +02:00
Chris Boesch
7fcfb60cc4 typo 2026-04-13 17:56:05 +02:00
Chris Boesch
34c3125411 Merge pull request 'AI hint added' (#392) from ai-slop into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/392
2026-04-12 19:13:44 +02:00
Chris Boesch
8fc1bfac38 AI hint added 2026-04-12 19:06:03 +02:00
Chris Boesch
8e055fcd18 Merge pull request 'Replace exercise 074_comptime9' (#391) from tjk/ziglings-exercises:comptime9 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/391
2026-04-12 17:28:37 +02:00
Tom
2472caa183 Replace exercise 074_comptime9
The exercise no longer needed any modifications to pass due to
advancements in Zig.  This new exercise attempts to teach about
@compileError, @compileLog, and some comptime debugging.  It tries to
help prepare users for the "super bonus challenge" in 075_quiz8.
2026-04-12 07:16:33 -07:00
Chris Boesch
b225538aed Merge pull request 'Changed exercise 60 to require change of format' (#384) from markuxcu/exercises:fix-060 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/384
2026-04-07 09:25:59 +02:00
Chris Boesch
7cb7a9948a Merge branch 'main' into fix-060 2026-04-07 09:18:37 +02:00
Chris Boesch
3574fd3ae0 Merge pull request 'Improvements for async-io' (#388) from async-improvements into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/388
2026-04-06 20:56:29 +02:00
Chris Boesch
882c6aa0ab improvements for async-io 2026-04-06 19:57:32 +02:00
Chris Boesch
55a4841b07 improvements for async-io 2026-04-06 19:38:19 +02:00
Chris Boesch
09bae6a70e improvements for async-io 2026-04-06 19:30:56 +02:00
Chris Boesch
aeeb18931d improvements for async-io 2026-04-06 18:50:57 +02:00
Chris Boesch
63e506586f improvements for async-io 2026-04-06 16:57:48 +02:00
Chris Boesch
446da3ce5a improvements for async-io 2026-04-06 12:22:41 +02:00
Chris Boesch
5e474ea5d1 improvements for async-io 2026-04-05 16:13:42 +02:00
Chris Boesch
2acf192775 improvements for async-io 2026-04-05 12:42:42 +02:00
Chris Boesch
58f8df66d5 improvements for async-io 2026-04-04 16:05:35 +02:00
Chris Boesch
966c1f83af Merge pull request 'fixed missing uppercase letter' (#387) from async2-fix into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/387
2026-04-03 21:36:33 +02:00
Chris Boesch
261c12d6a2 fixed missing uppercase letter 2026-04-03 21:30:49 +02:00
Chris Boesch
0206db8129 fixed missing uppercase letter 2026-04-03 21:27:55 +02:00
Chris Boesch
34bbe1347d Merge pull request 'removed unnecessary patches' (#385) from patches into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/385
2026-04-03 19:55:14 +02:00
Chris Boesch
366b597519 removed unnecessary patches 2026-04-03 19:47:02 +02:00
Chris Boesch
5307b2a338 Merge pull request 'revival of the async-io functions' (#383) from asyncIo into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/383
2026-04-03 19:32:53 +02:00
Chris Boesch
f6a6798c8b improved report design 2026-04-03 19:28:12 +02:00
Chris Boesch
7fae6e0607 improved timestamp comparison 2026-04-03 19:07:10 +02:00
Chris Boesch
1c6487c1e7 added async-io quiz 2026-04-03 18:11:00 +02:00
markuxcu
1166f3cfb6 exercise 60: changed patch file 2026-04-03 14:52:22 +02:00
markuxcu
52ba66c5e9 exercise 60: added new expected output 2026-04-03 14:48:34 +02:00
Chris Boesch
2500936153 new async exercise 2026-04-03 14:28:19 +02:00
markuxcu
9f314ce8e6 exercise 60: added hint on correct format 2026-04-03 14:25:44 +02:00
Chris Boesch
903c33cd0a new async exercise 2026-04-03 13:46:35 +02:00
Chris Boesch
e0259f43a7 Insert space for additional async exercises 2026-04-03 13:35:56 +02:00
Chris Boesch
ffde357f30 revival of the async-io functions, #90 2026-04-02 10:38:45 +02:00
Chris Boesch
3b22bfd898 revival of the async-io functions 2026-04-02 10:28:40 +02:00
Chris Boesch
e22748d488 revival of the async-io functions 2026-04-01 23:44:24 +02:00
Chris Boesch
fcfb0e80a0 revival of the async-io functions 2026-04-01 23:34:16 +02:00
Chris Boesch
db1fef8b86 revival of the async-io functions 2026-04-01 22:52:04 +02:00
Chris Boesch
6d89dcd2de revival of the async-io functions 2026-04-01 22:31:48 +02:00
Chris Boesch
77d3b684cb revival of the async-io functions 2026-04-01 22:28:37 +02:00
Chris Boesch
3056a2b544 Merge pull request 'fixed community link and improved the overview' (#382) from cummunity into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/382
2026-03-28 13:11:50 +01:00
Chris Boesch
149a2bea50 fixed community link and improved the overview 2026-03-28 12:56:49 +01:00
Chris Boesch
c5ad9ff6cf Merge pull request 'Switching the C exercises to LLVM' (#379) from sframe into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/379
2026-03-21 20:30:33 +01:00
Chris Boesch
8f7a629ffb switched to llvm for the c-exercixes 2026-03-21 20:14:31 +01:00
Chris Boesch
d3ec872dec Merge pull request 'readme updated' (#377) from readme into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/377
2026-03-20 19:30:58 +01:00
Chris Boesch
2cddd566bb readme updated 2026-03-20 19:29:50 +01:00
Chris Boesch
3409760a62 Merge pull request 'bump required Zig version' (#376) from MatthijsBlom/ziglings:main into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/376
2026-03-20 19:19:56 +01:00
Chris Boesch
9f6092aea6 Merge branch 'main' into main 2026-03-20 19:13:22 +01:00
Chris Boesch
95ad73013a Merge pull request 'Added field .skip_hint to show information on why a file has been' (#375) from cor-draconia/exercises:skip_hints into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/375
2026-03-20 19:08:46 +01:00
MatthijsBlom
04f4c1e32c bump required Zig version 2026-03-20 17:23:11 +01:00
inke
2b5a603c43 Added field .skip_hint to show information on why a file has been
skipped.
2026-03-18 13:55:35 +01:00
Chris Boesch
e6d93d731a Merge pull request 'Add exercises for packed structs/unions' (#374) from justusk/ziglings:packed into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/374
2026-03-13 18:18:50 +01:00
Justus Klausecker
16a794fbee 111/112: Add exercises for packed structs/unions
The first exercise introduces the `packed` keyword as an alternative for
bitwise operations. Its main goals are establishing a solid understanding
of field order and conveying the fact that packed containers are basically
integers.
It introduces the concept of container layouts and briefly explains the
default `auto` layout before introducing the `packed` layout (but doesn't
touch `extern` at all).
The exercise also presents a real-world use case for packed containers,
namely LZ4 frame descriptors.
Furthermore it covers equality comparisons between packed containers.

The second exercise talks about switch statements with packed containers
and goes into some more detail on packed unions.
2026-03-13 11:21:03 +01:00
Justus Klausecker
973ec41097 build.zig: replace deprecated GeneralPurposeAllocator alias with DebugAllocator 2026-03-13 09:50:58 +01:00
Chris Boesch
1de4e14096 Merge pull request 'update description of 050_no_value for clarity' (#373) from robertefry/ziglings_exercises:fix/050-clarity into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/373
2026-03-11 00:03:12 +01:00
Robert Fry
0385f5d017 fix: oops 2026-03-09 23:24:59 +00:00
Robert Fry
de3c99dddd update description of 050_no_value for clarity 2026-03-09 23:16:30 +00:00
Chris Boesch
1be6fcd7db Merge pull request 'improve grammar in 103_tokenization' (#365) from pebose/exercises:improve-grammar into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/365
2026-02-27 19:54:41 +01:00
Chris Boesch
d5fdfe708c Merge pull request 'emphasize that the end number of a for-loop range is exclusive' (#366) from pebose/exercises:emphasize-for-loop-range into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/366
2026-02-27 19:44:35 +01:00
Chris Boesch
88510735e1 Merge branch 'main' into emphasize-for-loop-range 2026-02-27 19:43:31 +01:00
Chris Boesch
07031c5daa Merge pull request 'add commas' (#364) from pebose/exercises:add-punctuations into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/364
2026-02-27 19:38:15 +01:00
Chris Boesch
1813c0ded8 Merge pull request 'replace deprecated mem.indexOf with mem.find' (#363) from pebose/exercises:indexof-to-find into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/363
2026-02-27 19:36:00 +01:00
Paul Ebose
8c119bebdc update output for exercise 095_for3 to include full range of numbers 2026-02-27 19:35:10 +01:00
Paul Ebose
dc71c2cd06 update patch file for 095_for3 2026-02-27 19:34:53 +01:00
Paul Ebose
7d03b8464d update patch file for 103_tokenization 2026-02-27 19:27:04 +01:00
Chris Boesch
908109df2d Merge pull request 'add hint that @field() works differently on types and values' (#367) from pebose/exercises:add-hint-to-exercise-82 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/367
2026-02-27 19:17:59 +01:00
Chris Boesch
c032550633 Merge pull request 'improve comment stating 'Zig 0.10.0' @typeName change' (#370) from pebose/exercises:improve-builtins2-comment-zig-0-10 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/370
2026-02-27 19:09:51 +01:00
Chris Boesch
a83a42528e Merge pull request 'fix zig build error when '.progress.txt' contains newline' (#368) from pebose/exercises:fix-zig-build-error into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/368
2026-02-27 19:05:06 +01:00
Chris Boesch
4500fba8b3 Merge branch 'main' into fix-zig-build-error 2026-02-27 18:56:08 +01:00
Paul Ebose
9db32388e3 update patch file 2026-02-27 13:11:03 +01:00
Paul Ebose
53f7e015cb update patch file 2026-02-27 13:09:54 +01:00
Chris Boesch
2e4c7a2310 Merge pull request 'improve comment on continue expression behavior' (#369) from pebose/exercises:improve-013-while3-comment into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/369
2026-02-27 12:49:58 +01:00
Chris Boesch
0785c71532 Merge pull request 'fix 068_comptime3 comment to 'std.Io.Writer.print'' (#371) from pebose/exercises:correct-comptime3-comment into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/371
2026-02-27 12:25:13 +01:00
Paul Ebose
178fd9cef3 fix zig build error when '.progress.txt' contains newline 2026-02-27 04:12:46 +01:00
Paul Ebose
93aa733d33 improve comment on continue expression behavior 2026-02-27 04:07:06 +01:00
Paul Ebose
686342375e improve comment stating 'Zig 0.10.0' @typeName change 2026-02-27 03:55:37 +01:00
Paul Ebose
46cf5e802c fix 068_comptime3 comment to 'std.Io.Writer.print' 2026-02-27 03:51:12 +01:00
Paul Ebose
2e981d408f add hint that @field() works differently on types and values 2026-02-27 03:48:11 +01:00
Paul Ebose
9fb6d21ce6 emphasize that the end number of a for-loop range is exclusive 2026-02-27 03:45:09 +01:00
Paul Ebose
9798e80deb improve grammar in 103_tokenization 2026-02-27 03:41:27 +01:00
Paul Ebose
4aeb7b83b9 add commas 2026-02-27 03:38:59 +01:00
Paul Ebose
8a2e40040b replace deprecated mem.indexOf with mem.find 2026-02-27 03:38:26 +01:00
Chris Boesch
3ecaa34271 Merge pull request 'use Io interface for enabling ansi escape codes' (#361) from sno2/exercises:main into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/361
2026-02-08 21:41:30 +01:00
Carter Snook
df3f2df50b use Io interface for enabling ansi escape codes 2026-02-08 18:53:27 -06:00
Chris Boesch
7d4162e388 Merge pull request 'changed to zig-dev version 2471' (#359) from i357 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/359
2026-02-04 11:44:04 +01:00
Chris Boesch
8840f201d5 changed to zig-dev version 2471 2026-02-04 10:37:03 +01:00
Chris Boesch
bfc57ca6bb Merge pull request 'fix: std.process.RunOptions fields changed (used in build.zig)' (#358) from tadakuso/ziglings:main into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/358
2026-02-04 10:28:34 +01:00
tadakuso
6fe9625899 fix: std.process.RunOptions fields changed (used in build.zig) 2026-02-04 08:16:11 +08:00
Chris Boesch
0ceb0df875 Merge pull request 'fix: 071 update TypeInfo field case to .int' (#356) from arthursolomiac/exercises:fix-071-typeinfo-case into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/356
2026-01-10 13:53:39 +01:00
Arthur Solomiac
3f9e390bcc fix: 071 update TypeInfo field case to .int 2026-01-10 10:50:37 +01:00
Chris Boesch
07583db582 Merge pull request 'I/O improvements' (#355) from io_improvements into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/355
2026-01-09 23:07:31 +01:00
Chris Boesch
1e552a1dd6 I/O improvements 2026-01-09 22:56:23 +01:00
Chris Boesch
6972af2178 Merge pull request 'fix: use new randomness api' (#354) from itsnoctural/exercises:main into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/354
2026-01-09 10:26:28 +01:00
itsnoctural
91f484ed47 bump required zig version 2026-01-09 00:37:33 +02:00
itsnoctural
551008ac19 fix: use new randomness api 2026-01-09 00:19:24 +02:00
Chris Boesch
335aaafcff Merge pull request 'Change link to documentation' (#351) from BartShoot/exercises:main into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/351
2026-01-08 13:34:03 +01:00
BartShoot
b98fb4d9fb Change link to documentation
It's pointing to pre-writergate documentation
2026-01-08 01:38:18 +01:00
Chris Boesch
9b18647fd2 Merge pull request 'adjust temp files' (#350) from i348 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/350
2026-01-07 20:05:10 +01:00
Chris Boesch
639a763044 adjust temp files 2026-01-07 19:57:43 +01:00
Chris Boesch
878bebb1d1 Merge pull request 'docs: add zig 0.16.0-dev.1976 version change' (#347) from doprz/exercises:docs/zig-version-change into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/347
2026-01-07 16:21:30 +01:00
Chris Boesch
d10c31672a Merge branch 'main' into docs/zig-version-change 2026-01-07 16:20:42 +01:00
Chris Boesch
bf4bea929f Merge pull request 'entered current version number' (#349) from i348 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/349
2026-01-07 16:20:02 +01:00
Chris Boesch
05b324d697 entered current version number 2026-01-07 15:39:08 +01:00
doprz
8f0771d7bf docs: add zig 0.16.0-dev.1976 version change 2026-01-06 11:13:19 -06:00
Chris Boesch
d776e07af2 Merge pull request 'fix build errors in new Zig compiler' (#344) from prasefia/ziglings:main into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/344
2026-01-06 14:26:14 +01:00
prasefia
a04f945d36 fix build errors in new Zig compiler 2026-01-06 02:55:10 +03:00
Chris Boesch
6212297335 Merge pull request 'minor typos' (#343) from typos into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/343
2026-01-04 14:35:07 +01:00
Chris Boesch
f87097ae54 minor typos 2026-01-04 14:17:27 +01:00
Chris Boesch
8791b9440a Merge pull request 'change io explanation' (#341) from std.Io into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/341
2025-12-30 13:52:40 +01:00
Chris Boesch
af2a30e6da change io explanation 2025-12-30 13:40:24 +01:00
Chris Boesch
4927ef6a26 Merge pull request 'Integrate file system I/O with the std.Io interface' (#339) from std_Io into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/339
2025-12-29 12:46:28 +01:00
Chris Boesch
e8f81ddb96 finish new i/o 2025-12-29 12:42:35 +01:00
Chris Boesch
b332dc879e build revised 2025-12-28 21:39:32 +01:00
Chris Boesch
5685c94194 tests revised 2025-12-28 21:28:26 +01:00
Chris Boesch
3a645ac9db exc. 107 migrated 2025-12-28 21:19:31 +01:00
Chris Boesch
4340642f3c exc. 106 migrated 2025-12-28 20:40:31 +01:00
Chris Boesch
8f9daa12b2 exc. 34 migrated 2025-12-28 14:46:23 +01:00
Chris Boesch
8e30debc6a improved i/o explanation for exc. 26 2025-12-28 02:01:19 +01:00
Chris Boesch
b33fd5a744 exc. 26 migrated 2025-12-28 01:55:06 +01:00
Chris Boesch
21f86f07ad migrated build and test 2025-12-27 23:44:12 +01:00
Chris Boesch
a5febf58c9 Merge pull request 'added dark ziglings image' (#338) from new_image into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/338
2025-12-24 14:00:12 +01:00
Chris Boesch
209ef19596 added dark ziglings image 2025-12-24 13:59:19 +01:00
Chris Boesch
80eb7054eb Merge pull request '099: Update URL to, and function name of, fmt string documentation/comment' (#337) from gregorh/fmtstring-documentation:main into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/337
2025-12-24 12:03:04 +01:00
gregorh
1c552813d9 Formatting 2025-12-24 01:10:39 +01:00
Gregor Hartmann
acf8c483ef change back to original 'format()' sentence 2025-12-24 01:08:19 +01:00
gregorh
8cbce258a6 Update to correct line number
Line 537 is the actual start of the documenting comment.
2025-12-19 17:56:02 +01:00
Gregor Hartmann
0010cb2a68 Update URL to, and function name of, fmt string documentation/comment 2025-12-19 15:46:02 +01:00
Chris Boesch
bb4e984a8e Merge pull request 'Update zig homepage example in 103' (#336) from nkhl/exercises:103-update-homepage-example into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/336
2025-12-15 15:04:38 +01:00
Nikhil
82d5dda273 Update zig homepage example in 103 2025-12-14 18:12:51 -08:00
Chris Boesch
2ffc3ee1d8 Merge pull request 'Update to new Zig mem trim API' (#335) from dpflug/ziglings_exercises:main into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/335
2025-12-14 13:52:52 +01:00
David Pflug
7d1184a140 Update to new Zig mem trim API
trimRight is now trimEnd
2025-12-13 12:01:10 -05:00
Chris Boesch
e767de2337 Merge pull request 'restrict parameter type in 'maximumNarcissism' in exercise 65' (#332) from Castanearie/ziglings:main into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/332
2025-12-08 20:15:55 +01:00
Castanearie
0c9d5abccd restrict parameter type in 'maximumNarcissism' 2025-12-07 23:15:42 +01:00
Chris Boesch
739d5ccce8 Merge pull request 'Added art description' (#331) from i330 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/331
2025-12-07 23:01:49 +01:00
Chris Boesch
274a49aa53 Added art description 2025-12-07 22:53:34 +01:00
Chris Boesch
9302d10282 Merge pull request 'changed 1 to 42 for better understanding' (#329) from i326 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/329
2025-11-28 15:15:49 +01:00
Chris Boesch
757826d45a changed 1 to 42 for better understanding 2025-11-28 14:42:58 +01:00
Chris Boesch
ed9694e557 Merge pull request 'changed 'sleep' to async I/O' (#328) from i323 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/328
2025-11-28 14:31:30 +01:00
Chris Boesch
dc416b6c5a changed 'sleep' to async I/O 2025-11-28 14:22:51 +01:00
Chris Boesch
39e346303c Merge branch 'psd-fix' 2025-11-15 19:23:27 +01:00
Chris Boesch
11d8172136 forgotten thread-sleep fix added 2025-11-15 19:14:36 +01:00
Chris Boesch
189376944c fixed path for freeBSD 2025-11-15 17:58:27 +01:00
Chris Boesch
56b220e98d Merge pull request 'pause slightly extended for faster computers' (#317) from new_io_2 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/317
2025-11-01 16:02:14 +01:00
Chris Boesch
850700e68e pause slightly extended for faster computers 2025-11-01 15:59:07 +01:00
Chris Boesch
6c8f4ef507 pause slightly extended for faster computers 2025-11-01 15:57:29 +01:00
Chris Boesch
4c291f35d5 Merge pull request 'fixed more changes due to new I/O API' (#316) from new_io_2 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/316
2025-11-01 15:52:40 +01:00
Chris Boesch
147ff302ec fixed more changes due to new I/O API 2025-11-01 15:46:31 +01:00
Chris Boesch
c45b9cd383 Merge pull request 'Update for new zig IO' (#315) from esensar/exercises:fix/zig-0.16-new-io into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/315
2025-11-01 15:33:46 +01:00
Ensar Sarajčić
26fc4fdaaa Update for new zig IO
`test/tests.zig` fails after https://github.com/ziglang/zig/pull/25592 was
merged in. This just ensures that Io is passed, it might not be the
ideal solution.
`build.zig` was also failing due to new color parameter.
2025-11-01 10:34:18 +01:00
Chris Boesch
7ad02b084f Merge pull request 'Wrap comment at 80 chars in 102' (#314) from whlr/ziglings-exercises:rewrap-102 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/314
2025-10-25 00:02:26 +02:00
Adam Wheeler
a5622fd5a8 update patch for 102 to match 2025-10-24 12:58:11 -04:00
Adam Wheeler
87358c610b Wrap comment at 80 chars in 102.
Some of the inline comments in 102 are wrapped into very short lines. This
rewraps the shortest ones for readability.
2025-10-24 11:54:25 -04:00
Chris Boesch
b72bcd7e47 Merge pull request 'Fixed description to decimal and scientific notation' (#312) from i311 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/312
2025-10-17 18:08:59 +02:00
Chris Boesch
837e6aba3b Fixed description to decimal and scientific notation 2025-10-17 17:59:57 +02:00
Chris Boesch
b25f9bb66e Merge pull request 'Fixed conversion from kg to tons' (#310) from i309 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/310
2025-10-03 13:37:39 +02:00
Chris Boesch
c7e59864ca Fixed conversion from kg to tons 2025-10-03 13:30:14 +02:00
chrboesch
c9218fbb22 Delete .woodpecker/healthcheck.yaml
needs a token :-(
2025-09-25 14:04:38 +02:00
chrboesch
0e27b4de2f Add .woodpecker/healthcheck.yaml 2025-09-25 09:41:04 +02:00
Chris Boesch
9a848f46b7 Merge pull request 'Fixed error in captureStdErr()' (#308) from i306 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/308
2025-09-24 23:25:23 +02:00
chrboesch
f1921e64d8 Update .woodpecker/eowyn.yaml
try with branch 'main'
2025-09-24 23:21:59 +02:00
chrboesch
b27a6a4d1f Update .woodpecker/eowyn.yaml
separate steps
2025-09-24 23:18:49 +02:00
chrboesch
e4a7db17b3 Update .woodpecker/eowyn.yaml
fix refs
2025-09-24 23:16:55 +02:00
chrboesch
f281c36f79 Update .woodpecker/eowyn.yaml
push only on main
2025-09-24 23:14:04 +02:00
Chris Boesch
4346d5f1d8 Fixed error in captureStdErr() 2025-09-24 20:30:54 +02:00
Chris Boesch
62ad50b71e Merge pull request 'Switched to new reader' (#305) from i304 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/305
2025-09-03 10:57:17 +02:00
Chris Boesch
ed93882b19 Switched to new reader 2025-09-03 10:45:19 +02:00
Chris Boesch
a4c1774847 Merge pull request 'formating contributing' (#301) from contributing into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/301
2025-08-25 21:50:29 +02:00
Chris Boesch
e12ee5cb9e formating contributing 2025-08-25 21:46:25 +02:00
Chris Boesch
0dbe83b20e Merge pull request 'fixes some minor typos' (#300) from i122 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/300
2025-08-24 19:30:51 +02:00
Chris Boesch
e422e24215 fixes some minor typos 2025-08-24 19:26:30 +02:00
Chris Boesch
4134d4fa6f Merge pull request 'Formatting' (#299) from gollum into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/299
2025-08-24 17:55:46 +02:00
Chris Boesch
ad361c4b18 Formatting 2025-08-24 17:55:03 +02:00
Chris Boesch
d4215ce5c6 Merge pull request 'Added instructions for patch files' (#298) from gollum into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/298
2025-08-24 16:31:54 +02:00
Chris Boesch
fd9e9aa36e Added instructions for patch files 2025-08-24 16:31:22 +02:00
Chris Boesch
b3178e81a8 Merge pull request 'Added instructions for patch files' (#297) from gollum into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/297
2025-08-24 16:27:03 +02:00
Chris Boesch
c36fe8007d Added instructions for patch files 2025-08-24 16:23:51 +02:00
Chris Boesch
7488727625 Merge pull request 'testing exercise, fix order of parameters to expectEqual' (#281) from cstyan/exercises:test-expect into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/281
2025-08-24 15:08:32 +02:00
Chris Boesch
a46db7e0e8 Merge branch 'main' into test-expect 2025-08-24 14:59:26 +02:00
Chris Boesch
564ea3405d Merge pull request 'fixed typo and broken link' (#296) from readme into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/296
2025-08-24 14:54:05 +02:00
Chris Boesch
16ec207471 fixed typo and broken link 2025-08-24 14:50:42 +02:00
Chris Boesch
04857aa75e Merge pull request 'fixed version numbers' (#295) from readme into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/295
2025-08-24 14:44:25 +02:00
Chris Boesch
6364087569 fixed version numbers 2025-08-24 14:42:03 +02:00
Chris Boesch
ad32e402a5 Merge pull request 'pass -freference-trace to executed compile command' (#294) from SimonLSchlee/exercises:pass-reference-trace into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/294
2025-08-24 14:37:57 +02:00
Chris Boesch
470f695968 Merge branch 'main' into pass-reference-trace 2025-08-24 13:48:18 +02:00
Chris Boesch
5b3b0eb26b Merge pull request '[Exercise 019] fix: typo in example function, missing return type' (#290) from imomaliev/ziglings:chore/fix-019-function-description into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/290
2025-08-24 13:40:04 +02:00
Chris Boesch
0661d4fd48 Merge branch 'main' into chore/fix-019-function-description 2025-08-24 13:19:25 +02:00
Simon 'Sze' L. Schlee
02db832677 pass -freference-trace to executed compile command
Currently users executing `zig build` to run the exercises,
may encounter compiler output that tells them to use
`-freference-trace=[num]` to see more of the hidden
reference traces, so we should pass this parameter to
the zigling exercise being compiled, so that the learner
can provide this parameter like they would normally, when
using `zig build` directly in normal Zig programs.
2025-08-24 03:08:17 +02:00
Chris Boesch
1407c7fb91 Merge pull request 'fixed typo in readme' (#293) from readme into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/293
2025-08-15 15:13:53 +02:00
Chris Boesch
1ca8b90589 fixed typo in readme 2025-08-15 15:10:47 +02:00
Chris Boesch
4bc9db1079 Merge pull request 'Fixed changes in array list' (#292) from i291 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/292
2025-08-15 15:06:54 +02:00
Chris Boesch
b580f7e30e adjusted version information 2025-08-15 15:03:10 +02:00
Chris Boesch
aeacadb76b Fixed changes in array list 2025-08-15 15:00:53 +02:00
Sardorbek Imomaliev
06e56be9c5 fix: 019 typo in example function, missing return type 2025-08-11 21:01:47 +01:00
Chris Boesch
82d8f06ffa Merge pull request 'Fixed zig version' (#289) from readme into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/289
2025-08-11 09:56:54 +02:00
Chris Boesch
80528613c2 Fixed zig version 2025-08-11 09:52:58 +02:00
Chris Boesch
8284ff2a4c Merge pull request 'Current version set' (#287) from i285 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/287
2025-08-08 20:40:05 +02:00
Chris Boesch
fd310273a7 Current version set 2025-08-08 20:34:59 +02:00
Chris Boesch
711cb70c5a Merge pull request 'Fix: The initial zig build fail due to wrong number of arguments passed in self.step.evalZigProcess()' (#286) from DoKoB/exercises:fix/initial-zig-build into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/286
2025-08-08 20:21:11 +02:00
DoKoB
9bff77a12a fix: initial zig build caused by self.step.evalZigProcess() 2025-08-05 08:11:36 +05:30
Chris Boesch
1f6ce9a268 Merge pull request 'Fix zig 0.15.0-dev.1149+4e6a04929 build errors' (#283) from zawupf/ziglings-exercises:zig-0.15 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/283
2025-07-22 10:52:04 +02:00
Chris Boesch
4044b93dd2 Added Readme 2025-07-22 10:45:09 +02:00
Chris Boesch
f461986896 Fixed 104 2025-07-22 10:30:19 +02:00
Chris Boesch
0d06220ec5 Fixed 98 2025-07-22 10:24:22 +02:00
Chris Boesch
54f48c75c4 Fixed 82 2025-07-22 10:16:17 +02:00
Chris Boesch
ed2f76e960 Added patch files. 2025-07-22 10:08:24 +02:00
Arnold Filip
f21f8f7863 Update stdout writer usage to use std.fs.File 2025-07-22 09:17:24 +02:00
Chris Boesch
b499788606 Corrected the necessary Zig version 2025-07-22 00:40:06 +02:00
Chris Boesch
49e73db5f5 Switched to new reader version 2025-07-22 00:28:03 +02:00
Chris Boesch
4bad15a95b Merge branch 'main' into zig-0.15 2025-07-21 21:14:15 +02:00
Chris Boesch
b9a372bde8 Merge pull request 'Removed patch files for async because of new formating errors.' (#284) from fix_format into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/284
2025-07-21 21:11:12 +02:00
Chris Boesch
cb0a1a027f Removed patch files for async because of new formating errors. 2025-07-21 21:05:45 +02:00
Arnold Filip
9ae739c4c9 Fix zig 0.15.0-dev.1149+4e6a04929 build errors 2025-07-21 15:04:57 +02:00
Callum Styan
f5d2c5124c for expectEqual the first param is expected
Signed-off-by: Callum Styan <callumstyan@gmail.com>
2025-07-13 17:02:50 -07:00
Chris Boesch
34a7c6c861 Merge pull request 'Fixes the changes in zig's struct.fields' (#279) from i278 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/279
2025-06-17 15:03:32 +02:00
Chris Boesch
bc96d06da4 Merge branch 'main' into i278 2025-06-17 14:10:16 +02:00
Chris Boesch
451e1a3739 Fixes the changes in zig's struct.fields 2025-06-17 14:07:31 +02:00
Chris Boesch
afaab2efca Merge pull request 'Stable release in README corrected.' (#277) from readme into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/277
2025-06-12 09:22:16 +02:00
Chris Boesch
e431cbb0cf Stable release in README corrected. 2025-06-12 09:20:33 +02:00
Chris Boesch
d1ffdd16e8 Merge pull request '080: Fix @typeName results in comment' (#271) from felixrabe/exercises:felixrabe-patch-4 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/271
2025-06-11 15:27:48 +02:00
Chris Boesch
37698736ce Merge pull request '099: Make hex example match output' (#274) from felixrabe/exercises:felixrabe-patch-5 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/274
2025-06-11 15:12:01 +02:00
Chris Boesch
cabbef97e8 Merge pull request '108: Make pretty' (#275) from felixrabe/exercises:felixrabe-patch-6 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/275
2025-06-03 23:11:57 +02:00
felixrabe
b1223f92ed 108: . 2025-06-01 01:08:07 +02:00
felixrabe
91f1c045bc 108: Make pretty 2025-06-01 01:05:37 +02:00
felixrabe
69ad718446 099: Make hex example match output 2025-05-31 23:15:55 +02:00
felixrabe
14c81a6cef 080: Fix @typeName results in comment 2025-05-30 21:54:25 +02:00
Chris Boesch
fd764e90ab Merge pull request 'Add ')'' (#268) from felixrabe/exercises:felixrabe-patch-1 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/268
2025-05-30 14:27:08 +02:00
felixrabe
76b8fcdb28 Add ')' 2025-05-30 12:12:26 +02:00
Chris Boesch
54b2b58b6a Merge pull request 'Exercise 097 - Changed the values for better understanding' (#251) from i210 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/251
2025-05-12 19:51:58 +00:00
Chris Boesch
761fb1a501 Changed the values for better understanding 2025-05-12 21:36:37 +02:00
chrboesch
377d184cdc new issue template 2025-04-14 17:05:40 +00:00
Chris Boesch
d7052e4137 Merge pull request 'fix: typos' (#222) from ddogfoodd/exercises:main into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/222
2025-03-22 10:47:00 +00:00
Jost Alemann
522b4673a4 fix: typos 2025-03-20 21:24:40 +01:00
Chris Boesch
7ce659f7fa Merge pull request 'Rectify 106 and 107 patches' (#219) from dustdfg/exercises:patch_rectify into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/219
2025-03-14 21:15:20 +00:00
Chris Boesch
02edb1f5c6 Merge branch 'main' into patch_rectify 2025-03-14 21:04:11 +00:00
Chris Boesch
5734e68789 Merge pull request 'Update type info for StructField type in 082' (#218) from dustdfg/exercises:update_struct_field into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/218
2025-03-14 20:49:25 +00:00
Yevhen Babiichuk (DustDFG)
1a9b7ec342 Rectify 106 and 107 patches
Signed-off-by: Yevhen Babiichuk (DustDFG) <dfgdust@gmail.com>
2025-03-14 22:26:20 +02:00
Yevhen Babiichuk (DustDFG)
6f3cdcf018 Update type info for StructField type in 082
Signed-off-by: Yevhen Babiichuk (DustDFG) <dfgdust@gmail.com>
2025-03-14 16:47:27 +02:00
Chris Boesch
eeb1246c2c Merge pull request 'Updated version number' (#215) from readme into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/215
2025-03-10 10:54:22 +00:00
Chris Boesch
e0ecff7045 Updated version number 2025-03-10 10:02:07 +01:00
Chris Boesch
ce64fe5a1a Merge pull request 'Shuttle weight fixed w.r.t. issue-211' (#212) from mz0/ziglings:shuttle-weight into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/212
2025-03-03 21:45:34 +00:00
mz0
a22f1df0a1 Shuttle weight fixed w.r.t. issue-211 2025-03-03 20:32:41 +04:00
Chris Boesch
2a9ef2d2c8 Merge pull request 'Shuttle weight fixed' (#208) from e60 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/208
2025-02-14 08:29:31 +00:00
Chris Boesch
f285bd59a4 Output from #60 adapted 2025-02-14 09:22:36 +01:00
Chris Boesch
7382949018 Shuttle weight fixed 2025-02-14 09:17:16 +01:00
Chris Boesch
0e0cafb71e Merge pull request 'Suggesting a third exercise for bit manipulation' (#202) from alexsisco/zigling-exercises:bit_man3 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/202
2025-02-13 22:27:29 +00:00
Chris Boesch
064184c8a7 Merge branch 'main' into bit_man3 2025-02-13 22:22:55 +00:00
Alexander Sisco
cd94f6023c fixed spelling of 'bitmask' 2025-02-13 13:14:29 -08:00
Alexander Sisco
90e90c997e fixed formatting 2025-02-13 12:45:46 -08:00
Alexander Sisco
8384d4d9bf fixed minor spelling and grammar typos 2025-02-12 12:59:29 -08:00
Alexander Sisco
2437edd51f fixed incorrect bitmask in xor example 2025-02-11 15:21:26 -08:00
Alexander Sisco
f7e8d4c444 added header for quiz problems 2025-02-11 15:13:25 -08:00
Alexander Sisco
b7b3297d06 added blank lines between sections to make them
easier to find
2025-02-11 15:11:55 -08:00
Alexander Sisco
6fbf81d929 edited the first two paragraphs 2025-02-11 15:07:51 -08:00
Alexander Sisco
465536baf0 made some simple changes to the wording to reflect
the fact that this is a quiz
2025-02-11 13:45:51 -08:00
Alexander Sisco
a7cd808bb8 moved explanatory content below the broken code in
main so that the exercise functions more like a quiz
2025-02-11 11:56:57 -08:00
Alexander Sisco
20596bc290 converted 110 to a quiz (quiz 9) 2025-02-10 21:33:15 -08:00
Chris Boesch
0af4f75e07 Merge pull request 'Fix repo link' (#207) from readme into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/207
2025-02-10 09:56:28 +00:00
Chris Boesch
d75f49b25b Fix repo link 2025-02-10 10:50:57 +01:00
Chris Boesch
838fb4ab9d Merge branch 'main' into bit_man3 2025-02-09 20:58:41 +00:00
Chris Boesch
c13a00fc71 Merge pull request 'Added deletion of progress.txt for eowyn' (#206) from eowyn_fix into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/206
2025-02-09 20:57:18 +00:00
Chris Boesch
c1777f47d5 Added delte_progress additional to the end of eowyn 2025-02-09 21:42:31 +01:00
Chris Boesch
c02e6ead16 Added deletion of progress.txt for eowyn 2025-02-09 21:31:07 +01:00
Chris Boesch
b3dd04885d Merge pull request 'issue201-adding-progress-tracking' (#203) from zendril/exercises:issue201-adding-progress-tracking into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/203
2025-02-09 20:16:55 +00:00
Chris Boesch
bfa0e624f1 Merge pull request 'Skip 74, the compiler corrects this now.' (#205) from i204 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/205
2025-02-09 15:54:11 +00:00
Chris Boesch
b38d70002a Skip 74, the compiler corrects this now. 2025-02-09 16:34:56 +01:00
Alexander Sisco
1478d41801 added patch file for exercise 110 2025-02-08 13:15:48 -08:00
Alexander Sisco
596d5e50ca format fix 2025-02-08 13:09:12 -08:00
Zendril
a9487c246f cleanup for PR 2025-02-04 22:24:52 -05:00
Zendril
e09c11a16a cleanup for PR 2025-02-04 21:29:56 -05:00
Zendril
92c7235362 cleanup for PR 2025-02-04 21:29:46 -05:00
Zendril
0903c5927b cleanup for PR 2025-02-04 21:14:41 -05:00
Zendril
8e6a52d5a6 tracking, skipping and reset all wired in 2025-02-04 21:13:33 -05:00
Zendril
e54b30f3d3 fmt 2025-02-04 15:37:01 -05:00
Zendril
4ac1d70f93 reset and completed exercise tracking wired in 2025-02-04 15:35:14 -05:00
Alexander Sisco
502ac8711e added newline between toggle and set sections to
make the expected output match
2025-02-04 09:31:29 -08:00
Alexander Sisco
0fa86eb8c8 rearranged order of expected output in build.zig 2025-02-04 09:06:23 -08:00
Alexander Sisco
657fd6aff0 changed the order of the sections to improve flow 2025-02-04 08:57:23 -08:00
Alexander Sisco
3faad6e17b Suggesting a third exercise for bit manipulation 2025-02-03 23:24:34 -08:00
Chris Boesch
fabedb4a24 Merge pull request 'Use print alias in exercise 100_for4.zig' (#198) from Zorgatone/ziglings-solutions:use-print-alias into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/198
2025-01-09 15:27:12 +00:00
Chris Boesch
b1fcca9d82 Merge pull request 'Update: 108 Labeled switch example to contain default case for exhaustion' (#196) from mikkurogue/exercises:main into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/196
closes #195
2025-01-08 14:30:04 +00:00
Chris Boesch
a47dfe1f4d Merge branch 'main' into main 2025-01-08 13:26:15 +00:00
chrboesch
90d05995b5 Update exercises/108_labeled_switch.zig
Fixed an error in the debug statement and made the text a bit more coherent.

Signed-off-by: chrboesch <chrboesch@noreply.codeberg.org>
2025-01-08 13:22:29 +00:00
chrboesch
54f743ba43 Update exercises/108_labeled_switch.zig
The sentence was slightly unclear

Signed-off-by: chrboesch <chrboesch@noreply.codeberg.org>
2025-01-08 12:18:25 +00:00
mikkurogue
87b258d0a9 Fix a typo: we need do we need to -> we need to
Morning delirium does not help when looking at lots of words
2025-01-07 18:00:16 +00:00
Zorgatone
6b29634279 Fix patch after print alias fix in 100_fo4.zig 2025-01-07 15:26:04 +00:00
Zorgatone
c2dcaf3099 Use print alias in exercise 100_for4.zig 2025-01-07 15:21:36 +00:00
mikkurogue
5cdaee7420 Update: Remove the 4th branch in favour of just making that the else branch
Probably easier to not have an "unused" branch that returns the same as the else branch in the example.

Signed-off-by: mikkurogue <mikkurogue@noreply.codeberg.org>
2025-01-07 10:15:59 +00:00
Chris Boesch
468e3d7eed Merge pull request 'Fix typo vaild → valid' (#197) from zyzzyxdonta/ziglings-exercises:fix-typo-vaild-valid into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/197
2025-01-04 23:45:10 +00:00
David Pape
26978cb2d3 Fix typo vaild → valid 2025-01-04 21:40:19 +01:00
mikkurogue
de353bcb3b Update: 108 Labeled switch example to contain default case for exhaustion
Update example text to give clarity on default/exhaustive case.

Reasoning:
The input for the example will not compile if user would want to test this for the logic of a labeled switch. Due the input not being an exhaustive input but rather "any u8 integer" (for the lack of better terminology) we need to use the else branch to indicate that the default case is handled, in this case by just emulating the '4' branch, but this could return an error.InvalidCaseProvided for example.

Signed-off-by: mikkurogue <michael.lindemans@outlook.com>
2025-01-04 11:56:25 +00:00
Chris Boesch
5ed3af57ee Merge pull request 'Updated credits' (#192) from readme into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/192
2024-12-22 15:50:29 +00:00
Chris Boesch
105c98782c Updated credits 2024-12-22 15:59:21 +01:00
Chris Boesch
f446402105 Updated credits 2024-12-22 15:52:52 +01:00
Chris Boesch
8da60edb82 Merge pull request 'Minor case-related changes.' (#184) from innerviewer/exercises:fix-consistent-naming-106 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/184
2024-11-09 22:36:35 +00:00
innerviewer
83e00872b8 Added patch file. 2024-11-09 20:36:47 +01:00
innerviewer
02bd0b2022 Merge branch 'main' into fix-consistent-naming-106 2024-11-09 13:28:43 +00:00
Chris Boesch
63951df523 Merge pull request 'Deleted unnecessary pointer.' (#185) from fix-176 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/185
2024-11-08 22:02:07 +00:00
Chris Boesch
0d9458807e Deleted unnecessary pointer. 2024-11-08 22:48:37 +01:00
Chris Boesch
ae541a0d9c Merge pull request 'Added SIMD.' (#178) from readme into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/178
2024-11-08 21:34:21 +00:00
Chris Boesch
fb46871dab Merge branch 'main' into readme 2024-11-08 21:34:00 +00:00
Chris Boesch
2606e53733 Merge pull request 'Added missing space after a sentence.' (#182) from innerviewer/exercises:fix-typo-105 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/182
2024-11-08 21:32:45 +00:00
innerviewer
33d61cb3c9 Minor case-related changes. 2024-11-08 13:29:44 +01:00
innerviewer
e55f8e8699 Added missing space after a sentence. 2024-11-07 22:05:00 +01:00
Chris Boesch
4d4eefa523 Merge pull request 'Fixed link to format source code.' (#180) from fix-link-99 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/180
2024-11-07 20:51:59 +00:00
Chris Boesch
37a0f42621 Fixed link to format source code. 2024-11-07 21:45:47 +01:00
Chris Boesch
97c2ea2f49 Added SIMD. 2024-11-07 15:30:13 +01:00
Chris Boesch
731a3eb0a6 Merge pull request 'vectors-addition' (#177) from vectors-addition into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/177

Thank you @bgthompson for this great exercise!
2024-11-07 14:24:51 +00:00
Chris Boesch
bfed660020 Fixed formating, created patch file. 2024-11-07 15:01:59 +01:00
bgthompson
46e8fc0b61 line ending format patch attempt 2024-11-07 13:42:53 +10:00
bgthompson
8cce587d3b added patch file for 109_vectors 2024-11-07 13:31:32 +10:00
bgthompson
75e5e53497 removed commented solution lines in vectors exercise, added ??? into lines instead 2024-11-03 11:18:18 +10:00
bgthompson
c90d6015e3 created a new exercise about vectors in zig, gave it number 109 2024-11-03 11:16:00 +10:00
Chris Boesch
150b3de299 Merge pull request 'Improved maximumNarcissism' (#174) from pr173 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/174
2024-11-02 16:13:53 +00:00
Chris Boesch
fb018d212c Improved maximumNarcissism 2024-11-02 17:03:46 +01:00
Chris Boesch
d0d31ae73a Merge pull request 'reuse fields' (#173) from rofrol/ziglings--exercises:reuse-fields into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/173
2024-11-02 15:54:34 +00:00
Roman Frołow
530dcde3d4 patch 2024-11-02 14:38:53 +01:00
Roman Frołow
286439cddc zero 2024-11-02 14:37:41 +01:00
Roman Frołow
f629d78268 reuse fields 2024-11-02 10:48:50 +01:00
Chris Boesch
71b4f5ea81 Merge pull request 'Fixed patch from quiz7 after text changes' (#171) from quiz7 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/171
2024-10-28 19:41:59 +00:00
Chris Boesch
8f49400aa1 Fixed patch from quiz7 after text changes
#Please enter the commit message for your changes. Lines starting
2024-10-28 09:40:17 +01:00
Chris Boesch
e2b20b3406 Merge pull request 'Rephrase instruction for clarity' (#170) from factormystic/exercises:quiz-7-instruction-clarify into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/170
2024-10-27 15:03:25 +00:00
factormystic
02478759b4 Rephrase instruction for clarity 2024-10-26 20:43:47 +00:00
Chris Boesch
173af62d34 Merge pull request 'Deleted .devcontainer because ist was a test.' (#165) from rm_devcont into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/165
2024-09-20 17:15:58 +00:00
Chris Boesch
9d1da38d38 Deleted .devcontainer because ist was a test. 2024-09-20 18:48:30 +02:00
Chris Boesch
775f5ebd29 Merge pull request 'Added Dave as initiator of Ziglings.' (#164) from readme into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/164
2024-09-20 11:21:28 +00:00
Chris Boesch
96df8ba304 Added Dave as initiator of Ziglings. 2024-09-20 12:45:23 +02:00
Chris Boesch
67c824118e Merge pull request 'Minor improvements.' (#163) from patch_lbl_sw into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/163
2024-09-20 10:19:26 +00:00
Chris Boesch
d1b49f353e Minor improvements. 2024-09-20 12:10:55 +02:00
Chris Boesch
94b5b4bf4b Merge pull request 'Add a new exercise for a labeled switch' (#161) from nm-remarkable/exercises:main into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/161
2024-09-19 10:16:08 +00:00
Nuno Mendes
f0c2c56087 update108 .patch due to line change 2024-09-18 23:29:08 +02:00
Nuno Mendes
ed1a20d51b improve explanantions in labeled switch 2024-09-18 23:26:33 +02:00
Nuno Mendes
d9ce18631d downgrade zig version to eowyn version
It is just 2 days behind so all features are already present for the new labeled switch test
2024-09-16 18:44:36 +02:00
Nuno Mendes
db569a1478 update labeled switch to also have a break statement 2024-09-16 18:39:54 +02:00
Nuno Mendes
798bb40396 update zig version in build and readme 2024-09-16 18:34:35 +02:00
Nuno Mendes
580e126266 Add .patch for 108_labeled_switch 2024-09-15 20:16:57 +02:00
Nuno Mendes
335a78f8f5 108: Add a exercise for a labeled switch 2024-09-15 20:14:49 +02:00
Chris Boesch
102ba8c894 Merge pull request 'Update README.md' (#160) from chrboesch-readme into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/160
2024-09-11 19:13:46 +00:00
chrboesch
827146f680 Update README.md
Added new todo for core lang
2024-09-11 17:49:54 +00:00
Chris Boesch
995a7c8f36 Merge pull request 'New patch file for 82' (#158) from p_struct_typeinfo into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/158
2024-09-07 17:46:59 +00:00
Chris Boesch
f28346d009 New patch file for 82 2024-09-07 19:36:45 +02:00
Chris Boesch
3dc79ca9c3 Merge pull request 'Corrects the description of the new @typeInfo().@"struct".fields' (#157) from p_struct_typeinfo into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/157
2024-09-07 17:25:35 +00:00
Chris Boesch
26f4785a99 Corrects the description of the new @typeInfo().@"struct".fields 2024-09-07 19:21:57 +02:00
Chris Boesch
b9cde40610 Merge pull request 'Update LICENSE' (#155) from chrboesch-lic-patch-1 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/155
2024-09-07 12:53:26 +00:00
chrboesch
c8b60f2c30 Update LICENSE 2024-09-07 12:53:07 +00:00
Chris Boesch
c9a98ad555 Merge pull request 'Reseted the simplification for de-referencing.' (#154) from i152 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/154
2024-09-04 18:59:51 +00:00
Chris Boesch
49e0c32ec5 Merge branch 'main' into i152 2024-09-04 18:59:27 +00:00
Chris Boesch
7f1df86938 Reseted the simplification for de-referencing. 2024-09-04 20:52:42 +02:00
Chris Boesch
b0f859c62f Merge pull request 'fixed typo: the date in version changes' (#153) from Seeingu/exercises:main-typo into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/153
2024-09-04 18:29:15 +00:00
Seeingu
a6759458b0 fixed typo: the date in version changes 2024-09-04 10:09:21 +08:00
Chris Boesch
2e5b570aef Merge pull request 'Fixes several changes in std.builtin.zig' (#150) from i149 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/150
2024-09-02 17:57:42 +00:00
Chris Boesch
b2f56c7cea Fixes several changes in std.builtin.zig 2024-09-02 19:33:59 +02:00
Chris Boesch
296a2b5c6a Merge pull request 'Fixes changes in zig build system.' (#148) from i_147 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/148
2024-08-22 16:44:30 +00:00
Chris Boesch
8e35cf7990 Insert wrong version number into build file. 2024-08-22 18:32:36 +02:00
Chris Boesch
dab5197027 Fixes changes in zig build system. 2024-08-22 18:19:21 +02:00
Chris Boesch
ed88236fa7 Merge pull request 'Added license to contributing' (#146) from contrib_lic into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/146
2024-08-19 12:19:05 +00:00
Chris Boesch
031e11aa61 Added license to contributing 2024-08-19 14:04:48 +02:00
Chris Boesch
118c1252be Merge pull request 'Simplified de-referencing for clarification' (#143) from i139 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/143
2024-08-11 16:43:17 +00:00
Chris Boesch
3baf0ae657 Simplified de-referencing for clarification 2024-08-11 18:23:48 +02:00
Chris Boesch
97c8bc39bc Merge pull request 'Clarification in description for ranges in loops.' (#142) from i141 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/142
2024-08-11 14:48:05 +00:00
Chris Boesch
17f9312034 Clarification in description for ranges in loops. 2024-08-11 16:29:14 +02:00
Chris Boesch
e2f356d95c Merge pull request 'Add build parameter to start at a specific exercise' (#140) from mythmon/ziglings-exercises:build-start-from into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/140
2024-08-09 10:21:08 +00:00
Michael Cooper
70b0522cb2 Add build parameter to start at a specific exercise 2024-08-08 08:23:14 -07:00
Chris Boesch
94d6a4da5f Merge pull request 'Changed needed zig version.' (#138) from pr_130 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/138
2024-08-04 13:19:44 +00:00
Chris Boesch
1ba74488e4 Changed needed zig version. 2024-08-04 15:05:11 +02:00
Chris Boesch
d6887f21c8 Merge pull request 'Fix #127 and #129 by updating the build files to account for recent 0.14.0-dev updates' (#130) from bsubei/exercises:fix-0.14.0-build-changes into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/130
2024-08-04 12:31:21 +00:00
Chris Boesch
a671def2cf Merge branch 'main' into fix-0.14.0-build-changes 2024-08-04 12:20:39 +00:00
Chris Boesch
28320b169f Merge pull request 'Fixed error message through a TAB in the comment, see https://github.com/ziglang/zig/issues/20928' (#137) from work into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/137
2024-08-04 12:20:10 +00:00
Chris Boesch
b26e3b2ac4 Fixed error message through a TAB in the comment, see https://github.com/ziglang/zig/issues/20928 2024-08-04 14:19:05 +02:00
bsubei
4cc1158fbc fix tests build file broken by addRemoveDirTree now requiring LazyPath 2024-07-21 13:01:59 -04:00
bsubei
e7dcf0b6ef fix build files broken by latest 0.14.0-dev changes to Build.Step.MakeOptions 2024-07-21 12:23:30 -04:00
Chris Boesch
e8f09190d6 Merge pull request 'document -Drandom' (#124) from hippietrail/exercises:random-exercise into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/124
2024-07-06 20:21:39 +00:00
Chris Boesch
1fd6aa1c65 Merge branch 'main' into random-exercise 2024-07-06 20:19:56 +00:00
Andrew Dunbar
4401cf8f49 document -Drandom 2024-07-06 14:18:56 +10:00
Chris Boesch
140c22e9f4 Merge pull request 'Update .woodpecker/eowyn.yaml' (#119) from chrboesch-wp-patch-3 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/119
2024-06-25 09:19:30 +00:00
chrboesch
c33898bc65 Update .woodpecker/eowyn.yaml
Add pull request
2024-06-25 09:11:04 +00:00
Chris Boesch
7705473447 Merge pull request 'Rename 'std.rand' to 'std.Random'' (#118) from fix_117 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/118
2024-06-25 08:53:25 +00:00
Chris Boesch
5bf56f03b0 Rename 'std.rand' to 'std.Random' 2024-06-25 10:45:54 +02:00
Chris Boesch
94fe012c77 Merge pull request 'attempt at implementing #113 "Add a way to do one random exercise"' (#117) from hippietrail/exercises:random-exercise into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/117
2024-06-25 08:30:14 +00:00
Andrew Dunbar
2259a18ece attempt at implementing #113 "Add a way to do one random exercise" 2024-06-25 17:22:57 +10:00
Chris Boesch
f496d79ab9 Merge pull request '046: Show usage of .? and hint towards new solution.' (#116) from alexmchughnz/ziglings:fix046 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/116
2024-06-24 19:13:25 +00:00
Alex McHugh
f656e950d5 Add patch. 2024-06-23 20:24:28 +12:00
Alex McHugh
3763f976eb 046: Show usage of .? and hint towards new solution. 2024-06-23 19:35:22 +12:00
Chris Boesch
da46008761 Merge pull request 'Fixes because of a new Zig version, which changes some functions.' (#114) from patch-106 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/114
2024-06-17 10:14:13 +00:00
Chris Boesch
5c000ce2d7 Fixes because of a new Zig version, which changes some functions. 2024-06-17 11:43:25 +02:00
Chris Boesch
c0c315b25a Merge pull request 'Calling split is deprecated' (#110) from cannero/zig-exercises:change_split into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/110
2024-06-17 08:00:44 +00:00
Sebastian
83f16709ba Calling split is deprecated
The `split` function in std mem is depreacted and a `@compileError`, splitSequence,
splitAny, or splitScalar should be used instead.
2024-06-16 18:58:48 +02:00
Chris Boesch
6d3d3651d0 Merge pull request 'English fixes for 107_files2.zig' (#108) from hippietrail/exercises:english-107 into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/108
2024-06-14 09:06:53 +00:00
Andrew Dunbar
582a2558c7 English fixes for 106_files.zig 2024-06-12 17:52:33 +10:00
Andrew Dunbar
c9e5c7d561 English fixes for 107_files2.zig 2024-06-12 17:29:11 +10:00
Chris Boesch
65387dda45 Merge pull request 'fixed typo' (#107) from typo into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/107
2024-06-08 17:25:17 +00:00
Chris Boesch
1f5ec78df8 fixed typo 2024-06-08 19:20:30 +02:00
Chris Boesch
bb032fad40 Merge pull request 'New Zig version' (#106) from readme into main
Reviewed-on: https://codeberg.org/ziglings/exercises/pulls/106
2024-06-08 17:07:59 +00:00
Chris Boesch
984f4af3a1 New Zig version 2024-06-08 19:07:20 +02:00
145 changed files with 4414 additions and 2876 deletions

View File

@@ -1,31 +0,0 @@
// 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"
}

5
.gitea/issue_template.md Normal file
View File

@@ -0,0 +1,5 @@
Ziglings is a progressive learning series — each exercise builds on previous ones.
Before opening an issue, please ensure you've followed the path and read the instructions carefully.
Respectful and constructive feedback is always welcome.

1
.gitignore vendored
View File

@@ -3,6 +3,7 @@
/answers/
/patches/healed/
/output/
.progress.txt
# Leave this in here for older zig versions
/zig-cache/

View File

@@ -5,5 +5,6 @@ steps:
commands:
- sh ./patches/eowyn.sh
when:
event: [push, cron]
event: [pull_request, push, cron]
branch: main
cron: daily*

View File

@@ -12,10 +12,10 @@ the current Zig snapshot, setup a copy of Ziglings, and knows
common language building blocks (if/then/else, loops, and
functions) is ready for Ziglings.
Ziglings is intended to be completely self-contained. If you
can't solve an exercise from the information you've gleaned so
far from Ziglings, then the exercise probably needs some
additional work. Please file an issue!
Zigling's excercises are self-contained. If you can't solve
an exercise from the information you've gleaned so far from
Ziglings, then the exercise probably needs some additional work.
Please file an issue!
If an example doesn't match a description or if something is
unclear, please file an issue!
@@ -38,8 +38,26 @@ Feel free to submit new exercises but please understand that they
may be heavily edited or rejected entirely if we feel they don't
fit for one reason or another.
## AI-Generated Content
We welcome contributions from non-native English speakers and
appreciate the effort it takes to write in a foreign language.
Using AI tools to polish your English is fine.
What we don't accept is AI-generated exercises, AI-generated
comments, or pull requests produced by coding agents. Ziglings
exercises require understanding the Zig build system, the
didactic progression, and the specific conventions of this
project. That understanding doesn't come from a prompt.
If we suspect a contribution is primarily AI-generated, we will
close it.
## Platforms and Zig Versions
Because it uses the Zig build system, Ziglings should work
wherever Zig does.
@@ -51,6 +69,8 @@ If you run into an error in Ziglings caused by breaking changes
in the latest development build of Zig, that's a new bug in
Ziglings. Please file an issue...or make a pull request!
For the latter, also read "The Secrets” section.
## Formatting
@@ -75,7 +95,36 @@ interface. Specifically:
eternal Ziglings contributor glory is yours!
## Licence
If you submit your contribution to the repository/project,
you agree that your contribution will be licensed under
the license of this repository/this project.
Please note, it does not change your rights to use your own
contribution for any other purpose.
## The Secrets
If you want to peek at the secrets, take a look at the `patches/`
directory.
Every Ziglings exercise contains mistakes on purpose.
To keep our automated tests happy, each exercise also
has a patch in `patches/patches` that “heals” it.
When you change an exercise, you will usually need to update
its patch too. Thats where our little helper Gollum comes in:
1. In the project root, create a folder called `answers/`
2. Put your solved version of the exercise file in there
3. Back in the root, run:
`./patches/gollum.sh <exercise-number>`<br>
For example: `./patches/gollum.sh 106`
This will generate a shiny new patch.
Double-check everything by asking the magical Eowyn:
`./patches/eowyn.sh`<br>
If all tests pass: You are done!
Dont forget to commit the patch file.

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021 Dave Gauer
Copyright (c) 2021 Dave Gauer, Chris Boesch
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

150
README.md
View File

@@ -1,20 +1,19 @@
# Ziglings
Welcome to Ziglings! This project contains a series of tiny
broken programs (and one nasty surprise). By fixing them, you'll
broken programs (and one nasty surprise). By fixing them, you'll
learn how to read and write [Zig](https://ziglang.org/) code.
![Ziglings](images/ziglings.jpg "Ziglings")
![Ziglings](images/ziglings_dark.jpg "Ziglings")
Those broken programs need your help! (You'll also save the
planet from evil aliens and help some friendly elephants stick
together, which is very sweet of you.)
This project was directly inspired by the brilliant and fun
[rustlings](https://github.com/rust-lang/rustlings)
project for the [Rust](https://www.rust-lang.org/) language.
Indirect inspiration comes from [Ruby Koans](http://rubykoans.com/)
and the Little LISPer/Little Schemer series of books.
This project was initiated by [Dave Gauer](https://ratfactor.com/) and is directly inspired
by the brilliant and fun [rustlings](https://github.com/rust-lang/rustlings) project.
Indirect inspiration comes from [Ruby Koans](http://rubykoans.com/) and the Little LISPer/Little
Schemer series of books.
## Intended Audience
@@ -26,40 +25,40 @@ language such as C.
Each exercise is self-contained and self-explained. However,
you're encouraged to also check out these Zig language resources
for more detail:
for more details:
* 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)
Also, the [Zig community](https://ziglang.org/community/)
is incredibly friendly and helpful!
## Getting Started
Install a [development build](https://ziglang.org/download/) of
the Zig compiler. (See the "master" section of the downloads
page.)
page.) Sometimes the latest build is not available there;
in that case, you can download it directly from the [build directory](https://ziglang.org/download/index.json).
Verify the installation and build number of `zig` like so:
```
$ zig version
0.13.0-dev.xxxx+xxxxxxxxx
0.17.0-dev.xxxx+xxxxxxxxx
```
Clone this repository with Git:
```
$ git clone https://ziglings.org
$ cd ziglings.org
git clone https://codeberg.org/ziglings/exercises.git ziglings
cd ziglings
```
Then run `zig build` and follow the instructions to begin!
```
$ zig build
zig build
```
Note: The output of Ziglings is the unaltered output from the Zig
@@ -74,10 +73,12 @@ 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.12.0`, but Ziglings needs a dev build with
pre-release version "0.13.0" and a build number at least as high
stable release was `0.16`, but Ziglings needs a dev build with
pre-release version "0.17.0-dev" and a build number at least as high
as that shown in the example version check above.
**Hint**: You can find a summary of breaking changes at the end of this README.
It is likely that you'll download a build which is _greater_ than
the minimum.
@@ -85,39 +86,6 @@ Once you have a build of the Zig compiler that works with
Ziglings, they'll continue to work together. But keep in mind
that if you update one, you may need to also update the other.
### Version Changes
Version-0.13.0-dev.339
* *2024-05-29* zig 0.13.0-dev.339 - rework std.Progress - see [#20059](https://github.com/ziglang/zig/pull/20059)
* *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`
* *2023-05-25* zig 0.11.0-dev.3295 - `std.debug.TTY` is now `std.io.tty`
* *2023-04-30* zig 0.11.0-dev.2704 - use of the new `std.Build.ExecutableOptions.link_libc` field
* *2023-04-12* zig 0.11.0-dev.2560 - changes in `std.Build` - remove run() and install()
* *2023-04-07* zig 0.11.0-dev.2401 - fixes of the new build system - see [#212](https://github.com/ratfactor/ziglings/pull/212)
* *2023-02-21* zig 0.11.0-dev.2157 - changes in `build system` - new: parallel processing of the build steps
* *2023-02-21* zig 0.11.0-dev.1711 - changes in `for loops` - new: Multi-Object For-Loops + Struct-of-Arrays
* *2023-02-12* zig 0.11.0-dev.1638 - changes in `std.Build` cache_root now returns a directory struct
* *2023-02-04* zig 0.11.0-dev.1568 - changes in `std.Build` (combine `std.build` and `std.build.Builder` into `std.Build`)
* *2023-01-14* zig 0.11.0-dev.1302 - changes in `@addWithOverflow` (now returns a tuple) and `@typeInfo`; temporary disabled async functionality
* *2022-09-09* zig 0.10.0-dev.3978 - change in `NativeTargetInfo.detect` in build
* *2022-09-06* zig 0.10.0-dev.3880 - Ex 074 correctly fails again: comptime array len
* *2022-08-29* zig 0.10.0-dev.3685 - `@typeName()` output change, stage1 req. for async
* *2022-07-31* zig 0.10.0-dev.3385 - std lib string `fmt()` option changes
* *2022-03-19* zig 0.10.0-dev.1427 - method for getting sentinel of type changed
* *2021-12-20* zig 0.9.0-dev.2025 - `c_void` is now `anyopaque`
* *2021-06-14* zig 0.9.0-dev.137 - std.build.Id `.Custom` is now `.custom`
* *2021-04-21* zig 0.8.0-dev.1983 - std.fmt.format() `any` format string required
* *2021-02-12* zig 0.8.0-dev.1065 - std.fmt.format() `s` (string) format string required
## Advanced Usage
It can be handy to check just a single exercise:
@@ -126,10 +94,16 @@ It can be handy to check just a single exercise:
zig build -Dn=19
```
You can also run without checking for correctness:
Or run all exercises, starting from a specific one:
```
zig build -Dn=19 test
zig build -Ds=27
```
Or let Ziglings pick an exercise for you:
```
zig build -Drandom
```
Or skip the build system entirely and interact directly with the
@@ -139,22 +113,15 @@ compiler if you're into that sort of thing:
zig run exercises/001_hello.zig
```
Calling all wizards: To prepare an executable for debugging,
install it to zig-cache/bin with:
```
zig build -Dn=19 install
```
To get a list of all possible options, run:
```
zig build -Dn=19 -l
zig build -h
```
install Install 019_functions2.zig to prefix path
uninstall Uninstall 019_functions2.zig from prefix path
test Run 019_functions2.zig without checking output
...
To reset the progress (have it run all the exercises that have already been completed):
```
zig build -Dreset
```
## What's Covered
@@ -208,11 +175,14 @@ Zig Core Language
* [x] Sentinel termination
* [x] Quoted identifiers @""
* [x] Anonymous structs/tuples/lists
* [ ] Async <--- ironically awaiting upstream Zig updates
* [x] Async I/O
* [X] Interfaces
* [X] Bit manipulation
* [X] Working with C
* [ ] Opaque types (anyopaque)
* [X] Threading
* [x] Labeled switch
* [x] Vector operations (SIMD)
Zig Standard Library
@@ -221,6 +191,55 @@ Zig Standard Library
* [X] Tokenization
* [X] File handling
### Version Changes
* 2026-05-31 zig 0.17.0-dev.607 - zig build: separate the maker process from the configurer process, see[#35428](https://codeberg.org/ziglang/zig/pulls/35428)
* 2026-03-20 zig 0.16.0-dev.2915 - `GeneralPurposeAllocator` was changed to `DebugAllocator`
* 2026-02-04 zig 0.16.0-dev.2471 - added process.Child.Cwd, see [#31090](https://codeberg.org/ziglang/zig/pulls/31090)
* 2026-01-09 zig 0.16.0-dev.2075 - move randomness API to `std.Io`, see [#30709](https://codeberg.org/ziglang/zig/pulls/30709)
* 2026-01-07 zig 0.16.0-dev.2040 - adjust temp files, see [#30683](https://codeberg.org/ziglang/zig/pulls/30683)
* 2026-01-06 zig 0.16.0-dev.1976 - move process API to `std.Io` and changes to main/environ/argv, see [#30644](https://codeberg.org/ziglang/zig/pulls/30644)
* *2025-12-28* zig 0.16.0-dev.1859 - file system I/O integrated with the std.Io interface, see [#30232](https://codeberg.org/ziglang/zig/pulls/30232)
* *2025-11-01* zig 0.16.0-dev.1204 - more changes due to new I/O API, see [#25592](https://github.com/ziglang/zig/pull/25592)
* *2025-09-24* zig 0.16.0-dev.377 - Enable passing file content as args, see [#25228](https://github.com/ziglang/zig/pull/25228)
* *2025-09-03* zig 0.16.0-dev.164 - changes in reader, see [#25077](https://github.com/ziglang/zig/pull/25077)
* *2025-08-15* zig 0.15.0-dev.1519 - changes in array list, see [#24801](https://github.com/ziglang/zig/pull/24801)
* *2025-08-08* zig 0.15.0-dev.1380 - changes in build system, see [#24588](https://github.com/ziglang/zig/pull/24588)
* *2025-07-22* zig 0.15.0-dev.1092 - various changes due to new I/O API, see [#24488](https://github.com/ziglang/zig/pull/24488)
* *2024-09-16* zig 0.14.0-dev.1573 - introduction of labeled switch, see [#21257](https://github.com/ziglang/zig/pull/21257)
* *2024-09-02* zig 0.14.0-dev.1409 - several changes in std.builtin, see [#21225](https://github.com/ziglang/zig/pull/21225)
* *2024-08-04* zig 0.14.0-dev.1224 - several changes in build system, see [#21115](https://github.com/ziglang/zig/pull/21115)
* *2024-08-04* zig 0.14.0-dev.839 - several changes in build system, see [#20580](https://github.com/ziglang/zig/pull/20580), [#20600](https://github.com/ziglang/zig/issues/20600)
* *2024-06-17* zig 0.14.0-dev.42 - changes in `std.mem.split and tokenize` - see [#15579](https://github.com/ziglang/zig/pull/15579)
* *2024-05-29* zig 0.13.0-dev.339 - rework std.Progress - see [#20059](https://github.com/ziglang/zig/pull/20059)
* *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`
* *2023-05-25* zig 0.11.0-dev.3295 - `std.debug.TTY` is now `std.io.tty`
* *2023-04-30* zig 0.11.0-dev.2704 - use of the new `std.Build.ExecutableOptions.link_libc` field
* *2023-04-12* zig 0.11.0-dev.2560 - changes in `std.Build` - remove run() and install()
* *2023-04-07* zig 0.11.0-dev.2401 - fixes of the new build system - see [#212](https://github.com/ratfactor/ziglings/pull/212)
* *2023-02-21* zig 0.11.0-dev.2157 - changes in `build system` - new: parallel processing of the build steps
* *2023-02-21* zig 0.11.0-dev.1711 - changes in `for loops` - new: Multi-Object For-Loops + Struct-of-Arrays
* *2023-02-12* zig 0.11.0-dev.1638 - changes in `std.Build` cache_root now returns a directory struct
* *2023-02-04* zig 0.11.0-dev.1568 - changes in `std.Build` (combine `std.build` and `std.build.Builder` into `std.Build`)
* *2023-01-14* zig 0.11.0-dev.1302 - changes in `@addWithOverflow` (now returns a tuple) and `@typeInfo`; temporary disabled async functionality
* *2022-09-09* zig 0.10.0-dev.3978 - change in `NativeTargetInfo.detect` in build
* *2022-09-06* zig 0.10.0-dev.3880 - Ex 074 correctly fails again: comptime array len
* *2022-08-29* zig 0.10.0-dev.3685 - `@typeName()` output change, stage1 req. for async
* *2022-07-31* zig 0.10.0-dev.3385 - std lib string `fmt()` option changes
* *2022-03-19* zig 0.10.0-dev.1427 - method for getting sentinel of type changed
* *2021-12-20* zig 0.9.0-dev.2025 - `c_void` is now `anyopaque`
* *2021-06-14* zig 0.9.0-dev.137 - std.build.Id `.Custom` is now `.custom`
* *2021-04-21* zig 0.8.0-dev.1983 - std.fmt.format() `any` format string required
* *2021-02-12* zig 0.8.0-dev.1065 - std.fmt.format() `s` (string) format string required
## Contributing
Contributions are very welcome! I'm writing this to teach myself
@@ -233,3 +252,4 @@ tons of room for improvement:
Please see [CONTRIBUTING](https://codeberg.org/ziglings/exercises/src/branch/main/CONTRIBUTING.md)
in this repo for the full details.

1142
build.zig

File diff suppressed because it is too large Load Diff

View File

@@ -2,8 +2,8 @@
// Oh no, this is supposed to print "Hello world!" but it needs
// your help.
//
// Zig functions are private by default but the main() function
// should be public.
// Zig functions are private by default, but the main() function
// must be public.
//
// A function is made public with the "pub" statement like so:
//

View File

@@ -1,5 +1,5 @@
//
// Zig has some fun array operators.
// Zig has one array operator.
//
// You can use '++' to concatenate two arrays:
//
@@ -7,12 +7,8 @@
// const b = [_]u8{ 3,4 };
// const c = a ++ b ++ [_]u8{ 5 }; // equals 1 2 3 4 5
//
// You can use '**' to repeat an array:
//
// const d = [_]u8{ 1,2,3 } ** 2; // equals 1 2 3 1 2 3
//
// Note that both '++' and '**' only operate on arrays while your
// program is _being compiled_. This special time is known in Zig
// Note that '++' only operates on arrays while your program is
// _being compiled_. This special time is known in Zig
// parlance as "comptime" and we'll learn plenty more about that
// later.
//
@@ -30,7 +26,8 @@ pub fn main() void {
// (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_unit = [_]u8{ ??? };
const bit_pattern: [3 * bit_pattern_unit.len]u8 = @bitCast(@as([3][bit_pattern_unit.len]u8, @splat(bit_pattern_unit)));
// Okay, that's all of the problems. Let's see the results.
//

View File

@@ -27,10 +27,6 @@ pub fn main() void {
const d: u8 = ziggy[???];
// (Problem 2)
// Use the array repeat '**' operator to make "ha ha ha ".
const laugh = "ha " ???;
// (Problem 3)
// Use the array concatenation '++' operator to make "Major Tom".
// (You'll need to add a space as well!)
const major = "Major";
@@ -38,7 +34,7 @@ pub fn main() void {
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 });
std.debug.print("d={u} {s}\n", .{ d, major_tom });
// Keen eyes will notice that we've put 'u' and 's' inside the '{}'
// placeholders in the format string above. This tells the
// print() function to format the values as a UTF-8 character and

View File

@@ -21,13 +21,13 @@
const std = @import("std");
pub fn main() void {
const foo = 1;
const foo = 42;
// Please fix this condition:
if (foo) {
// We want our program to print this message!
std.debug.print("Foo is 1!\n", .{});
std.debug.print("Foo is 42!\n", .{});
} else {
std.debug.print("Foo is not 1!\n", .{});
std.debug.print("Foo is not 42!\n", .{});
}
}

View File

@@ -11,8 +11,8 @@
//
// }
//
// The "continue expression" executes every time the loop restarts
// whether the "continue" statement happens or not.
// The "continue expression" executes every single time the loop restarts,
// even when a `continue` statement skips the rest of the loop body.
//
const std = @import("std");

View File

@@ -3,7 +3,7 @@
// example that takes two parameters. As you can see, parameters
// are declared just like any other types ("name": "type"):
//
// fn myFunction(number: u8, is_lucky: bool) {
// fn myFunction(number: u8, is_lucky: bool) void {
// ...
// }
//

View File

@@ -14,9 +14,14 @@ const std = @import("std");
// You can find more information at:
// https://ziglang.org/documentation/master/#Inferred-Error-Sets
//
pub fn main() !void {
// We get a Writer for Standard Out so we can print() to it.
const stdout = std.io.getStdOut().writer();
pub fn main(init: std.process.Init) !void {
// Instance for input/output operations; we will learn more about this later.
const io = init.io;
// We get a Writer for Standard Out...
var stdout_writer = std.Io.File.stdout().writer(io, &.{});
// ...and extract its interface so we can print() to it.
const stdout = &stdout_writer.interface;
// Unlike std.debug.print(), the Standard Out writer can fail
// with an error. We don't care _what_ the error is, we want

View File

@@ -10,6 +10,8 @@ pub fn main() void {
for (animals) |a| printAnimal(a);
std.debug.print("done.\n", .{});
std.debug.print("Answer to everything? {d}\n", .{calculateTheUltimateQuestionOfLife()});
}
// This function is _supposed_ to print an animal name in parentheses
@@ -35,3 +37,24 @@ fn printAnimal(animal: u8) void {
std.debug.print("Unknown", .{});
}
// This function is supposed to calculate the answer to the
// ultimate question of life, the universe, and everything,
// but it needs to be deferred as far in the future as possible,
// in order to gather more data.
//
// When there are multiple defers in a single block, they are executed in reverse order.
// This example might seem silly, but it's important to know when e.g.
// deinitializing containers whose elements need to be deinitialized first.
fn calculateTheUltimateQuestionOfLife() u32 {
var x: u32 = 100;
// Try reordering the statements to get the answer 42
{
defer x = x / 10;
defer x = x + 11;
defer x = x * 2;
}
return x;
}

View File

@@ -17,7 +17,7 @@
//
// if (foo) |value| {
// ...
// } else |err| switch(err) {
// } else |err| switch (err) {
// ...
// }
//

View File

@@ -9,8 +9,10 @@ const std = @import("std");
const NumError = error{IllegalNumber};
pub fn main() void {
const stdout = std.io.getStdOut().writer();
pub fn main(init: std.process.Init) !void {
const io = init.io;
var stdout_writer = std.Io.File.stdout().writer(io, &.{});
const stdout = &stdout_writer.interface;
const my_num: u32 = getNumber();

View File

@@ -4,7 +4,7 @@
// var foo: u8 = 5; // foo is 5
// var bar: *u8 = &foo; // bar is a pointer
//
// What is a pointer? It's a reference to a value. In this example
// What is a pointer? It's a reference to a value. In this example,
// bar is a reference to the memory space that currently contains the
// value 5.
//

View File

@@ -27,3 +27,19 @@ pub fn main() void {
std.debug.print("a: {}, b: {}\n", .{ a, b.* });
}
//
// A look into the future:
// When you allocate memory, you store the returned address in
// a const var. The pointer itself never changes — it always
// refers to the same allocation — but you can still read and
// write the data it points to.
//
// Example:
//
// const buf = try allocator.alloc(u8, 1024);
// buf[0] = 42; // fine: the *contents* are mutable
//
// Note:
// Passing this pointer to a function is cheap: it's just an address
// copied on the stack. The caller can work with the data without
// needing to know where it came from or how it was allocated.

View File

@@ -5,7 +5,7 @@
// linked to the first elephant. This is because we had NO CONCEPT
// of a tail that didn't point to another elephant!
//
// We also introduce the handy ".?" shortcut:
// We also introduce the handy `.?` shortcut:
//
// const foo = bar.?;
//
@@ -13,7 +13,8 @@
//
// const foo = bar orelse unreachable;
//
// See if you can find where we use this shortcut below.
// Check out where we use this shortcut below to change control flow
// based on if an optional value exists.
//
// Now let's make those elephant tails optional!
//
@@ -31,14 +32,25 @@ pub fn main() void {
var elephantC = Elephant{ .letter = 'C' };
// Link the elephants so that each tail "points" to the next.
elephantA.tail = &elephantB;
elephantB.tail = &elephantC;
linkElephants(&elephantA, &elephantB);
linkElephants(&elephantB, &elephantC);
// `linkElephants` will stop the program if you try and link an
// elephant that doesn't exist! Uncomment and see what happens.
// const missingElephant: ?*Elephant = null;
// linkElephants(&elephantC, missingElephant);
visitElephants(&elephantA);
std.debug.print("\n", .{});
}
// If e1 and e2 are valid pointers to elephants,
// this function links the elephants so that e1's tail "points" to e2.
fn linkElephants(e1: ?*Elephant, e2: ?*Elephant) void {
e1.?.tail = e2.?;
}
// This function visits all elephants once, starting with the
// first elephant and following the tails to the next elephant.
fn visitElephants(first_elephant: *Elephant) void {
@@ -51,6 +63,9 @@ 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?
// HINT: We want something similar to what `.?` does,
// but instead of ending the program, we want to exit the loop...
e = e.tail ???
}
}

View File

@@ -14,8 +14,8 @@
//
// "undefined" should not be thought of as a value, but as a way
// of telling the compiler that you are not assigning a value
// _yet_. Any type may be set to undefined, but attempting
// to read or use that value is _always_ a mistake.
// _yet_. Any variable may be set to undefined, but attempting to
// read its value before assigning one is _always_ a mistake.
//
// * null
//
@@ -24,7 +24,7 @@
// The "null" primitive value _is_ a value that means "no value".
// This is typically used with optional types as with the ?u8
// shown above. When foo equals null, that's not a value of type
// u8. It means there is _no value_ of type u8 in foo at all!
// u8. It means you have assigned foo to have _no value_!
//
// * error
//
@@ -32,10 +32,9 @@
//
// Errors are _very_ similar to nulls. They _are_ a value, but
// they usually indicate that the "real value" you were looking
// for does not exist. Instead, you have an error. The example
// error union type of MyError!u8 means that foo either holds
// a u8 value OR an error. There is _no value_ of type u8 in foo
// when it's set to an error!
// for does not exist. Instead of "no value", you have an error.
// The example error union type of MyError!u8 means that foo
// either holds a u8 value OR a MyError error.
//
// * void
//
@@ -43,7 +42,7 @@
//
// "void" is a _type_, not a value. It is the most popular of the
// Zero Bit Types (those types which take up absolutely no space
// and have only a semantic value. When compiled to executable
// and have only a semantic value). When compiled to executable
// code, zero bit types generate no code at all. The above example
// shows a variable foo of type void which is assigned the value
// of an empty expression. It's much more common to see void as
@@ -55,7 +54,7 @@
// * undefined - there is no value YET, this cannot be read YET
// * null - there is an explicit value of "no value"
// * errors - there is no value because something went wrong
// * void - there will NEVER be a value stored here
// * void - there will NEVER be a value here
//
// Please use the correct "no value" for each ??? to make this program
// print out a cursed quote from the Necronomicon. ...If you dare.

View File

@@ -54,7 +54,7 @@ var global_wizard = Character{};
// an extremely efficient place for memory storage.
//
// Also, when a function executes, the input arguments are often
// loaded into the beating heart of the CPU itself in registers.
// loaded into the beating heart of the CPU itself, in registers.
//
// Our main() function here has no input parameters, but it will have
// a stack entry (called a "frame").

View File

@@ -190,7 +190,7 @@ const TripItem = union(enum) {
fn printMe(self: TripItem) void {
switch (self) {
// Oops! The hermit forgot how to capture the union values
// in a switch statement. Please capture both values as
// in a switch statement. Please capture each value as
// 'p' so the print statements work!
.place => print("{s}", .{p.name}),
.path => print("--{}->", .{p.dist}),
@@ -224,11 +224,10 @@ const NotebookEntry = struct {
// +---+----------------+----------------+----------+
//
const HermitsNotebook = struct {
// Remember the array repetition operator `**`? It is no mere
// novelty, it's also a great way to assign multiple items in an
// array without having to list them one by one. Here we use it to
// initialize an array with null values.
entries: [place_count]?NotebookEntry = .{null} ** place_count,
// Remember the array repetition function @splat()? It is a great way
// to assign multiple items in an array without having to list them
// one by one. Here we use it to initialize an array with null values.
entries: [place_count]?NotebookEntry = @splat(null),
// The next entry keeps track of where we are in our "todo" list.
next_entry: u8 = 0,
@@ -409,7 +408,7 @@ pub fn main() void {
// aside memory for the trip and have the hermit's notebook fill
// in the trip from the destination back to the path. Note that
// this is the first time we've actually used the destination!
var trip = [_]?TripItem{null} ** (place_count * 2);
var trip: [place_count * 2]?TripItem = @splat(null);
notebook.getTripTo(trip[0..], destination) catch |err| {
print("Oh no! {}\n", .{err});

View File

@@ -27,10 +27,17 @@
// the types match. Zig does not perform unsafe type coercions
// behind your back:
//
// var foo: f16 = 5; // NO ERROR
// var foo: f16 = 5; // NO ERROR
//
// A runtime value can coerce to a different type,
// as long as the value is losslessly representable:
//
// var foo: u16 = 5;
// var bar: f16 = foo; // NO ERROR (5 fits in f16)
//
// var foo: u16 = 49876;
// var bar: f16 = foo; // ERROR (49876 not representable in f16)
//
// var foo: u16 = 5; // A literal of a different type
// var bar: f16 = foo; // ERROR
//
// Please fix the two float problems with this program and
// display the result as a whole number.
@@ -41,14 +48,17 @@ pub fn main() void {
// The approximate weight of the Space Shuttle upon liftoff
// (including boosters and fuel tank) was 4,480,000 lb.
//
// 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;
// We'll convert this weight from pounds to metric units at a
// conversion of 0.453592 kg to the pound.
const shuttle_weight: f16 = 0.453592 * 4480e3;
// By default, float values are formatted in scientific
// notation. Try experimenting with '{d}' and '{d:.3}' to see
// how decimal formatting works.
print("Shuttle liftoff weight: {d:.0}kg\n", .{shuttle_weight});
// By default, float values are formatted in standard decimal
// notation. Experiment with '{d}' and '{d:.3}' to see how
// decimal formatting works, or try '{e}' and '{e:.3}' for
// scientific notation.
// NOTE: The weight of the shuttle is a huge number, a scientific notation
// may be more appropriate.
print("Shuttle liftoff weight: {d:.0} metric tons\n", .{shuttle_weight / 1e3});
}
// Floating further:

View File

@@ -93,32 +93,25 @@ pub fn main() void {
print("He has room in his heart for:", .{});
// A StructFields array
const fields = @typeInfo(Narcissus).Struct.fields;
// `field_names` is a slice of strings and it holds the names of the struct's fields
// `field_types` is a slice of strings and it holds the types of the struct's fields,
// it is guaranteed to be the same length as `field_names`
const field_names = @typeInfo(Narcissus).@"struct".field_names;
const field_types = @typeInfo(Narcissus).@"struct".field_types;
// 'fields' is a slice of StructFields. Here's the declaration:
//
// pub const StructField = struct {
// name: []const u8,
// type: type,
// default_value: anytype,
// is_comptime: bool,
// alignment: comptime_int,
// };
//
// Please complete these 'if' statements so that the field
// name will not be printed if the field is of type 'void'
// (which is a zero-bit type that takes up no space at all!):
if (fields[0].??? != void) {
print(" {s}", .{@typeInfo(Narcissus).Struct.fields[0].name});
if (field_???[???] != void) {
print(" {s}", .{field_???[???]});
}
if (fields[1].??? != void) {
print(" {s}", .{@typeInfo(Narcissus).Struct.fields[1].name});
if (field_???[???] != void) {
print(" {s}", .{field_???[???]});
}
if (fields[2].??? != void) {
print(" {s}", .{@typeInfo(Narcissus).Struct.fields[2].name});
if (field_???[???] != void) {
print(" {s}", .{field_???[???]});
}
// Yuck, look at all that repeated code above! I don't know
@@ -133,17 +126,20 @@ pub fn main() void {
}
// NOTE: This exercise did not originally include the function below.
// But a change after Zig 0.10.0 added the source file name to the
// type. "Narcissus" became "065_builtins2.Narcissus".
// After Zig 0.10.0, `@typeName` began prefixing the returned type name
// with the source file name. For example, "Narcissus" became
// "065_builtins2.Narcissus".
//
// To fix this, I've added this function to strip the filename from
// the front of the type name in the dumbest way possible. (It returns
// a slice of the type name starting at character 14 (assuming
// single-byte characters).
// To fix this, we've added this function to strip the filename from
// the front of the type name. (It returns a slice of the type name
// starting just after the ".")
//
// We'll be seeing @typeName again in Exercise 070. For now, you can
// see that it takes a Type and returns a u8 "string".
fn maximumNarcissism(myType: anytype) []const u8 {
// Turn '065_builtins2.Narcissus' into 'Narcissus'
return @typeName(myType)[14..];
fn maximumNarcissism(myType: type) []const u8 {
const find = @import("std").mem.find;
// Turn "065_builtins2.Narcissus" into "Narcissus"
const name = @typeName(myType);
return name[find(u8, name, ".").? + 1 ..];
}

View File

@@ -8,6 +8,7 @@
// --o-- comptime * | .. .
// * | * . . . . --*-- . * .
// . . . . . . . . . | . . .
// (ASCII art depicting a starry sky with "comptime" as rising star)
//
// When placed before a variable declaration, 'comptime'
// guarantees that every usage of that variable will be performed
@@ -38,16 +39,16 @@ pub fn main() void {
var count = 0;
count += 1;
const a1: [count]u8 = .{'A'} ** count;
const a1: [count]u8 = @splat('A');
count += 1;
const a2: [count]u8 = .{'B'} ** count;
const a2: [count]u8 = @splat('B');
count += 1;
const a3: [count]u8 = .{'C'} ** count;
const a3: [count]u8 = @splat('C');
count += 1;
const a4: [count]u8 = .{'D'} ** count;
const a4: [count]u8 = @splat('D');
print("{s} {s} {s} {s}\n", .{ a1, a2, a3, a4 });

View File

@@ -11,7 +11,7 @@
// format string can be checked for errors at compile time rather
// than crashing at runtime.
//
// (The actual formatting is done by std.fmt.format() and it
// (The actual formatting is done by std.Io.Writer.print() and it
// contains a complete format string parser that runs entirely at
// compile time!)
//

View File

@@ -7,12 +7,12 @@
// doing this work.
//
// An 'inline for' is performed at compile time, allowing you to
// programatically loop through a series of items in situations
// programmatically loop through a series of items in situations
// like those mentioned above where a regular runtime 'for' loop
// wouldn't be allowed:
//
// inline for (.{ u8, u16, u32, u64 }) |T| {
// print("{} ", .{@typeInfo(T).Int.bits});
// print("{} ", .{@typeInfo(T).int.bits});
// }
//
// In the above example, we're looping over a list of types,
@@ -36,13 +36,14 @@ pub fn main() void {
// statement was repeated three times almost verbatim. Yuck!
//
// Please use an 'inline for' to implement the block below
// for each field in the slice 'fields'!
// for each field in the corresponding slices (they're of the same length)!
const fields = @typeInfo(Narcissus).Struct.fields;
const field_names = @typeInfo(Narcissus).@"struct".field_names;
const field_types = @typeInfo(Narcissus).@"struct".field_types;
??? {
if (field.type != void) {
print(" {s}", .{field.name});
if (field_type != void) {
print(" {s}", .{field_name});
}
}

View File

@@ -1,62 +1,112 @@
//
// In addition to knowing when to use the 'comptime' keyword,
// it's also good to know when you DON'T need it.
//
// The following contexts are already IMPLICITLY evaluated at
// compile time, and adding the 'comptime' keyword would be
// superfluous, redundant, and smelly:
//
// * The container-level scope (outside of any function in a source file)
// * Type declarations of:
// * Variables
// * Functions (types of parameters and return values)
// * Structs
// * Unions
// * Enums
// * The test expressions in inline for and while loops
// * An expression passed to the @cImport() builtin
//
// Work with Zig for a while, and you'll start to develop an
// intuition for these contexts. Let's work on that now.
//
// You have been given just one 'comptime' statement to use in
// the program below. Here it is:
//
// comptime
//
// Just one is all it takes. Use it wisely!
//
const print = @import("std").debug.print;
const std = @import("std");
const print = std.debug.print;
// Being in the container-level scope, everything about this value is
// implicitly required to be known compile time.
const llama_count = 5;
// We're going to (ab)use the power of Zig to make animal hybrid creatures!
// What do you think a GatorMouse would look like? Eek.
//
// Let's try a MouseLlama instead.
//
// We'll make a function that runs at comptime and takes a short code describing
// the desired creature. A Mouse is represented by "m" and a Llama is "lm".
// A MouseLlama hybrid, then, would be represented by "mlm".
// Again, this value's type and size must be known at compile
// time, but we're letting the compiler infer both from the
// return type of a function.
const llamas = makeLlamas(llama_count);
const Animal = enum {
Mouse,
Llama,
Gator,
};
// And here's the function. Note that the return value type
// depends on one of the input arguments!
fn makeLlamas(count: usize) [count]u8 {
var temp: [count]u8 = undefined;
var i = 0;
// makeCreature takes the count of animals making up the hybrid creature (so we
// know how big a pen we'll need) and a format string, like the "mlm" for
// MouseLlama.
fn makeCreature(comptime count: usize, comptime fmt: []const u8) [count]Animal {
// Note that this does NOT need to be an inline 'while'.
while (i < count) : (i += 1) {
temp[i] = i;
// Since not every animal is represented by a single character, we need to
// track the state of things as we move along. For example, if we see an
// "m", is that a new Mouse or the end of a Llama?
const State = enum {
start, // Ready to start a new animal.
l, // This means we've seen an "l", so if we see an "m", we know it's a Llama.
};
var state = State.start;
// We return an array of animals representing the creature. (This is why we
// really needed the 'count' parameter. Arrays need a size.)
var animals: [count]Animal = undefined;
var next_animal: usize = 0;
inline for (fmt) |char| {
// This is a good spot to add a @compileLog() call if you need to debug
// any variables... (Come back here after you see main().)
switch (state) {
.start => switch (char) {
// We've seen the start of a Llama.
'l' => state = .l,
// Mice are smaller. An "m" is a full Mouse.
'm' => {
animals[next_animal] = .Mouse;
next_animal += 1;
},
// @compileError lets us stop the build immediately if something
// is wrong. It's like @compileLog but it prints a message
// instead of inspecting values.
//
// What do you think happens with Gators? Do they join with
// other animals or is this an error?
'g' => ???,
else => @compileError(std.fmt.comptimePrint("No animal starts with '{c}'!", .{char})),
},
.l => switch (char) {
// We've seen the end of a Llama.
'm' => {
animals[next_animal] = .Llama;
next_animal += 1;
// Something is missing here. After we finish a Llama, we
// need to be ready to _start_ over with a new animal...
???
},
else => @compileError("Only llamas start with 'l'!"),
},
}
}
return temp;
if (state != .start) {
@compileError("Oh no, an incomplete llama!");
}
if (next_animal != count) {
@compileError("Creature is missing an animal (format string too short).");
}
return animals;
}
pub fn main() void {
print("My llama value is {}.\n", .{llamas[2]});
// Once you've fixed the ??? marks above, this makeCreature call will still
// only succeed if you move it outside of main, so it will run at comptime.
//
// With the call here, Zig will try to make the creature at runtime, and
// you'll get an interesting error.
//
// You may think the state got mixed up, but if you use @compileLog to check
// some variables in makeCreature, you'll see that Zig is trying to compare
// comptime values with "[runtime value]", which will never match.
//
// You can solve this by adding "comptime" to two of the variables in
// makeCreature...
const creature = makeCreature(2, "mlm");
for (creature) |animal| {
// @tagName gives us a string representing which variant of an enum we
// have. This lets us print the names of animals without repeating them
// here.
print("{s}", .{@tagName(animal)});
}
print(" joins the crew!", .{});
}
//
// The lesson here is to not pepper your program with 'comptime'
// keywords unless you need them. Between the implicit compile
// time contexts and Zig's aggressive evaluation of any
// expression it can figure out at compile time, it's sometimes
// surprising how few places actually need the keyword.

View File

@@ -48,9 +48,7 @@ const Path = struct {
// instead.
//
// Please fill in the body of this function!
fn makePath(from: *Place, to: *Place, dist: u8) Path {
}
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!
@@ -97,7 +95,7 @@ const NotebookEntry = struct {
};
const HermitsNotebook = struct {
entries: [place_count]?NotebookEntry = .{null} ** place_count,
entries: [place_count]?NotebookEntry = @splat(null),
next_entry: u8 = 0,
end_of_entries: u8 = 0,
@@ -193,7 +191,7 @@ pub fn main() void {
}
}
var trip = [_]?TripItem{null} ** (place_count * 2);
var trip: [place_count * 2]?TripItem = @splat(null);
notebook.getTripTo(trip[0..], destination) catch |err| {
print("Oh no! {}\n", .{err});

View File

@@ -78,7 +78,7 @@ fn printSequence(my_seq: anytype) void {
// a switch to handle printing the Array or Pointer fields,
// depending on which type of my_seq was passed in:
switch (my_typeinfo) {
.Array => {
.array => {
print("Array:", .{});
// Loop through the items in my_seq.
@@ -86,7 +86,7 @@ fn printSequence(my_seq: anytype) void {
print("{}", .{s});
}
},
.Pointer => {
.pointer => {
// Check this out - it's pretty cool:
const my_sentinel = sentinel(@TypeOf(my_seq));
print("Many-item pointer:", .{});

View File

@@ -19,12 +19,12 @@
// const MyBar = Bar(); // store the struct type
// const bar = Bar() {}; // create instance of the struct
//
// * The value of @typeName(Bar()) is "Bar()".
// * The value of @typeName(MyBar) is "Bar()".
// * The value of @typeName(@TypeOf(bar)) is "Bar()".
// * The value of @typeName(Bar()) is "<filename>.Bar()".
// * The value of @typeName(MyBar) is "<filename>.Bar()".
// * The value of @typeName(@TypeOf(bar)) is "<filename>.Bar()".
//
// You can also have completely anonymous structs. The value
// of @typeName(struct {}) is "struct:<position in source>".
// of @typeName(struct {}) is "<filename>.<function>__struct_<nnn>".
//
const print = @import("std").debug.print;

View File

@@ -74,34 +74,27 @@ fn printTuple(tuple: anytype) void {
// @typeInfo() - takes a type, returns a TypeInfo union
// with fields specific to that type.
//
// The list of a struct type's fields can be found in
// TypeInfo's Struct.fields.
// The list of a struct type's field types can be found in
// TypeInfo's @"struct".field_types.
//
// Example:
//
// @typeInfo(Circle).Struct.fields
// @typeInfo(Circle).@"struct".field_types
//
// This will be an array of StructFields.
const fields = ???;
// This will be an array of field types.
const field_types = ???;
// This will be an array of field names.
const field_names = ???;
// 2. Loop through each field. This must be done at compile
// time.
//
// Hint: remember 'inline' loops?
//
for (fields) |field| {
for (???, ???) |???, ???| {
// 3. Print the field's name, type, and value.
//
// Each 'field' in this loop is one of these:
//
// pub const StructField = struct {
// name: []const u8,
// type: type,
// default_value: anytype,
// is_comptime: bool,
// alignment: comptime_int,
// };
//
// You'll need this builtin:
//
// @field(lhs: anytype, comptime field_name: []const u8)
@@ -116,9 +109,13 @@ fn printTuple(tuple: anytype) void {
// @field(foo, "x"); // returns the value at foo.x
//
// The first field should print as: "0"(bool):true
//
// Hint: Be careful! If your 'lhs' is a type, @field() looks
// for declarations. If it's a value, it looks for data.
//
print("\"{s}\"({any}):{any} ", .{
field.???,
field.???,
field_name,
field_type,
???,
});
}

View File

@@ -1,58 +0,0 @@
//
// Six Facts:
//
// 1. The memory space allocated to your program for the
// invocation of a function and all of its data is called a
// "stack frame".
//
// 2. The 'return' keyword "pops" the current function
// invocation's frame off of the stack (it is no longer needed)
// and returns control to the place where the function was
// called.
//
// fn foo() void {
// return; // Pop the frame and return control
// }
//
// 3. Like 'return', the 'suspend' keyword returns control to the
// place where the function was called BUT the function
// invocation's frame remains so that it can regain control again
// at a later time. Functions which do this are "async"
// functions.
//
// fn fooThatSuspends() void {
// suspend {} // return control, but leave the frame alone
// }
//
// 4. To call any function in async context and get a reference
// to its frame for later use, use the 'async' keyword:
//
// var foo_frame = async fooThatSuspends();
//
// 5. If you call an async function without the 'async' keyword,
// the function FROM WHICH you called the async function itself
// becomes async! In this example, the bar() function is now
// async because it calls fooThatSuspends(), which is async.
//
// fn bar() void {
// fooThatSuspends();
// }
//
// 6. The main() function cannot be async!
//
// Given facts 3 and 4, how do we fix this program (broken by facts
// 5 and 6)?
//
const print = @import("std").debug.print;
pub fn main() void {
// Additional Hint: you can assign things to '_' when you
// don't intend to do anything with them.
foo();
}
fn foo() void {
print("foo() A\n", .{});
suspend {}
print("foo() B\n", .{});
}

View File

@@ -102,7 +102,7 @@ pub fn main() !void {
Insect{ .grasshopper = Grasshopper{ .distance_hopped = 32 } },
};
std.debug.print("Daily Insect Report:\n", .{});
std.debug.print("=== Doctor Zoraptera's Insect Report ===\n", .{});
for (my_insects) |insect| {
// Almost done! We want to print() each insect with a
// single method call here.

49
exercises/085_async.zig Normal file
View File

@@ -0,0 +1,49 @@
//
// In previous versions of Zig, async/await used special keywords
// like 'suspend', 'resume', and 'async' that operated on stackframes
// directly. Those keywords no longer exist!
//
// Zig 0.16 replaced them with a unified I/O interface: std.Io.
// This interface uses a VTable pattern - a struct of function pointers -
// to abstract over different concurrency backends:
//
// * Threaded - thread-pool based I/O
// * Evented - chooses the best event-loop backend for your OS:
// * Uring on Linux (io_uring)
// * Kqueue on BSD/macOS
// * Dispatch on macOS (Grand Central Dispatch)
//
// The Io struct itself is tiny:
//
// const Io = struct {
// userdata: ?*anyopaque, // opaque state of the backend
// vtable: *const VTable, // table of function pointers
// };
//
// Your code receives an Io value and calls methods on it.
// The backend is chosen at initialization time - your code doesn't
// need to know which one it is!
//
// In Zig 0.16, main() receives a std.process.Init struct to opt
// into I/O and concurrency support:
//
// pub fn main(init: std.process.Init) !void {
// const io = init.io;
// // ... use io ...
// }
//
// Let's start simple. Fix the main function to extract the Io
// interface from init, then use it to get the current time.
//
const std = @import("std");
pub fn main(init: std.process.Init) !void {
const io = init.???;
// Get the current wall-clock time using the Io interface.
// Hint: Timestamp.now() takes an Io and a Clock type (.real = wall clock).
const timestamp = std.Io.Timestamp.now(io, .real);
// Print the timestamp in seconds since the Unix epoch.
std.debug.print("Current time: {}s since epoch\n", .{timestamp.toSeconds()});
}

View File

@@ -1,28 +0,0 @@
//
// So, 'suspend' returns control to the place from which it was
// called (the "call site"). How do we give control back to the
// suspended function?
//
// For that, we have a new keyword called 'resume' which takes an
// async function invocation's frame and returns control to it.
//
// fn fooThatSuspends() void {
// suspend {}
// }
//
// var foo_frame = async fooThatSuspends();
// resume foo_frame;
//
// See if you can make this program print "Hello async!".
//
const print = @import("std").debug.print;
pub fn main() void {
var foo_frame = async foo();
}
fn foo() void {
print("Hello ", .{});
suspend {}
print("async!\n", .{});
}

54
exercises/086_async2.zig Normal file
View File

@@ -0,0 +1,54 @@
//
// Now that we know how to get an Io value, let's use it for
// asynchronous execution!
//
// io.async() launches a function and returns a Future. The result
// won't necessarily be available until you call .await() on it:
//
// var future = io.async(someFunction, .{ arg1, arg2 });
// const result = future.await(io);
//
// The function *may* run immediately or on another thread -
// your code doesn't need to care! That's the beauty of the
// Io abstraction.
//
// IMPORTANT: Every Future MUST be either .await()ed or .cancel()ed.
// Failing to do so leaks resources! A safe pattern is:
//
// var future = io.async(myFn, .{});
// defer _ = future.cancel(io); // safety net
// // ... later, if we want the result:
// const result = future.await(io);
// // (await after cancel is fine — it just returns the result)
//
// Both .await() and .cancel() block until the task finishes and
// return the result. The difference is that .cancel() also
// requests the task to stop at its next cancellation point.
// Calling either one more than once is safe — subsequent calls
// just return a copy of the result.
//
// Fix this program so that computeAnswer runs asynchronously
// and its result is properly awaited.
//
const std = @import("std");
const print = std.debug.print;
pub fn main(init: std.process.Init) !void {
const io = init.io;
// Launch computeAnswer asynchronously.
var future = io.async(computeAnswer, .{ 6, 7 });
defer _ = future.cancel(io); // always clean up!
print("Computing... ", .{});
// Now collect the result. What method on Future gives us
// the value, blocking until it's ready?
const answer = future.???(io);
print("The answer is: {}\n", .{answer});
}
fn computeAnswer(a: u32, b: u32) u32 {
return a * b;
}

View File

@@ -1,29 +0,0 @@
//
// Because they can suspend and resume, async Zig functions are
// an example of a more general programming concept called
// "coroutines". One of the neat things about Zig async functions
// is that they retain their state as they are suspended and
// resumed.
//
// See if you can make this program print "5 4 3 2 1".
//
const print = @import("std").debug.print;
pub fn main() void {
const n = 5;
var foo_frame = async foo(n);
???
print("\n", .{});
}
fn foo(countdown: u32) void {
var current = countdown;
while (current > 0) {
print("{} ", .{current});
current -= 1;
suspend {}
}
}

49
exercises/087_async3.zig Normal file
View File

@@ -0,0 +1,49 @@
//
// The real power of async shows when you launch MULTIPLE tasks!
//
// With io.async(), you can start several operations, then await
// them all. The Io backend may run them concurrently:
//
// var f1 = io.async(taskA, .{});
// defer _ = f1.cancel(io);
// var f2 = io.async(taskB, .{});
// defer _ = f2.cancel(io);
// const a = f1.await(io);
// const b = f2.await(io);
//
// Notice the defer pattern: each async call is immediately
// followed by a defer cancel. This ensures cleanup even if
// we return early or hit an error before reaching await.
// Since await/cancel are idempotent, the defer is harmless
// if we've already awaited.
//
// Fix this program to launch both tasks and collect their results.
//
const std = @import("std");
const print = std.debug.print;
pub fn main(init: std.process.Init) !void {
const io = init.io;
// Launch both tasks asynchronously.
var future_a = io.async(slowAdd, .{ 1, 2 });
defer _ = future_a.cancel(io);
var future_b = ???(slowMul, .{ 6, 7 });
defer _ = future_b.cancel(io);
// Await both results.
const sum = future_a.await(io);
const product = future_b.await(io);
print("{} + {} = {}\n", .{ 1, 2, sum });
print("{} * {} = {}\n", .{ 6, 7, product });
print("Total: {}\n", .{sum + product});
}
fn slowAdd(a: u32, b: u32) u32 {
return a + b;
}
fn slowMul(a: u32, b: u32) u32 {
return a * b;
}

View File

@@ -1,30 +0,0 @@
//
// It has probably not escaped your attention that we are no
// longer capturing a return value from foo() because the 'async'
// keyword returns the frame instead.
//
// One way to solve this is to use a global variable.
//
// See if you can make this program print "1 2 3 4 5".
//
const print = @import("std").debug.print;
var global_counter: i32 = 0;
pub fn main() void {
var foo_frame = async foo();
while (global_counter <= 5) {
print("{} ", .{global_counter});
???
}
print("\n", .{});
}
fn foo() void {
while (true) {
???
???
}
}

50
exercises/088_async4.zig Normal file
View File

@@ -0,0 +1,50 @@
//
// When you have many tasks that don't return individual values,
// use a Group! A Group is an unordered set of tasks that can
// only be awaited or canceled as a whole:
//
// var group: std.Io.Group = .init;
// group.async(io, myTask, .{arg1});
// group.async(io, myTask, .{arg2});
// try group.await(io); // blocks until ALL tasks finish
//
// Important rules:
// * The return type of functions spawned in a group must be
// coercible to Cancelable!void (i.e. void, or error{Canceled}!void).
// * Once you call group.async(), you MUST eventually call
// group.await() or group.cancel() to release resources.
// * group.cancel() requests cancellation on ALL members,
// then blocks until they all finish.
//
// Unlike Future, Group tasks don't return values to the caller.
// They're ideal for parallel work that communicates through
// shared state or side effects (like printing).
//
// Fix this program to await all tasks in the group.
//
const std = @import("std");
const print = std.debug.print;
pub fn main(init: std.process.Init) !void {
const io = init.io;
var group: std.Io.Group = .init;
// Spawn 3 tasks in any order. Each sleeps for (id * 1) seconds
// before printing, so the output order is deterministic.
group.async(io, doWork, .{ io, 1 });
group.async(io, doWork, .{ io, 3 });
group.async(io, doWork, .{ io, 2 });
// Wait for all tasks to finish.
// What Group method blocks until all tasks complete?
try group.???(io);
print("All tasks finished!\n", .{});
}
fn doWork(io: std.Io, id: u32) void {
// Sleep ensures deterministic output order.
io.sleep(std.Io.Duration.fromSeconds(id), .awake) catch return;
print("Task {} done.\n", .{id});
}

View File

@@ -1,48 +0,0 @@
//
// Sure, we can solve our async value problem with a global
// variable. But this hardly seems like an ideal solution.
//
// So how do we REALLY get return values from async functions?
//
// The 'await' keyword waits for an async function to complete
// and then captures its return value.
//
// fn foo() u32 {
// return 5;
// }
//
// var foo_frame = async foo(); // invoke and get frame
// var value = await foo_frame; // await result using frame
//
// The above example is just a silly way to call foo() and get 5
// back. But if foo() did something more interesting such as wait
// for a network response to get that 5, our code would pause
// until the value was ready.
//
// As you can see, async/await basically splits a function call
// into two parts:
//
// 1. Invoke the function ('async')
// 2. Getting the return value ('await')
//
// Also notice that a 'suspend' keyword does NOT need to exist in
// a function to be called in an async context.
//
// Please use 'await' to get the string returned by
// getPageTitle().
//
const print = @import("std").debug.print;
pub fn main() void {
var myframe = async getPageTitle("http://example.com");
var value = ???
print("{s}\n", .{value});
}
fn getPageTitle(url: []const u8) []const u8 {
// Please PRETEND this is actually making a network request.
_ = url;
return "Example Title.";
}

67
exercises/089_async5.zig Normal file
View File

@@ -0,0 +1,67 @@
//
// One of the most important features of the new Io system is
// structured cancellation!
//
// Every Future has a .cancel() method that:
// 1. Requests the task to stop (via error.Canceled at the
// next "cancellation point")
// 2. BLOCKS until the task actually finishes
// 3. Returns whatever result the task produced
//
// A "cancellation point" is any Io function that can return
// error.Canceled - most commonly io.sleep():
//
// fn myTask(io: std.Io) u32 {
// io.sleep(...) catch |err| switch (err) {
// error.Canceled => return 0, // error handle
// };
// return 42;
// }
//
// This is fundamentally different from killing a thread -
// the task gets a chance to clean up and return a value!
//
// Remember: both .await() and .cancel() block and return the
// result. The only difference is that .cancel() also sends
// the cancellation request. And both are idempotent — calling
// either one again just returns the same result.
//
// Fix this program: the slow task would take 10 seconds,
// but we cancel it after 1 second. The task should detect
// the cancellation and return early.
//
const std = @import("std");
const print = std.debug.print;
pub fn main(init: std.process.Init) !void {
const io = init.io;
var future = io.async(slowTask, .{io});
defer _ = future.cancel(io); // safety net
// Wait 1 second, then cancel instead of waiting the full 10.
io.sleep(std.Io.Duration.fromSeconds(1), .awake) catch {};
print("Canceling slow task...\n", .{});
// We don't want to wait 10 seconds!
// Which Future method requests cancellation AND returns the result?
const result = future.???(io);
print("Task returned: {}\n", .{result});
}
fn slowTask(io: std.Io) u32 {
print("Starting long computation...\n", .{});
// Try to sleep for 10 seconds - but we might get canceled!
io.sleep(std.Io.Duration.fromSeconds(10), .awake) catch |err| switch (err) {
error.Canceled => {
print("Task was canceled, cleaning up.\n", .{});
return 0;
},
};
print("Task completed normally.\n", .{});
return 42;
}

View File

@@ -1,54 +0,0 @@
//
// The power and purpose of async/await becomes more apparent
// when we do multiple things concurrently. Foo and Bar do not
// depend on each other and can happen at the same time, but End
// requires that they both be finished.
//
// +---------+
// | Start |
// +---------+
// / \
// / \
// +---------+ +---------+
// | Foo | | Bar |
// +---------+ +---------+
// \ /
// \ /
// +---------+
// | End |
// +---------+
//
// We can express this in Zig like so:
//
// fn foo() u32 { ... }
// fn bar() u32 { ... }
//
// // Start
//
// var foo_frame = async foo();
// var bar_frame = async bar();
//
// var foo_value = await foo_frame;
// var bar_value = await bar_frame;
//
// // End
//
// Please await TWO page titles!
//
const print = @import("std").debug.print;
pub fn main() void {
var com_frame = async getPageTitle("http://example.com");
var org_frame = async getPageTitle("http://example.org");
var com_title = com_frame;
var org_title = org_frame;
print(".com: {s}, .org: {s}.\n", .{ com_title, org_title });
}
fn getPageTitle(url: []const u8) []const u8 {
// Please PRETEND this is actually making a network request.
_ = url;
return "Example Title";
}

76
exercises/090_async6.zig Normal file
View File

@@ -0,0 +1,76 @@
//
// Sometimes you want to race multiple tasks and act on whichever
// finishes first. That's what Select is for!
//
// Select is like a Group, but lets you receive individual results
// as tasks complete — one at a time:
//
// const Race = std.Io.Select(union(enum) {
// fast: u32,
// slow: u32,
// });
//
// var buffer: [2]Race.Union = undefined;
// var sel = Race.init(io, &buffer);
//
// sel.async(.fast, fastFn, .{io});
// sel.async(.slow, slowFn, .{io});
//
// const winner = try sel.await(); // returns first completed
// switch (winner) {
// .fast => |val| ...,
// .slow => |val| ...,
// }
// sel.cancelDiscard(); // cancel remaining, discard results
//
// As with all async primitives: tasks spawned in a Select MUST
// be cleaned up. Use sel.cancel() to get remaining results one
// by one (for resource cleanup), or sel.cancelDiscard() if you
// don't need them.
//
// The buffer must be large enough for all tasks that might
// complete before you call cancelDiscard().
//
// Fix this program to receive the winner of the race.
//
const std = @import("std");
const print = std.debug.print;
const RaceResult = std.Io.Select(union(enum) {
hare: []const u8,
tortoise: []const u8,
});
pub fn main(init: std.process.Init) !void {
const io = init.io;
var buffer: [2]RaceResult.Union = undefined;
var sel = RaceResult.init(io, &buffer);
sel.async(.hare, runHare, .{io});
sel.async(.tortoise, runTortoise, .{io});
// Wait for the first finisher.
// What Select method returns the first completed result?
const winner = try sel.???();
switch (winner) {
.hare => |msg| print("Hare: {s}\n", .{msg}),
.tortoise => |msg| print("Tortoise: {s}\n", .{msg}),
}
// Clean up the loser — we don't need their result.
sel.cancelDiscard();
}
fn runHare(io: std.Io) []const u8 {
// The hare is fast — only 1 second!
io.sleep(std.Io.Duration.fromSeconds(1), .awake) catch return "I got canceled!";
return "I'm fast!";
}
fn runTortoise(io: std.Io) []const u8 {
// The tortoise is slow — 10 seconds.
io.sleep(std.Io.Duration.fromSeconds(10), .awake) catch return "I got canceled!";
return "Slow and steady...";
}

View File

@@ -1,87 +0,0 @@
//
// Remember how a function with 'suspend' is async and calling an
// async function without the 'async' keyword makes the CALLING
// function async?
//
// fn fooThatMightSuspend(maybe: bool) void {
// if (maybe) suspend {}
// }
//
// fn bar() void {
// fooThatMightSuspend(true); // Now bar() is async!
// }
//
// But if you KNOW the function won't suspend, you can make a
// promise to the compiler with the 'nosuspend' keyword:
//
// fn bar() void {
// nosuspend fooThatMightSuspend(false);
// }
//
// If the function does suspend and YOUR PROMISE TO THE COMPILER
// IS BROKEN, the program will panic at runtime, which is
// probably better than you deserve, you oathbreaker! >:-(
//
const print = @import("std").debug.print;
pub fn main() void {
// The main() function can not be async. But we know
// getBeef() will not suspend with this particular
// invocation. Please make this okay:
var my_beef = getBeef(0);
print("beef? {X}!\n", .{my_beef});
}
fn getBeef(input: u32) u32 {
if (input == 0xDEAD) {
suspend {}
}
return 0xBEEF;
}
//
// Going Deeper Into...
// ...uNdeFiNEd beHAVi0r!
//
// We haven't discussed it yet, but runtime "safety" features
// require some extra instructions in your compiled program.
// Most of the time, you're going to want to keep these in.
//
// But in some programs, when data integrity is less important
// than raw speed (some games, for example), you can compile
// without these safety features.
//
// Instead of a safe panic when something goes wrong, your
// program will now exhibit Undefined Behavior (UB), which simply
// means that the Zig language does not (cannot) define what will
// happen. The best case is that it will crash, but in the worst
// case, it will continue to run with the wrong results and
// corrupt your data or expose you to security risks.
//
// This program is a great way to explore UB. Once you get it
// working, try calling the getBeef() function with the value
// 0xDEAD so that it will invoke the 'suspend' keyword:
//
// getBeef(0xDEAD)
//
// Now when you run the program, it will panic and give you a
// nice stack trace to help debug the problem.
//
// zig run exercises/090_async7.zig
// thread 328 panic: async function called...
// ...
//
// But see what happens when you turn off safety checks by using
// ReleaseFast mode:
//
// zig run -O ReleaseFast exercises/090_async7.zig
// beef? 0!
//
// This is the wrong result. On your computer, you may get a
// different answer or it might crash! What exactly will happen
// is UNDEFINED. Your computer is now like a wild animal,
// reacting to bits and bytes of raw memory with the base
// instincts of the CPU. It is both terrifying and exhilarating.
//

63
exercises/091_async7.zig Normal file
View File

@@ -0,0 +1,63 @@
//
// When multiple async tasks access shared data, you need
// synchronization! Io provides a Mutex for this:
//
// var mutex: std.Io.Mutex = .init;
//
// // In a task:
// try mutex.lock(io); // blocks until lock is acquired
// defer mutex.unlock(io);
// // ... critical section: safe to modify shared data ...
//
// Without the mutex, concurrent tasks could read and write the
// same memory simultaneously, causing a data race — the result
// would be unpredictable.
//
// mutex.lock() is a cancellation point — it can return
// error.Canceled. There's also tryLock() which returns
// immediately (true if acquired, false if not).
//
// Fix this program so the counter is correctly synchronized.
// Without the fix, the final count would be unpredictable.
// With it, four tasks incrementing 100 times each = 400.
//
const std = @import("std");
const print = std.debug.print;
const SharedState = struct {
counter: u32 = 0,
mutex: std.Io.Mutex = .init,
};
pub fn main(init: std.process.Init) !void {
const io = init.io;
var state = SharedState{};
var group: std.Io.Group = .init;
group.async(io, increment, .{ io, &state, 100 });
group.async(io, increment, .{ io, &state, 100 });
group.async(io, increment, .{ io, &state, 100 });
group.async(io, increment, .{ io, &state, 100 });
try group.await(io);
print("Counter: {}\n", .{state.counter});
}
fn increment(io: std.Io, state: *SharedState, times: u32) void {
for (0..times) |_| {
// Acquire the lock before modifying shared state.
// What Mutex method blocks until the lock is acquired?
state.mutex.??? catch return;
defer state.mutex.unlock(); // <-- what's missing here?
// Sleep to give the other tasks a chance to run in the meantime.
// We do this here only to make nondeterminism more visible.
io.sleep(std.Io.Duration.fromMilliseconds(1), .awake) catch {};
// What happens if you neglect to lock the mutex?
state.counter += 1;
}
}

View File

@@ -1,35 +0,0 @@
//
// You have doubtless noticed that 'suspend' requires a block
// expression like so:
//
// suspend {}
//
// The suspend block executes when a function suspends. To get
// sense for when this happens, please make the following
// program print the string
//
// "ABCDEF"
//
const print = @import("std").debug.print;
pub fn main() void {
print("A", .{});
var frame = async suspendable();
print("X", .{});
resume frame;
print("F", .{});
}
fn suspendable() void {
print("X", .{});
suspend {
print("X", .{});
}
print("X", .{});
}

62
exercises/092_async8.zig Normal file
View File

@@ -0,0 +1,62 @@
//
// Tasks often need to communicate! Io provides Queue for this —
// a bounded, thread-safe channel for passing data between tasks:
//
// var backing: [16]u32 = undefined;
// var queue: std.Io.Queue(u32) = .init(&backing);
//
// // Producer task:
// try queue.putOne(io, value); // blocks if queue is full
//
// // Consumer task:
// const val = try queue.getOne(io); // blocks if queue is empty
//
// When the producer is done, it calls queue.close(io) to signal
// that no more data is coming. After that, getOne() will return
// error.Closed once the queue is drained.
//
// This is the classic producer/consumer pattern — one task
// generates work, another processes it, and the queue handles
// all the synchronization automatically.
//
// Fix this program: the producer sends numbers 1..10, the
// consumer sums them up. The expected sum is 55.
//
const std = @import("std");
const print = std.debug.print;
pub fn main(init: std.process.Init) !void {
const io = init.io;
var backing: [4]u32 = undefined;
var queue: std.Io.Queue(u32) = .init(&backing);
var group: std.Io.Group = .init;
group.async(io, producer, .{ io, &queue });
group.async(io, consumer, .{ io, &queue });
try group.await(io);
}
fn producer(io: std.Io, queue: *std.Io.Queue(u32)) void {
// Send numbers 1 through 10 into the queue.
for (1..11) |i| {
// What Queue method sends a single element, blocking if full?
queue.???(io, @intCast(i)) catch return;
}
// Signal that we're done sending.
queue.close(io);
}
fn consumer(io: std.Io, queue: *std.Io.Queue(u32)) void {
var sum: u32 = 0;
while (true) {
const value = queue.getOne(io) catch |err| switch (err) {
error.Closed => break,
error.Canceled => return,
};
sum += value;
}
print("Sum of 1..10 = {}\n", .{sum});
}

109
exercises/093_async9.zig Normal file
View File

@@ -0,0 +1,109 @@
//
// We've been using io.async() to launch tasks. But there's a
// stronger variant: io.concurrent().
//
// The difference:
//
// io.async():
// * The function MAY run on a separate unit of concurrency,
// or it may run immediately on the caller (synchronously).
// * Never fails — if no concurrency is available, it just
// runs the function right away.
// * More portable, works with all Io backends.
//
// io.concurrent():
// * GUARANTEES a separate unit of concurrency.
// * Can fail with error.ConcurrencyUnavailable if resources
// are exhausted or the backend doesn't support it.
// * Use when you NEED the task to run independently of the
// caller.
//
// What is a "unit of concurrency"? That depends on the backend!
// The Threaded backend uses OS threads. But the Evented backends
// (Uring, Kqueue, Dispatch) use M:N green threads / fibers,
// which can provide concurrency even on a SINGLE OS thread.
// Your code doesn't need to know the difference.
//
// Because concurrent() can fail, you must handle the error:
//
// var future = try io.concurrent(myFn, .{args});
// defer _ = future.cancel(io);
// const result = future.await(io);
//
// Let's try a slightly simplified example from signal processing:
// Suppose we're looking for the beginning of a signal above the noise
// level. To do this, we compare each entry from beginning to end with
// the threshold. To speed things up a bit, we split the signal into
// two halves and have two parallel workers search for them.
// Who finds the beginning first "wins" and thus ends the other one.
//
// As I said, this is a simplified explanation,
// but in practice it's done more or less like this.
//
const std = @import("std");
const Io = std.Io;
const print = std.debug.print;
const SearchResult = struct {
found: bool,
worker_id: u8 = 0,
index: usize = 0,
};
pub fn main(init: std.process.Init) !void {
const io = init.io;
const data = [_]u32{ 10, 23, 45, 67, 12, 69, 3, 54, 69, 42, 68, 56, 71, 79, 79, 75, 70, 77 };
const threshold = 70;
const mid = data.len / 2;
// A queue with space for one result.
var buf: [1]SearchResult = undefined;
var queue = Io.Queue(SearchResult).init(&buf);
// Launch two workers, each searching half the array.
// Remember, we want them to be guaranteed separate units of concurrency.
var f1 = ???(searchThreshold, .{ io, data[0..mid], threshold, 0, 0, &queue });
defer _ = f1.cancel(io);
var f2 = ???(searchThreshold, .{ io, data[mid..], threshold, mid, 1, &queue });
defer _ = f2.cancel(io);
// Wait for the first result.
const result = try queue.getOne(io);
if (result.found)
print("Worker {} found signal start over threshold at index {}!\n", .{ result.worker_id, result.index });
}
fn searchThreshold(
io: Io,
slice: []const u32,
threshold: u32,
base_offset: usize,
worker_id: u8,
queue: *Io.Queue(SearchResult),
) void {
for (slice, 0..) |val, i| {
// This pause is necessary so that the process can be canceled
// if another one has already finished. Without this pause,
// all workers would continue until the end.
io.sleep(Io.Duration.fromMilliseconds(1), .awake) catch return;
// To test this, you can uncomment this to view the work of the workers
// and then comment out the pause.
// print("id: {} - val: {}\n", .{ worker_id, val });
if (val >= threshold) {
queue.putOne(io, .{
.found = true,
.worker_id = worker_id,
.index = base_offset + i,
}) catch return;
return;
}
}
// Nothing found
queue.putOneUncancelable(io, .{ .found = false }) catch return;
}

68
exercises/094_async10.zig Normal file
View File

@@ -0,0 +1,68 @@
//
// In exercise 089, we learned that cancellation happens at
// "cancellation points" — any Io function that can return
// error.Canceled.
//
// But sometimes a task has a critical section that MUST NOT
// be interrupted — for example, writing a consistent state
// to disk, or completing a transaction.
//
// Io provides CancelProtection for this:
//
// const old = io.swapCancelProtection(.blocked);
// defer _ = io.swapCancelProtection(old);
// // In this block, NO Io function will return error.Canceled.
// // The cancel request is held until protection is restored.
//
// There are two states:
// .unblocked — normal: cancellation points can fire (default)
// .blocked — protected: error.Canceled is never returned
//
// There's also io.checkCancel() — a pure cancellation point
// that does nothing except return error.Canceled if a cancel
// request is pending. Useful in long CPU-bound loops.
//
// And io.recancel() — re-arms a consumed cancel request so
// the NEXT cancellation point will fire again.
//
// Fix this program so the critical section completes even
// when the task is canceled.
//
const std = @import("std");
const print = std.debug.print;
pub fn main(init: std.process.Init) !void {
const io = init.io;
var future = io.async(importantTask, .{io});
defer _ = future.cancel(io);
// Give the task time to start and enter its critical section.
io.sleep(std.Io.Duration.fromMilliseconds(200), .awake) catch {};
// Cancel while the task is in its protected section.
const result = future.cancel(io);
print("Task result: {s}\n", .{result});
}
fn importantTask(io: std.Io) []const u8 {
print("Starting critical section...\n", .{});
// Protect this section from cancellation.
// What method swaps the cancel protection state?
const old = io.???(.blocked);
defer _ = io.???(old);
// This sleep will NOT return error.Canceled even though
// we get canceled during it — protection is active!
io.sleep(std.Io.Duration.fromMilliseconds(300), .awake) catch |err| switch (err) {
error.Canceled => {
// This should never happen while protected!
return "ERROR: canceled during critical section!";
},
};
print("Critical section completed safely.\n", .{});
return "All data saved.";
}

View File

@@ -0,0 +1,187 @@
//
// Quiz Time — Async I/O!
//
// Doctor Zoraptera's insect simulation is going well, but she
// realized that her virtual garden needs weather data! Insects
// behave differently depending on temperature, humidity, and
// wind conditions.
//
// She has set up three weather sensors around the garden that
// measure conditions in parallel and report their readings
// through a shared data channel. A collector task gathers the
// readings, and after all sensors have reported, a garden
// report is printed.
//
// But Doctor Z rushed through the code (she was being chased
// by a grasshopper) and left several bugs. Can you fix them?
//
// Here's what the program should do:
// 1. Three sensor tasks send exactly 3 readings each through
// a Queue
// 2. A collector task receives readings concurrently,
// protected by a Mutex
// 3. After all sensors finish, the queue is closed
// 4. The final report is written in a cancel-protected section
//
// *************************************************************
// * A NOTE ABOUT THIS EXERCISE *
// * *
// * This quiz uses concepts from exercises 085-094. *
// * There are 6 bugs to fix — look for the ???s! *
// * *
// *************************************************************
//
const std = @import("std");
const print = std.debug.print;
const SensorType = enum { thermometer, hygrometer, anemometer };
const Reading = struct {
sensor_type: SensorType,
value: i32,
};
const GardenWeather = struct {
temperature: i32 = 0,
humidity: i32 = 0,
wind: i32 = 0,
readings_count: u32 = 0,
mutex: std.Io.Mutex = .init,
fn addReading(self: *GardenWeather, io: std.Io, reading: Reading) void {
// Bug 1: The collector needs to lock before modifying
// shared state. What Mutex method acquires the lock?
self.mutex.???(io) catch return;
defer self.mutex.unlock(io);
switch (reading.sensor_type) {
.thermometer => self.temperature = reading.value,
.hygrometer => self.humidity = reading.value,
.anemometer => self.wind = reading.value,
}
self.readings_count += 1;
}
};
pub fn main(init: std.process.Init) !void {
const io = init.io;
var weather = GardenWeather{};
var reading_buf: [8]Reading = undefined;
var queue: std.Io.Queue(Reading) = .init(&reading_buf);
// The collector must run concurrently so it can process
// readings while the sensors are still sending.
// Start it FIRST to ensure its concurrency unit is reserved.
//
// Bug 2: The collector needs guaranteed concurrency.
// What method ensures a separate unit of concurrency?
// (Don't forget: it can fail!)
var collector_future = try io.???(collector, .{ io, &queue, &weather });
defer _ = collector_future.cancel(io);
// Sensor group: the sensors can use async — they just need
// to run, and async is more portable.
var sensors: std.Io.Group = .init;
sensors.async(io, sensor, .{ io, &queue, .thermometer, 20 });
sensors.async(io, sensor, .{ io, &queue, .hygrometer, 60 });
sensors.async(io, sensor, .{ io, &queue, .anemometer, 10 });
// Bug 3: Wait for ALL sensors to finish sending their readings.
// What Group method blocks until all tasks complete?
try sensors.???(io);
// All sensors done — close the queue so the collector knows
// there's no more data coming.
queue.close(io);
// Bug 4: How do we wait for the collector to drain the remaining queue?
_ = collector_future.???(io);
// Now write the garden report. This is critical — it must
// NOT be interrupted, even if something tries to cancel us!
//
// Bug 5: Protect this section from cancellation.
// What Io method swaps the cancel protection state?
const old_protection = io.???(.blocked);
defer _ = io.???(old_protection);
printGardenReport(&weather);
}
fn sensor(
io: std.Io,
queue: *std.Io.Queue(Reading),
sensor_type: SensorType,
base_value: i32,
) void {
// Each sensor takes exactly 3 measurements.
for (1..4) |i| {
io.sleep(std.Io.Duration.fromMilliseconds(100), .awake) catch return;
const reading = Reading{
.sensor_type = sensor_type,
.value = base_value + @as(i32, @intCast(i)),
};
// Bug 6: Send the reading into the queue.
// What Queue method sends a single element?
queue.???(io, reading) catch return;
}
}
fn collector(
io: std.Io,
queue: *std.Io.Queue(Reading),
weather: *GardenWeather,
) void {
while (true) {
const reading = queue.getOne(io) catch |err| switch (err) {
error.Closed => break,
error.Canceled => return,
};
weather.addReading(io, reading);
}
}
fn printGardenReport(weather: *GardenWeather) void {
print("=== Doctor Zoraptera's Garden Report ===\n", .{});
print("Temperature : {}C\n", .{weather.temperature});
print("Humidity : {}%\n", .{weather.humidity});
print("Wind : {} km/h\n", .{weather.wind});
print("Readings : {}\n", .{weather.readings_count});
if (weather.temperature > 20 and weather.wind < 15) {
print("Bee-friendly conditions! Expect high pollination.\n", .{});
} else {
print("Grasshoppers will be grumpy today.\n", .{});
}
}
// Further reading for the curious:
//
// This quiz covered the main async I/O primitives:
// io.async() - launch a task (may run inline)
// io.concurrent() - guaranteed unit of concurrency
// Future.await/cancel - collect or cancel a single task
// Group.async/await/cancel - manage fire-and-forget tasks
// Select.async/await - race tasks, act on first completion
// Queue - bounded channel between tasks
// Mutex - protect shared state
// CancelProtection - shield critical sections
//
// There are more synchronization primitives we didn't cover:
// Condition - wait for a condition to become true
// RwLock - multiple readers OR one writer
// Semaphore - limit concurrent access to a resource
// Futex - low-level wait/wake on a memory address
// Batch - submit multiple I/O operations at once
//
// The key insight: all of these work through the Io VTable,
// so your code is portable across backends — whether Threaded
// (OS thread pool), or Evented (M:N green threads / fibers
// that can provide concurrency even on a single OS thread).
//
// Doctor Zoraptera approves.

View File

@@ -28,7 +28,9 @@
// 0..10 is a range from 0 to 9
// 1..4 is a range from 1 to 3
//
// At the moment, ranges are only supported in 'for' loops.
// Crucially, the end value is EXCLUSIVE.
//
// At the moment, ranges in loops are only supported in 'for' loops.
//
// Perhaps you recall Exercise 13? We were printing a numeric
// sequence like so:
@@ -64,6 +66,12 @@ pub fn main() void {
}
std.debug.print("\n", .{});
// Let's also print every number from 1 through 15
for (???) |n| {
std.debug.print("{} ", .{n});
}
std.debug.print("\n", .{});
}
//
// That's a bit nicer, right?

View File

@@ -71,9 +71,9 @@ const print = std.debug.print;
pub fn main() !void {
// As in the example above, we use 1 and 0 as values for x and y
var x: u8 = 1;
var y: u8 = 0;
// Let us use 1101 and 1011 as values for x and y
var x: u8 = 0b1101;
var y: u8 = 0b1011;
// Now we swap the values of the two variables by doing xor on them
x ^= y;
@@ -82,7 +82,7 @@ pub fn main() !void {
// What must be written here?
???;
print("x = {d}; y = {d}\n", .{ x, y });
print("x = {b}; y = {b}\n", .{ x, y });
}
// This variable swap takes advantage of the fact that the value resulting
@@ -93,3 +93,12 @@ pub fn main() !void {
//
// For Crypto it is better not to use this, but in sorting algorithms like
// Bubble Sort it works very well.
//
// By the way, congratulations for making it to Exercise 100!
//
// +-------------+
// | Celebration |
// | Area * * * |
// +-------------+
//
// Please keep your celebrating within the area provided.

View File

@@ -32,7 +32,7 @@ const print = std.debug.print;
pub fn main() !void {
// let's check the pangram
print("Is this a pangram? {?}!\n", .{isPangram("The quick brown fox jumps over the lazy dog.")});
print("Is this a pangram? {}!\n", .{isPangram("The quick brown fox jumps over the lazy dog.")});
}
fn isPangram(str: []const u8) bool {
@@ -45,7 +45,7 @@ fn isPangram(str: []const u8) bool {
// loop about all characters in the string
for (str) |c| {
// if the character is an alphabetical character
if (ascii.isASCII(c) and ascii.isAlphabetic(c)) {
if (ascii.isAscii(c) and ascii.isAlphabetic(c)) {
// then we set the bit at the position
//
// to do this, we use a little trick:

View File

@@ -13,10 +13,10 @@
// no official documentation for standard library features such
// as string formatting.
//
// Therefore, the comments for the format() function are the only
// Therefore, the comments for the print() function are the only
// way to definitively learn how to format strings in Zig:
//
// https://github.com/ziglang/zig/blob/master/lib/std/fmt.zig#L29
// https://ziglang.org/documentation/master/std/#std.Io.Writer.print
//
// Zig already has a very nice selection of formatting options.
// These can be used in different ways, but generally to convert
@@ -56,11 +56,11 @@
// the placeholder will determine how the corresponding value,
// e.g. foo, is displayed.
//
// And this is where it gets exciting, because format() accepts a
// And this is where it gets exciting, because print() accepts a
// variety of formatting instructions. It's basically a tiny
// language of its own. Here's a numeric example:
//
// print("Catch-{x:0>4}.", .{twenty_two});
// print("Catch-0x{x:0>4}.", .{twenty_two});
//
// This formatting instruction outputs a hexadecimal number with
// leading zeros:

View File

@@ -41,22 +41,13 @@ pub fn main() void {
for (hex_nums, ???) |hn, ???| {
if (hn != dn) {
std.debug.print("Uh oh! Found a mismatch: {d} vs {d}\n", .{ hn, dn });
print("Uh oh! Found a mismatch: {d} vs {d}\n", .{ hn, dn });
return;
}
}
std.debug.print("Arrays match!\n", .{});
print("Arrays match!\n", .{});
}
//
// You are perhaps wondering what happens if one of the two lists
// is longer than the other? Try it!
//
// By the way, congratulations for making it to Exercise 100!
//
// +-------------+
// | Celebration |
// | Area * * * |
// +-------------+
//
// Please keep your celebrating within the area provided.

View File

@@ -37,63 +37,48 @@
const std = @import("std");
const testing = std.testing;
// This is a simple function
// that builds a sum from the
// passed parameters and returns.
// This is a simple function that builds a sum from the passed parameters and
// returns.
fn add(a: f16, b: f16) f16 {
return a + b;
}
// The associated test.
// It always starts with the keyword "test",
// followed by a description of the tasks
// of the test. This is followed by the
// test cases in curly brackets.
// The associated test. It always starts with the keyword "test", followed by a
// description of the tasks of the test. This is followed by the test cases in
// curly brackets.
test "add" {
// The first test checks if the sum
// of '41' and '1' gives '42', which
// is correct.
// The first test checks if the sum of '41' and '1' gives '42', which is
// correct.
try testing.expect(add(41, 1) == 42);
// Another way to perform this test
// is as follows:
try testing.expectEqual(add(41, 1), 42);
// Another way to perform this test is as follows:
try testing.expectEqual(42, add(41, 1));
// This time a test with the addition
// of a negative number:
// This time a test with the addition of a negative number:
try testing.expect(add(5, -4) == 1);
// And a floating point operation:
try testing.expect(add(1.5, 1.5) == 3);
}
// Another simple function
// that returns the result
// of subtracting the two
// Another simple function that returns the result of subtracting the two
// parameters.
fn sub(a: f16, b: f16) f16 {
return a - b;
}
// The corresponding test
// is not much different
// from the previous one.
// Except that it contains
// an error that you need
// to correct.
// The corresponding test is not much different from the previous one. Except
// that it contains an error that you need to correct.
test "sub" {
try testing.expect(sub(10, 5) == 6);
try testing.expect(sub(3, 1.5) == 1.5);
}
// This function divides the
// numerator by the denominator.
// Here it is important that the
// denominator must not be zero.
// This is checked and if it
// occurs an error is returned.
// This function divides the numerator by the denominator. Here it is important
// that the denominator must not be zero. This is checked and if it occurs an
// error is returned.
fn divide(a: f16, b: f16) !f16 {
if (b == 0) return error.DivisionByZero;
return a / b;
@@ -105,8 +90,7 @@ test "divide" {
try testing.expect(divide(10, 2) catch unreachable == 5);
try testing.expect(divide(1, 3) catch unreachable == 0.3333333333333333);
// Now we test if the function returns an error
// if we pass a zero as denominator.
// But which error needs to be tested?
// Now we test if the function returns an error if we pass a zero as
// denominator. But which error needs to be tested?
try testing.expectError(error.???, divide(15, 0));
}

View File

@@ -1,92 +0,0 @@
//
// 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?

View File

@@ -2,7 +2,7 @@
// The functionality of the standard library is becoming increasingly
// 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. In addition these
// 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.
@@ -14,7 +14,7 @@
// exercises.
//
// A nice example of this has been published on the Zig homepage,
// replacing the somewhat dusty 'Hello world!
// replacing the somewhat dusty 'Hello world!'
//
// Nothing against 'Hello world!', but it just doesn't do justice
// to the elegance of Zig and that's a pity, if someone takes a short,
@@ -24,8 +24,7 @@
// suited to understand the basic principles.
//
// In the following exercises we will also read and process data from
// large files and at the latest then it will be clear to everyone how
// useful all this is.
// large files, it will then be clearer to you how useful all this is.
//
// Let's start with the analysis of the example from the Zig homepage
// and explain the most important things.
@@ -48,15 +47,14 @@
// // In order to be able to process the input values,
// // memory is required. An allocator is defined here for
// // this purpose.
// const ally = std.testing.allocator;
// const gpa = std.testing.allocator;
//
// // The allocator is used to initialize an array into which
// // the numbers are stored.
// var list = std.ArrayList(u32).init(ally);
// // An array into which the numbers are stored is initialized.
// var list: std.ArrayList(u32) = .empty;
//
// // This way you can never forget what is urgently needed
// // and the compiler doesn't grumble either.
// defer list.deinit();
// defer list.deinit(gpa);
//
// // Now it gets exciting:
// // A standard tokenizer is called (Zig has several) and
@@ -73,7 +71,7 @@
// const n = try parseInt(u32, num, 10);
//
// // Finally the individual values are stored in the array.
// try list.append(n);
// try list.append(gpa, n);
// }
//
// // For the subsequent test, a second static array is created,
@@ -119,9 +117,9 @@
// after all we need some practice. Suppose we want to count the words
// of this little poem:
//
// My name is Ozymandias, King of Kings;
// Look on my Works, ye Mighty, and despair!
// by Percy Bysshe Shelley
// My name is Ozymandias, King of Kings;
// Look on my Works, ye Mighty, and despair!
// by Percy Bysshe Shelley
//
//
const std = @import("std");

View File

@@ -1,52 +0,0 @@
//
// 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
});
}

View File

@@ -1,31 +1,22 @@
//
// 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.
// In Exercises 84-91, we learned about Zig's Io interface for
// concurrent execution: io.async(), Group, Select, and Futures.
// Under the hood, the Threaded backend manages a pool of real
// OS threads for you - including scheduling, cancellation, and
// resource cleanup.
//
// 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.
// But sometimes you need direct control over threads:
// * Long-lived dedicated workers
// * Specific stack sizes or thread counts
// * Code that doesn't have an Io interface available
// * Fine-grained synchronization patterns
//
// 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.
// That's where std.Thread comes in. It gives you a raw OS thread
// that you spawn, manage, and join yourself. No pool, no Futures,
// no automatic cancellation - but full control.
//
// 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.
// The following diagram roughly illustrates the difference between
// the various types of process execution:
//
//
// Synchronous Asynchronous
@@ -106,7 +97,9 @@ pub fn main() !void {
// 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);
var io_instance: std.Io.Threaded = .init_single_threaded;
const io = io_instance.io();
try io.sleep(std.Io.Duration.fromMilliseconds(400), .awake);
std.debug.print("Some weird stuff, after starting the threads.\n", .{});
}
// After we have left the closed area, we wait until
@@ -116,15 +109,17 @@ pub fn main() !void {
// 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." });
fn thread_function(id: usize) !void {
var io_instance: std.Io.Threaded = .init_single_threaded;
const io = io_instance.io();
try io.sleep(std.Io.Duration.fromMilliseconds(100 * @as(isize, @intCast(id))), .awake);
std.debug.print("thread {d}: {s}\n", .{ id, "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);
const work_time = 300 * ((5 - id % 3) - 2);
try io.sleep(std.Io.Duration.fromMilliseconds(@intCast(work_time)), .awake);
std.debug.print("thread {d}: {s}\n", .{ num, "finished." });
std.debug.print("thread {d}: {s}\n", .{ id, "finished." });
}
// This is the easiest way to run threads in parallel.
// In general, however, more management effort is required,

View File

@@ -21,9 +21,9 @@
// 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
// formula, which was published by Leibniz in 1682 in the journal
// "Acta Eruditorum".
// This is why this method has become known as the "Leibnitz series",
// This is why this method has become known as the "Leibniz 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:
@@ -39,7 +39,7 @@
// 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
// 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
@@ -50,7 +50,7 @@
// 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
// As we have already discovered, the Leibniz 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
@@ -105,3 +105,6 @@ fn thread_pi(pi: *f64, begin: u64, end: u64) !void {
//
// And you should remove the formatting restriction in "print",
// otherwise you will not be able to see the additional digits.
//
// If count = 10_000_000_000_000 you should see the following:
// 3.141592653589

102
exercises/109_files.zig Normal file
View File

@@ -0,0 +1,102 @@
//
// Until now, we've only been printing our output in the console,
// which is good enough for fighting aliens and hermit bookkeeping.
//
// However, many other tasks require some interaction with the file system,
// which is the underlying structure for organizing files on your computer.
//
// The file system provides a hierarchical structure for storing files
// by organizing them into directories, which hold files and other directories,
// thus creating a tree structure that can be navigated.
//
// Fortunately, the Zig Standard Library provides a simple API for interacting
// with the file system, see the detail documentation here:
//
// https://ziglang.org/documentation/master/std/#std.Io
//
// In this exercise, we'll try to:
// - create a new directory,
// - open a file in the directory,
// - write to the file.
//
// Note: For simplicity, we write byte-by-byte without buffering.
// In real applications, you'd typically use a buffer for better
// performance. We'll learn about buffered I/O in a later exercise.
//
const std = @import("std");
pub fn main(init: std.process.Init) !void {
// default I/O implementation
const io = init.io;
// first we get the current working directory
const cwd: std.Io.Dir = std.Io.Dir.cwd();
// then we'll try to make a new directory /output/
// to store our output files.
cwd.createDir(io, "output", .default_dir) catch |e| switch (e) {
// there is a chance you might want to run this
// program more than once and the path might already
// have been created, so we'll have to handle this error
// by doing nothing
//
// we want to catch error.PathAlreadyExists and do nothing
??? => {},
// if there's 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.Io.Dir = try cwd.openDir(io, "output", .{});
defer output_dir.close(io);
// we try to open the file `zigling.txt`,
// and propagate any error up
const file: std.Io.File = try output_dir.createFile(io, "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
// allowed you to "defer" code execution to the end of the scope...
file.close(io);
// you are not allowed to move these lines above the file closing line!
var file_writer = file.writer(io, &.{});
const writer = &file_writer.interface;
const byte_written = try writer.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 in your text editor, or
// 2. print the content of the file in the console with one of these commands
// Linux/macOS: >> cat ./output/zigling.txt
// Windows (CMD): >> type .\output\zigling.txt
//
//
// More on Creating files
//
// notice in:
// ... try output_dir.createFile(io, "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 the documentation of the struct `std.Io.Dir` here:
// https://ziglang.org/documentation/master/std/#std.Io.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?

61
exercises/110_files2.zig Normal file
View File

@@ -0,0 +1,61 @@
//
// Prerequisite :
// - exercise/109_files.zig, or
// - create a file {project_root}/output/zigling.txt
// with content `It's zigling time!`(18 bytes total)
//
// Now there's 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 initialize an array of characters with all letter 'A', and print it
// - After that, we read the content of the file into the array
// - Finally, we print out the content we just read
//
// Note: For simplicity, we read byte-by-byte without buffering.
// In real applications, you'd typically use a buffer for better
// performance. We'll learn about buffered I/O in a later exercise.
const std = @import("std");
pub fn main(init: std.process.Init) !void {
const io = init.io;
// Get the current working directory
const cwd = std.Io.Dir.cwd();
// try to open ./output assuming you did your 109_files exercise
var output_dir = try cwd.openDir(io, "output", .{});
defer output_dir.close(io);
// try to open the file
const file = try output_dir.openFile(io, "zigling.txt", .{});
defer file.close(io);
// initialize an array of u8 entirely with the letter 'A'
// we need to pick the size of the array, 64 seems like a good number
// do you remember the array repetition function?
var content: ??? = ???('A');
// this should print out : `AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA`
std.debug.print("{s}\n", .{content});
var file_reader = file.reader(io, &.{});
const reader = &file_reader.interface;
// 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.Io.Reader
// hint: look for a method that reads into a slice
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
});
}

View File

@@ -0,0 +1,79 @@
//
// You've heard of while loops in exercises 011,012,013 and 014
// You've also heard of switch expressions in exercises 030 and 31.
// You've also seen how labels can be used in exercise 063.
//
// By combining while loops and switch statements with continue and break statements
// one can create very concise State Machines.
//
// One such example would be:
//
// pub fn main() void {
// var op: u8 = 1;
// while (true) {
// switch (op) {
// 1 => { op = 2; continue; },
// 2 => { op = 3; continue; },
// 3 => return,
// else => {},
// }
// break;
// }
// std.debug.print("This statement cannot be reached\n", .{});
// }
//
// By combining all we've learned so far, we can now proceed with a labeled switch.
//
// A labeled switch is some extra syntactic sugar, which comes with all sorts of
// candy (performance benefits). Don't believe me? Directly to source https://github.com/ziglang/zig/pull/21367
//
// Here is the previous excerpt implemented as a labeled switch instead:
//
// pub fn main() void {
// foo: switch (@as(u8, 1)) {
// 1 => continue :foo 2,
// 2 => continue :foo 3,
// 3 => return,
// else => {},
// }
// std.debug.print("This statement cannot be reached\n", .{});
// }
//
// The flow of execution on this second case is:
// 1. The switch starts with value '1';
// 2. The switch evaluates to case '1' which in turn uses the continue statement
// to re-evaluate the labeled switch again, now providing the value '2';
// 3. In the case '2' we repeat the same pattern as case '1'
// but instead the value to be evaluated is now '3';
// 4. Finally we get to case '3', where we return from the function as a whole,
// so the debug statement is never executed.
// 5. In this example, since the input does not have clear, exhaustive patterns and
// can essentially be any 'u8' integer, we need to handle all cases not explicitly
// covered by using the 'else => {}' branch as the default case.
//
//
const std = @import("std");
const PullRequestState = enum(u8) {
Draft,
InReview,
Approved,
Rejected,
Merged,
};
pub fn main() void {
// Oh no, your pull request keeps being rejected,
// how would you fix it?
pr: switch (PullRequestState.Draft) {
PullRequestState.Draft => continue :pr PullRequestState.InReview,
PullRequestState.InReview => continue :pr PullRequestState.Rejected,
PullRequestState.Approved => continue :pr PullRequestState.Merged,
PullRequestState.Rejected => {
std.debug.print("The pull request has been rejected.\n", .{});
return;
},
PullRequestState.Merged => break, // Would you know where to break to?
}
std.debug.print("The pull request has been merged.\n", .{});
}

147
exercises/112_vectors.zig Normal file
View File

@@ -0,0 +1,147 @@
// So far in Ziglings, we've seen how for loops can be used to
// repeat calculations across an array in several ways.
//
// For loops are generally great for this kind of task, but
// sometimes they don't fully utilize the capabilities of the
// CPU.
//
// Most modern CPUs can execute instructions in which SEVERAL
// calculations are performed WITHIN registers at the SAME TIME.
// These are known as "single instruction, multiple data" (SIMD)
// instructions. SIMD instructions can make code significantly
// more performant.
//
// To see why, imagine we have a program in which we take the
// square root of four (changing) f32 floats.
//
// A simple compiler would take the program and produce machine code
// which calculates each square root sequentially. Most registers on
// modern CPUs have 64 bits, so we could imagine that each float moves
// into a 64-bit register, and the following happens four times:
//
// 32 bits 32 bits
// +-------------------+
// register | 0 | x |
// +-------------------+
//
// |
// [SQRT instruction]
// V
//
// +-------------------+
// | 0 | sqrt(x) |
// +-------------------+
//
// Notice that half of the register contains blank data to which
// nothing happened. What a waste! What if we were able to use
// that space instead? This is the idea at the core of SIMD.
//
// Most modern CPUs contain specialized registers with at least 128 bits
// for performing SIMD instructions. On a machine with 128-bit SIMD
// registers, a smart compiler would probably NOT issue four sqrt
// instructions as above, but instead pack the floats into a single
// 128-bit register, then execute a single "packed" sqrt
// instruction to do ALL the square root calculations at once.
//
// For example:
//
//
// 32 bits 32 bits 32 bits 32 bits
// +---------------------------------------+
// register | 4.0 | 9.0 | 25.0 | 49.0 |
// +---------------------------------------+
//
// |
// [SIMD SQRT instruction]
// V
//
// +---------------------------------------+
// register | 2.0 | 3.0 | 5.0 | 7.0 |
// +---------------------------------------+
//
// Pretty cool, right?
//
// Code with SIMD instructions is usually more performant than code
// without SIMD instructions. Zig cares a lot about performance,
// so it has built-in support for SIMD! It has a data structure that
// directly supports SIMD instructions:
//
// +-----------+
// | Vectors |
// +-----------+
//
// Operations performed on vectors in Zig will be done in parallel using
// SIMD instructions, whenever possible.
//
// Defining vectors in Zig is straightforward. No library import is needed.
const v1 = @Vector(3, i32){ 1, 10, 100 };
const v2 = @Vector(3, f32){ 2.0, 3.0, 5.0 };
// Vectors support the same builtin operators as their underlying base types.
const v3 = v1 + v1; // { 2, 20, 200};
const v4 = v2 * v2; // { 4.0, 9.0, 25.0};
// Intrinsics that apply to base types usually extend to vectors.
const v5: @Vector(3, f32) = @floatFromInt(v3); // { 2.0, 20.0, 200.0}
const v6 = v4 - v5; // { 2.0, -11.0, -175.0}
const v7 = @abs(v6); // { 2.0, 11.0, 175.0}
// We can make constant vectors, and reduce vectors.
const v8: @Vector(4, u8) = @splat(2); // { 2, 2, 2, 2}
const v8_sum = @reduce(.Add, v8); // 8
const v8_min = @reduce(.Min, v8); // 2
// Fixed-length arrays can be automatically assigned to vectors (and vice-versa).
const single_digit_primes = [4]i8{ 2, 3, 5, 7 };
const prime_vector: @Vector(4, i8) = single_digit_primes;
// Now let's use vectors to simplify and optimize some code!
//
// Ewa is writing a program in which they frequently want to compare
// two lists of four f32s. Ewa expects the lists to be similar, and
// wants to determine the largest pairwise difference between the lists.
//
// Ewa wrote the following function to figure this out.
fn calcMaxPairwiseDiffOld(list1: [4]f32, list2: [4]f32) f32 {
var max_diff: f32 = 0;
for (list1, list2) |n1, n2| {
const abs_diff = @abs(n1 - n2);
if (abs_diff > max_diff) {
max_diff = abs_diff;
}
}
return max_diff;
}
// Ewa heard about vectors in Zig, and started writing a new vector
// version of the function, but has got stuck!
//
// Help Ewa finish the vector version! The examples above should help.
const Vec4 = @Vector(4, f32);
fn calcMaxPairwiseDiffNew(a: Vec4, b: Vec4) f32 {
const abs_diff_vec = ???;
const max_diff = @reduce(???, abs_diff_vec);
return max_diff;
}
// Quite the simplification! We could even write the function in one line
// and it would still be readable.
//
// Since the entire function is now expressed in terms of vector operations,
// the Zig compiler will easily be able to compile it down to machine code
// which utilizes the all-powerful SIMD instructions and does a lot of the
// computation in parallel.
const std = @import("std");
const print = std.debug.print;
pub fn main() void {
const l1 = [4]f32{ 3.141, 2.718, 0.577, 1.000 };
const l2 = [4]f32{ 3.154, 2.707, 0.591, 0.993 };
const mpd_old = calcMaxPairwiseDiffOld(l1, l2);
const mpd_new = calcMaxPairwiseDiffNew(l1, l2);
print("Max difference (old fn): {d: >5.3}\n", .{mpd_old});
print("Max difference (new fn): {d: >5.3}\n", .{mpd_new});
}

484
exercises/113_quiz9.zig Normal file
View File

@@ -0,0 +1,484 @@
// ----------------------------------------------------------------------------
// Quiz Time: Toggling, Setting, and Clearing Bits
// ----------------------------------------------------------------------------
//
// Another exciting thing about Zig is its suitability for embedded
// programming. Your Zig code doesn't have to remain on your laptop; you can
// also deploy your code to microcontrollers! This means you can write Zig to
// drive your next robot or greenhouse climate control system! Ready to enter
// the exciting world of embedded programming? Let's get started!
//
// ----------------------------------------------------------------------------
// Some Background
// ----------------------------------------------------------------------------
//
// A common activity in microcontroller programming is setting and clearing
// bits on input and output pins. This lets you control LEDs, sensors, motors
// and more! In a previous exercise (097_bit_manipulation.zig) you learned how
// to swap two bytes using the ^ (XOR - exclusive or) operator. This quiz will
// test your knowledge of bit manipulation in Zig while giving you a taste of
// what it's like to control registers in a real microcontroller. Included at
// the end are some helper functions that demonstrate how we might make our
// code a little more readable.
//
// Below is a pinout diagram for the famous ATmega328 AVR microcontroller used
// as the primary microchip on popular microcontroller platforms like the
// Arduino UNO.
//
// ============ PINOUT DIAGRAM FOR ATMEGA328 MICROCONTROLLER ============
// _____ _____
// | U |
// (RESET) PC6 --| 1 28 |-- PC5
// PD0 --| 2 27 |-- PC4
// PD1 --| 3 26 |-- PC3
// PD2 --| 4 25 |-- PC2
// PD3 --| 5 24 |-- PC1
// PD4 --| 6 23 |-- PC0
// VCC --| 7 22 |-- GND
// GND --| 8 21 |-- AREF
// |-- PB6 --| 9 20 |-- AVCC
// |-- PB7 --| 10 19 |-- PB5 --|
// | PD5 --| 11 18 |-- PB4 --|
// | PD6 --| 12 17 |-- PB3 --|
// | PD7 --| 13 16 |-- PB2 --|
// |-- PB0 --| 14 15 |-- PB1 --|
// | |___________| |
// \_______________________________/
// |
// PORTB
//
// Drawing inspiration from this diagram, we'll use the pins for PORTB as our
// mental model for this quiz on bit manipulation. It should be noted that
// in the following problems we are using ordinary variables, one of which we
// have named PORTB, to simulate modifying the bits of real hardware registers.
// But in actual microcontroller code, PORTB would be defined something like
// this:
// pub const PORTB = @as(*volatile u8, @ptrFromInt(0x25));
//
// This lets the compiler know not to make any optimizations to PORTB so that
// the IO pins are properly mapped to our code.
//
// NOTE : To keep things simple, the following problems are given using type
// u4, so applying the output to PORTB would only affect the lower four pins
// PB0..PB3. Of course, there is nothing to prevent you from swapping the u4
// with a u8 so you can control all 8 of PORTB's IO pins.
const std = @import("std");
const print = std.debug.print;
const testing = std.testing;
pub fn main() !void {
var PORTB: u4 = 0b0000; // only 4 bits wide for simplicity
// ------------------------------------------------------------------------
// Quiz
// ------------------------------------------------------------------------
// See if you can solve the following problems. The last two problems throw
// you a bit of a curve ball. Try solving them on your own. If you need
// help, scroll to the bottom of main to see some in depth explanations on
// toggling, setting, and clearing bits in Zig.
print("Toggle pins with XOR on PORTB\n", .{});
print("-----------------------------\n", .{});
PORTB = 0b1100;
print(" {b:0>4} // (initial state of PORTB)\n", .{PORTB});
print("^ {b:0>4} // (bitmask)\n", .{0b0101});
PORTB ^= (1 << 1) | (1 << 0); // What's wrong here?
checkAnswer(0b1001, PORTB);
newline();
PORTB = 0b1100;
print(" {b:0>4} // (initial state of PORTB)\n", .{PORTB});
print("^ {b:0>4} // (bitmask)\n", .{0b0011});
PORTB ^= (1 << 1) & (1 << 0); // What's wrong here?
checkAnswer(0b1111, PORTB);
newline();
print("Set pins with OR on PORTB\n", .{});
print("-------------------------\n", .{});
PORTB = 0b1001; // reset PORTB
print(" {b:0>4} // (initial state of PORTB)\n", .{PORTB});
print("| {b:0>4} // (bitmask)\n", .{0b0100});
PORTB = PORTB ??? (1 << 2); // What's missing here?
checkAnswer(0b1101, PORTB);
newline();
PORTB = 0b1001; // reset PORTB
print(" {b:0>4} // (reset state)\n", .{PORTB});
print("| {b:0>4} // (bitmask)\n", .{0b0100});
PORTB ??? (1 << 2); // What's missing here?
checkAnswer(0b1101, PORTB);
newline();
print("Clear pins with AND and NOT on PORTB\n", .{});
print("------------------------------------\n", .{});
PORTB = 0b1110; // reset PORTB
print(" {b:0>4} // (initial state of PORTB)\n", .{PORTB});
print("& {b:0>4} // (bitmask)\n", .{0b1011});
PORTB = PORTB & ???@as(u4, 1 << 2); // What character is missing here?
checkAnswer(0b1010, PORTB);
newline();
PORTB = 0b0111; // reset PORTB
print(" {b:0>4} // (reset state)\n", .{PORTB});
print("& {b:0>4} // (bitmask)\n", .{0b1110});
PORTB &= ~(1 << 0); // What's missing here?
checkAnswer(0b0110, PORTB);
newline();
newline();
}
// ************************************************************************
// IN-DEPTH EXPLANATIONS BELOW
// ************************************************************************
//
//
//
//
//
//
//
//
//
//
//
// ------------------------------------------------------------------------
// Toggling bits with XOR:
// ------------------------------------------------------------------------
// XOR stands for "exclusive or". We can toggle bits with the ^ (XOR)
// bitwise operator, like so:
//
//
// In order to output a 1, the logic of an XOR operation requires that the
// two input bits are of different values. Therefore, 0 ^ 1 and 1 ^ 0 will
// both yield a 1 but 0 ^ 0 and 1 ^ 1 will output 0. XOR's unique behavior
// of outputting a 0 when both inputs are 1s is what makes it different from
// the OR operator; it also gives us the ability to toggle bits by putting
// 1s into our bitmask.
//
// - 1s in our bitmask operand, can be thought of as causing the
// corresponding bits in the other operand to flip to the opposite value.
// - 0s cause no change.
//
// The 0s in our bitmask preserve these values
// -XOR op- ---expanded--- in the output.
// _______________/
// / /
// 1100 1 1 0 0
// ^ 0101 0 1 0 1 (bitmask)
// ------ - - - -
// = 1001 1 0 0 1 <- This bit was already cleared.
// \_______\
// \
// We can think of these bits having flipped
// because of the presence of 1s in those columns
// of our bitmask.
//
// Now let's take a look at setting bits with the | operator.
//
//
//
//
//
// ------------------------------------------------------------------------
// Setting bits with OR:
// ------------------------------------------------------------------------
// We can set bits on PORTB with the | (OR) operator, like so:
//
// var PORTB: u4 = 0b1001;
// PORTB = PORTB | 0b0010;
// print("PORTB: {b:0>4}\n", .{PORTB}); // output: 1011
//
// -OR op- ---expanded---
// _ Set only this bit.
// /
// 1001 1 0 0 1
// | 0010 0 0 1 0 (bitmask)
// ------ - - - -
// = 1011 1 0 1 1
// \___\_______\
// \
// These bits remain untouched because OR-ing with
// a 0 effects no change.
//
// ------------------------------------------------------------------------
// To create a bitmask like 0b0010 used above:
//
// 1. First, shift the value 1 over one place with the bitwise << (shift
// left) operator as indicated below:
// 1 << 0 -> 0001
// 1 << 1 -> 0010 <-- Shift 1 one place to the left
// 1 << 2 -> 0100
// 1 << 3 -> 1000
//
// This allows us to rewrite the above code like this:
//
// var PORTB: u4 = 0b1001;
// PORTB = PORTB | (1 << 1);
// print("PORTB: {b:0>4}\n", .{PORTB}); // output: 1011
//
// Finally, as in the C language, Zig allows us to use the |= operator, so
// we can rewrite our code again in an even more compact and idiomatic
// form: PORTB |= (1 << 1)
// So now we've covered how to toggle and set bits. What about clearing
// them? Well, this is where Zig throws us a curve ball. Don't worry we'll
// go through it step by step.
//
//
//
//
//
// ------------------------------------------------------------------------
// Clearing bits with AND and NOT:
// ------------------------------------------------------------------------
// We can clear bits with the & (AND) bitwise operator, like so:
// PORTB = 0b1110; // reset PORTB
// PORTB = PORTB & 0b1011;
// print("PORTB: {b:0>4}\n", .{PORTB}); // output -> 1010
//
// - 0s clear bits when used in conjunction with a bitwise AND.
// - 1s do nothing, thus preserving the original bits.
//
// -AND op- ---expanded---
// __________ Clear only this bit.
// /
// 1110 1 1 1 0
// & 1011 1 0 1 1 (bitmask)
// ------ - - - -
// = 1010 1 0 1 0 <- This bit was already cleared.
// \_______\
// \
// These bits remain untouched because AND-ing with a
// 1 preserves the original bit value whether 0 or 1.
//
// ------------------------------------------------------------------------
// We can use the ~ (NOT) operator to easily create a bitmask like 1011:
//
// 1. First, shift the value 1 over two places with the bit-wise << (shift
// left) operator as indicated below:
// 1 << 0 -> 0001
// 1 << 1 -> 0010
// 1 << 2 -> 0100 <- The 1 has been shifted two places to the left
// 1 << 3 -> 1000
//
// 2. The second step in creating our bitmask is to invert the bits
// ~0100 -> 1011
// in C we would write this as:
// ~(1 << 2) -> 1011
//
// But if we try to compile ~(1 << 2) in Zig, we'll get an error:
// unable to perform binary not operation on type 'comptime_int'
//
// Before Zig can invert our bits, it needs to know the number of
// bits it's being asked to invert.
//
// We do this with the @as (cast as) built-in like this:
// @as(u4, 1 << 2) -> 0100
//
// Finally, we can invert our new mask by placing the NOT ~ operator
// before our expression, like this:
// ~@as(u4, 1 << 2) -> 1011
//
// If you are offput by the fact that you can't simply invert bits like
// you can in languages such as C without casting to a particular size
// of integer, you're not alone. However, this is actually another
// instance where Zig is really helpful because it protects you from
// difficult to debug integer overflow bugs that can have you tearing
// your hair out. In the interest of keeping things sane, Zig requires
// you simply to tell it the size of number you are inverting. In the
// words of Andrew Kelley, "If you want to invert the bits of an
// integer, zig has to know how many bits there are."
//
// For more insight into the Zig team's position on why the language
// takes the approach it does with the ~ operator, take a look at
// Andrew's comments on the following github issue:
// https://github.com/ziglang/zig/issues/1382#issuecomment-414459529
//
// Whew, so after all that what we end up with is:
// PORTB = PORTB & ~@as(u4, 1 << 2);
//
// We can shorten this with the &= combined AND and assignment operator,
// which applies the AND operator on PORTB and then reassigns PORTB. Here's
// what that looks like:
// PORTB &= ~@as(u4, 1 << 2);
//
// ------------------------------------------------------------------------
// Conclusion
// ------------------------------------------------------------------------
//
// While the examples in this quiz have used only 4-bit wide variables,
// working with 8 bits is no different. Here's an example where we set
// every other bit beginning with the two's place:
// var PORTD: u8 = 0b0000_0000;
// print("PORTD: {b:0>8}\n", .{PORTD});
// PORTD |= (1 << 1);
// PORTD = setBit(u8, PORTD, 3);
// PORTD |= (1 << 5) | (1 << 7);
// print("PORTD: {b:0>8} // set every other bit\n", .{PORTD});
// PORTD = ~PORTD;
// print("PORTD: {b:0>8} // bits flipped with NOT (~)\n", .{PORTD});
// newline();
//
// // Here we clear every other bit beginning with the two's place.
//
// PORTD = 0b1111_1111;
// print("PORTD: {b:0>8}\n", .{PORTD});
// PORTD &= ~@as(u8, 1 << 1);
// PORTD = clearBit(u8, PORTD, 3);
// PORTD &= ~@as(u8, (1 << 5) | (1 << 7));
// print("PORTD: {b:0>8} // clear every other bit\n", .{PORTD});
// PORTD = ~PORTD;
// print("PORTD: {b:0>8} // bits flipped with NOT (~)\n", .{PORTD});
// newline();
// ----------------------------------------------------------------------------
// Here are some helper functions for manipulating bits
// ----------------------------------------------------------------------------
// Functions for setting, clearing, and toggling a single bit
fn setBit(comptime T: type, byte: T, comptime bit_pos: T) !T {
return byte | (1 << bit_pos);
}
test "setBit" {
try testing.expectEqual(setBit(u8, 0b0000_0000, 3), 0b0000_1000);
}
fn clearBit(comptime T: type, byte: T, comptime bit_pos: T) T {
return byte & ~@as(T, (1 << bit_pos));
}
test "clearBit" {
try testing.expectEqual(clearBit(u8, 0b1111_1111, 0), 0b1111_1110);
}
fn toggleBit(comptime T: type, byte: T, comptime bit_pos: T) T {
return byte ^ (1 << bit_pos);
}
test "toggleBit" {
var byte = toggleBit(u8, 0b0000_0000, 0);
try testing.expectEqual(byte, 0b0000_0001);
byte = toggleBit(u8, byte, 0);
try testing.expectEqual(byte, 0b0000_0000);
}
// ----------------------------------------------------------------------------
// Some additional functions for setting, clearing, and toggling multiple bits
// at once with a tuple because, hey, why not?
// ----------------------------------------------------------------------------
//
fn createBitmask(comptime T: type, comptime bits: anytype) !T {
comptime var bitmask: T = 0;
inline for (bits) |bit| {
if (bit >= @bitSizeOf(T)) return error.BitPosTooLarge;
if (bit < 0) return error.BitPosTooSmall;
bitmask |= (1 << bit);
}
return bitmask;
}
test "creating bitmasks from a tuple" {
try testing.expectEqual(createBitmask(u8, .{0}), 0b0000_0001);
try testing.expectEqual(createBitmask(u8, .{1}), 0b0000_0010);
try testing.expectEqual(createBitmask(u8, .{2}), 0b0000_0100);
try testing.expectEqual(createBitmask(u8, .{3}), 0b0000_1000);
//
try testing.expectEqual(createBitmask(u8, .{ 0, 4 }), 0b0001_0001);
try testing.expectEqual(createBitmask(u8, .{ 1, 5 }), 0b0010_0010);
try testing.expectEqual(createBitmask(u8, .{ 2, 6 }), 0b0100_0100);
try testing.expectEqual(createBitmask(u8, .{ 3, 7 }), 0b1000_1000);
try testing.expectError(error.BitPosTooLarge, createBitmask(u4, .{4}));
}
fn setBits(byte: u8, bits: anytype) !u8 {
const bitmask = try createBitmask(u8, bits);
return byte | bitmask;
}
test "setBits" {
try testing.expectEqual(setBits(0b0000_0000, .{0}), 0b0000_0001);
try testing.expectEqual(setBits(0b0000_0000, .{7}), 0b1000_0000);
try testing.expectEqual(setBits(0b0000_0000, .{ 0, 1, 2, 3, 4, 5, 6, 7 }), 0b1111_1111);
try testing.expectEqual(setBits(0b1111_1111, .{ 0, 1, 2, 3, 4, 5, 6, 7 }), 0b1111_1111);
try testing.expectEqual(setBits(0b0000_0000, .{ 2, 3, 4, 5 }), 0b0011_1100);
try testing.expectError(error.BitPosTooLarge, setBits(0b1111_1111, .{8}));
try testing.expectError(error.BitPosTooSmall, setBits(0b1111_1111, .{-1}));
}
fn clearBits(comptime byte: u8, comptime bits: anytype) !u8 {
const bitmask: u8 = try createBitmask(u8, bits);
return byte & ~@as(u8, bitmask);
}
test "clearBits" {
try testing.expectEqual(clearBits(0b1111_1111, .{0}), 0b1111_1110);
try testing.expectEqual(clearBits(0b1111_1111, .{7}), 0b0111_1111);
try testing.expectEqual(clearBits(0b1111_1111, .{ 0, 1, 2, 3, 4, 5, 6, 7 }), 0b000_0000);
try testing.expectEqual(clearBits(0b0000_0000, .{ 0, 1, 2, 3, 4, 5, 6, 7 }), 0b000_0000);
try testing.expectEqual(clearBits(0b1111_1111, .{ 0, 1, 6, 7 }), 0b0011_1100);
try testing.expectError(error.BitPosTooLarge, clearBits(0b1111_1111, .{8}));
try testing.expectError(error.BitPosTooSmall, clearBits(0b1111_1111, .{-1}));
}
fn toggleBits(comptime byte: u8, comptime bits: anytype) !u8 {
const bitmask = try createBitmask(u8, bits);
return byte ^ bitmask;
}
test "toggleBits" {
try testing.expectEqual(toggleBits(0b0000_0000, .{0}), 0b0000_0001);
try testing.expectEqual(toggleBits(0b0000_0000, .{7}), 0b1000_0000);
try testing.expectEqual(toggleBits(0b1111_1111, .{ 0, 1, 2, 3, 4, 5, 6, 7 }), 0b000_0000);
try testing.expectEqual(toggleBits(0b0000_0000, .{ 0, 1, 2, 3, 4, 5, 6, 7 }), 0b1111_1111);
try testing.expectEqual(toggleBits(0b0000_1111, .{ 0, 1, 2, 3, 4, 5, 6, 7 }), 0b1111_0000);
try testing.expectEqual(toggleBits(0b0000_1111, .{ 0, 1, 2, 3 }), 0b0000_0000);
try testing.expectEqual(toggleBits(0b0000_0000, .{ 0, 2, 4, 6 }), 0b0101_0101);
try testing.expectError(error.BitPosTooLarge, toggleBits(0b1111_1111, .{8}));
try testing.expectError(error.BitPosTooSmall, toggleBits(0b1111_1111, .{-1}));
}
// ----------------------------------------------------------------------------
// Utility functions
// ----------------------------------------------------------------------------
fn newline() void {
print("\n", .{});
}
fn checkAnswer(expected: u4, answer: u4) void {
if (expected != answer) {
print("*************************************************************\n", .{});
print("= {b:0>4} <- INCORRECT! THE EXPECTED OUTPUT IS {b:0>4}\n", .{ answer, expected });
print("*************************************************************\n", .{});
} else {
print("= {b:0>4}", .{answer});
}
newline();
}

175
exercises/114_packed.zig Normal file
View File

@@ -0,0 +1,175 @@
//
// We've already learned plenty about bit manipulation using bitwise operations
// in exercises 097 and 098 and in quiz 110. The techniques we already know work
// just fine, but creating masks and shifting individual bits around can become
// quite tedious and unwieldy pretty quickly.
// What if there was a better, a more convenient way to control individual bits?
//
// Luckily, Zig has a keyword for exactly this purpose:
//
// packed
//
// It doesn't do anything on its own, to unlock its potential (and to get our
// program to compile) we have to attach it either to a struct or to a union
// declaration:
//
// const Foo = packed struct { ... };
// const Bar = packed union { ... };
//
// Now, what does this keyword even do?
// To answer this question we first have to talk about *container layouts*.
//
// Plain structs and unions use the `auto` layout; it gives no guarantees about
// their size or the order of the fields they contain, both are fully up to the
// compiler (though both size and field order *are* guaranteed to be the same
// across any single compilation unit).
//
// Attaching the `packed` keyword to a container makes it use `packed` layout:
// Suddenly, all of its fields are *packed* together tightly without any padding
// in between and their order is guaranteed to be the same as the one specified
// in our source code. For structs, the size of the container is guaranteed to
// be the sum of the (bit-)sizes of all of its fields. For unions, all fields
// have to have the exact same (bit-)size (no padding allowed!); the union itself
// is also guaranteed to be exactly of this size.
//
// If you're familiar with C, you might have already heard of structure packing
// in a different context: arranging fields in a way that minimizes the amount
// of alignment padding between them (or having the compiler do it for you).
// This is *not* what Zig's `packed` keyword is for!
//
// Try to make the comptime assertions below pass:
const PackedStruct = packed struct {
a: u2,
b: u?,
};
comptime {
assert(@bitSizeOf(PackedStruct) == 6);
}
const PackedUnion = packed union {
a: bool,
b: u?,
};
comptime {
assert(@bitSizeOf(PackedUnion) == 1);
}
// Now, how can we use this new knowledge to manipulate some bits?
//
// As you might have already guessed, `packed` containers are very useful for
// representing bitflags or other tightly packed collections of bit-sized values
// often found in file headers and network protocols.
//
// Let's take a look at a real-life example:
// The LZ4 compression format (†) specifies a frame format to describe compressed
// data. Each LZ4 frame has a descriptor, and each descriptor contains a 'FLG'
// byte that specifies the contents of its frame:
/// | BitNb | 7-6 | 5 | 4 | 3 | 2 | 1 | 0 |
/// | ------- |-------|-------|----------|------|----------|--------|------|
/// |FieldName|Version|B.Indep|B.Checksum|C.Size|C.Checksum|Reserved|DictID|
///
const FLG = packed struct(u8) {
dict_id: bool,
reserved: u1 = 0,
content_checksum: bool,
content_size: bool,
block_checksum: bool,
block_indepencence: bool,
version: u2,
};
// Wait, what's with the `(u8)` after the `struct` keyword? What do integers have
// to do with all of this?
// Well, this is a good opportunity to come clear about something:
// packed structs and packed unions aren't actually structs or unions at all...
// They are merely integers in disguise! For all intents and purposes, their
// fields are just convenient names for ranges of their underlying bits. To make
// it easier to enforce size requirements for packed containers, Zig allows us
// to specify a *backing integer* for them, just like for enums.
//
// In the case of `FLG`, we want our struct to occupy exactly a single byte, so
// we specify `u8` as the backing integer. It's safe to convert between a packed
// container and its backing integer using the builtin `@bitCast`.
// The LZ4 spec also mandates that reserved bits must always be zero, so it's
// good practice to set `0` as a default value for `reserved`.
//
// The fields of a packed struct start at the least significant bit of its backing
// integer and end at its most significant bit. This is the case no matter what
// endianness our target has.
//
// Try to silence the complaints below:
const Bits = packed struct(u4) {
a: u1 = 0,
b: u1 = 0,
c: u1 = 0,
d: u1 = 0,
};
pub fn main() void {
{
const expected: Bits = @bitCast(@as(u4, 0b1000));
const my_bits: Bits = .{};
if (my_bits != expected) complain(my_bits, expected, @src());
}
{
const expected: Bits = @bitCast(@as(u4, 0b0001));
const my_bits: Bits = .{};
if (my_bits != expected) complain(my_bits, expected, @src());
}
{
const expected: Bits = @bitCast(@as(u4, 0b0010));
const my_bits: Bits = .{};
if (my_bits != expected) complain(my_bits, expected, @src());
}
{
const expected: Bits = @bitCast(@as(u4, 0b0011));
const my_bits: Bits = .{};
if (my_bits != expected) complain(my_bits, expected, @src());
}
{
const expected: Bits = @bitCast(@as(u4, 0b1101));
const my_bits: Bits = .{};
if (my_bits != expected) complain(my_bits, expected, @src());
}
}
// As we can see, equality comparisons (`==` and `!=`) work for packed structs.
// They also work for packed unions. However, since packed containers are not
// naturally ordered, we can't use any other comparison operators on them.
//
// It's also possible to use packed containers in `switch` statements, which we
// will cover in the next exercise!
//
// Since packed containers make very strong guarantees about their memory layout,
// only a handful of types are eligible to be part of them.
// The following types are allowed as field types:
//
// - integers
// - floats
// - bool
// - void
// - enums with explicit backing integers
// - packed unions
// - packed structs
//
const std = @import("std");
const assert = std.debug.assert;
fn complain(my_bits: Bits, expected: Bits, src_loc: std.builtin.SourceLocation) void {
std.debug.print(
"That's not quite right! You've got 0b{b:0>4}, but we want 0b{b:0>4} in line {d}.\n",
.{ @as(u4, @bitCast(my_bits)), @as(u4, @bitCast(expected)), src_loc.line },
);
}
// (†) https://github.com/lz4/lz4/blob/5c4c1fb2354133e1f3b087a341576985f8114bd5/doc/lz4_Frame_format.md#frame-descriptor

78
exercises/115_packed2.zig Normal file
View File

@@ -0,0 +1,78 @@
//
// We've already learned about switch statements in exercises 030, 031 and 108.
// They also work with packed containers:
const S = packed struct(u2) {
a: bool,
b: i1,
};
// Try to make it compile without adding an `else` prong!
comptime {
const s: S = .{ .a = true, .b = -1 };
switch (s) {
.{ .a = true, .b = -1 } => {}, // ok!
.{ .a = true, .b = ??? },
.{ .a = ???, .b = 0 },
.{ .a = ???, .b = ??? },
=> @compileError("We don't want to end up here!"),
}
}
// As we can see, switching on packed structs is pretty straightforward.
// When switching on packed unions however, we'll realize that a packed
// union never keeps track of its active tag, not even in debug mode! This
// means that packed unions compare solely by their bit pattern (again, just
// like integers).
const U = packed union(u2) {
a: u2,
b: i2,
};
// Find and remove the duplicate case!
comptime {
const u: U = .{ .a = 3 };
switch (u) {
.{ .a = 3 } => {}, // ok!
.{ .a = 2 },
.{ .b = 1 },
.{ .b = -1 },
.{ .a = 0 },
=> @compileError("We don't want to end up here!"),
}
}
// Since packed unions don't have the concept of an active tag, it's always legal
// to access any of their fields. This can be useful to view the same data from
// different perspectives seamlessly.
//
// Try to make the float below negative:
/// IEEE 754 half precision float
const Float = packed union(u16) {
value: f16,
bits: packed struct(u16) {
mantissa: u10,
exponent: u5,
sign: u1,
},
};
pub fn main() void {
// Reminder: if the sign bit of a float is set, the number is negative!
var number: Float = .{ .value = 2.34 };
number.bits.??? = ???;
if (number.value != -2.34) {
std.debug.print("Make it negative!\n", .{});
}
}
// This concludes our introduction to packed containers. The next time you need
// control over individual bits, keep them in mind as a potent alternative!
//
const std = @import("std");

BIN
images/ziglings_dark.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
#
# "I will be a shieldmaiden no longer,
# nor vie with the great Riders, nor
@@ -12,6 +12,12 @@
# using the patches in this directory and convey them
# to convalesce in the healed directory.
#
delete_progress() {
progress_file=".progress.txt"
if [ -f $progress_file ]; then
rm $progress_file
fi
}
set -e
# We check ourselves before we wreck ourselves.
@@ -23,9 +29,12 @@ fi
# Which version we have?
echo "Zig version" $(zig version)
echo "Eowyn version 23.10.5.1, let's try our magic power."
echo "Eowyn version 25.1.9, let's try our magic power."
echo ""
# Remove progress file
delete_progress
# Create directory of healing if it doesn't already exist.
mkdir -p patches/healed
@@ -54,3 +63,6 @@ zig fmt --check patches/healed
# Test the healed exercises. May the compiler have mercy upon us.
zig build -Dhealed
# Remove progress file again
delete_progress

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
#
# "How do you pick up the threads of an old life?
# How do you go on, when in your heart you begin

View File

@@ -1,5 +1,5 @@
--- exercises/001_hello.zig 2023-10-03 22:15:22.122241138 +0200
+++ answers/001_hello.zig 2023-10-05 20:04:06.846096282 +0200
--- exercises/001_hello.zig 2026-01-04 14:04:52.752848018 +0100
+++ answers/001_hello.zig 2026-01-04 14:04:54.209877278 +0100
@@ -16,6 +16,6 @@
//
const std = @import("std");

View File

@@ -1,6 +1,6 @@
--- exercises/005_arrays2.zig 2023-10-03 22:15:22.122241138 +0200
+++ answers/005_arrays2.zig 2023-10-05 20:04:06.862763262 +0200
@@ -25,12 +25,12 @@
--- exercises/005_arrays2.zig 2026-05-04 16:26:32.778330847 +0200
+++ answers/005_arrays2.zig 2026-05-04 16:26:13.082917974 +0200
@@ -21,12 +21,12 @@
// (Problem 1)
// Please set this array concatenating the two arrays above.
// It should result in: 1 3 3 7
@@ -10,8 +10,8 @@
// (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;
- const bit_pattern_unit = [_]u8{ ??? };
+ const bit_pattern_unit = [_]u8{ 1, 0, 0, 1 };
const bit_pattern: [3 * bit_pattern_unit.len]u8 = @bitCast(@as([3][bit_pattern_unit.len]u8, @splat(bit_pattern_unit)));
// Okay, that's all of the problems. Let's see the results.
//

View File

@@ -1,6 +1,6 @@
--- exercises/006_strings.zig 2023-10-03 22:15:22.122241138 +0200
+++ answers/006_strings.zig 2023-10-05 20:04:06.869430053 +0200
@@ -24,18 +24,18 @@
--- exercises/006_strings.zig 2026-05-04 17:04:31.763821070 +0200
+++ answers/006_strings.zig 2026-05-04 17:02:11.672866263 +0200
@@ -24,14 +24,14 @@
// (Problem 1)
// Use array square bracket syntax to get the letter 'd' from
// the string "stardust" above.
@@ -8,11 +8,6 @@
+ 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";
@@ -21,4 +16,4 @@
+ 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 });
std.debug.print("d={u} {s}\n", .{ d, major_tom });

View File

@@ -1,11 +1,11 @@
--- exercises/009_if.zig 2023-10-03 22:15:22.122241138 +0200
+++ answers/009_if.zig 2023-10-05 20:04:06.882763636 +0200
--- exercises/009_if.zig 2025-11-28 14:40:19.301738185 +0100
+++ answers/009_if.zig 2025-11-28 14:39:07.756077340 +0100
@@ -24,7 +24,7 @@
const foo = 1;
const foo = 42;
// Please fix this condition:
- if (foo) {
+ if (foo == 1) {
+ if (foo == 42) {
// We want our program to print this message!
std.debug.print("Foo is 1!\n", .{});
std.debug.print("Foo is 42!\n", .{});
} else {

View File

@@ -1,6 +1,6 @@
--- exercises/026_hello2.zig 2023-10-03 22:15:22.122241138 +0200
+++ answers/026_hello2.zig 2023-10-05 20:04:06.959431737 +0200
@@ -23,5 +23,5 @@
--- exercises/026_hello2.zig 2026-01-09 22:51:45.803358789 +0100
+++ answers/026_hello2.zig 2026-01-09 22:50:46.016166527 +0100
@@ -28,5 +28,5 @@
// to be able to pass it up as a return value of main().
//
// We just learned of a single statement which can accomplish this.

View File

@@ -1,6 +1,6 @@
--- exercises/028_defer2.zig 2023-10-03 22:15:22.122241138 +0200
+++ answers/028_defer2.zig 2023-10-05 20:04:06.966098530 +0200
@@ -18,7 +18,7 @@
--- exercises/028_defer2.zig 2026-06-02 06:08:12.713672612 +0200
+++ answers/028_defer2.zig 2026-06-02 06:08:43.262234023 +0200
@@ -20,7 +20,7 @@
fn printAnimal(animal: u8) void {
std.debug.print("(", .{});
@@ -9,3 +9,15 @@
if (animal == 'g') {
std.debug.print("Goat", .{});
@@ -51,9 +51,9 @@
// Try reordering the statements to get the answer 42
{
- defer x = x / 10;
- defer x = x + 11;
defer x = x * 2;
+ defer x = x + 11;
+ defer x = x / 10;
}
return x;

View File

@@ -1,12 +1,8 @@
--- exercises/034_quiz4.zig 2023-10-03 22:15:22.122241138 +0200
+++ answers/034_quiz4.zig 2023-10-05 20:04:06.996099091 +0200
@@ -9,10 +9,10 @@
const NumError = error{IllegalNumber};
-pub fn main() void {
+pub fn main() !void {
const stdout = std.io.getStdOut().writer();
--- exercises/034_quiz4.zig 2026-01-09 22:45:53.115325559 +0100
+++ answers/034_quiz4.zig 2026-01-09 22:45:15.658578603 +0100
@@ -14,7 +14,7 @@
var stdout_writer = std.Io.File.stdout().writer(io, &.{});
const stdout = &stdout_writer.interface;
- const my_num: u32 = getNumber();
+ const my_num: u32 = try getNumber();

View File

@@ -1,5 +1,5 @@
--- exercises/040_pointers2.zig 2023-10-03 22:15:22.122241138 +0200
+++ answers/040_pointers2.zig 2023-10-05 20:04:07.022766257 +0200
--- exercises/040_pointers2.zig 2026-05-22 21:57:28.601255748 +0200
+++ answers/040_pointers2.zig 2026-05-22 21:57:27.672235943 +0200
@@ -23,7 +23,7 @@
pub fn main() void {

View File

@@ -1,18 +1,18 @@
--- 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 @@
--- exercises/046_optionals2.zig 2024-11-08 22:46:25.592875338 +0100
+++ answers/046_optionals2.zig 2024-11-08 22:46:20.699447951 +0100
@@ -22,7 +22,7 @@
const Elephant = struct {
letter: u8,
- tail: *Elephant = null, // Hmm... tail needs something...
+ tail: ?*Elephant = null, // <---- make this optional!
+ tail: ?*Elephant = null, // Hmm... tail needs something...
visited: bool = false,
};
@@ -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?
@@ -66,6 +66,6 @@
// HINT: We want something similar to what `.?` does,
// but instead of ending the program, we want to exit the loop...
- e = e.tail ???
+ e = e.tail orelse break;
}

View File

@@ -1,8 +1,8 @@
--- exercises/058_quiz7.zig 2023-10-03 22:15:22.125574535 +0200
+++ answers/058_quiz7.zig 2023-10-05 20:04:07.106101152 +0200
--- exercises/058_quiz7.zig 2026-05-04 16:34:31.692458399 +0200
+++ answers/058_quiz7.zig 2026-05-04 16:34:29.239406323 +0200
@@ -192,8 +192,8 @@
// Oops! The hermit forgot how to capture the union values
// in a switch statement. Please capture both values as
// in a switch statement. Please capture each value as
// 'p' so the print statements work!
- .place => print("{s}", .{p.name}),
- .path => print("--{}->", .{p.dist}),
@@ -11,7 +11,7 @@
}
}
};
@@ -255,7 +255,7 @@
@@ -254,7 +254,7 @@
// dereference and optional value "unwrapping" look
// together. Remember that you return the address with the
// "&" operator.
@@ -20,7 +20,7 @@
// Try to make your answer this long:__________;
}
return null;
@@ -309,7 +309,7 @@
@@ -308,7 +308,7 @@
//
// Looks like the hermit forgot something in the return value of
// this function. What could that be?

View File

@@ -1,11 +1,20 @@
--- 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 @@
--- exercises/060_floats.zig 2026-05-02 19:22:46.225370223 +0200
+++ answers/060_floats.zig 2026-05-02 19:22:47.523142218 +0200
@@ -50,7 +50,7 @@
//
// 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;
// We'll convert this weight from pounds to metric units at a
// conversion of 0.453592 kg to the pound.
- const shuttle_weight: f16 = 0.453592 * 4480e3;
+ const shuttle_weight: f32 = 0.453592 * 4480e3;
// By default, float values are formatted in scientific
// notation. Try experimenting with '{d}' and '{d:.3}' to see
// By default, float values are formatted in standard decimal
// notation. Experiment with '{d}' and '{d:.3}' to see how
@@ -58,7 +58,7 @@
// scientific notation.
// NOTE: The weight of the shuttle is a huge number, a scientific notation
// may be more appropriate.
- print("Shuttle liftoff weight: {d:.0} metric tons\n", .{shuttle_weight / 1e3});
+ print("Shuttle liftoff weight: {e:.3} metric tons\n", .{shuttle_weight / 1e3});
}
// Floating further:

View File

@@ -1,5 +1,5 @@
--- exercises/065_builtins2.zig 2023-10-03 22:15:22.125574535 +0200
+++ answers/065_builtins2.zig 2023-10-05 20:04:07.136101712 +0200
--- exercises/065_builtins2.zig 2026-06-01 15:33:16.617432671 +0200
+++ answers/065_builtins2.zig 2026-06-01 15:33:31.104018108 +0200
@@ -58,7 +58,7 @@
// Oops! We cannot leave the 'me' and 'myself' fields
// undefined. Please set them here:
@@ -18,22 +18,26 @@
// Now we print a pithy statement about Narcissus.
print("A {s} loves all {s}es. ", .{
@@ -109,15 +109,15 @@
@@ -102,16 +102,16 @@
// Please complete these 'if' statements so that the field
// name will not be printed if the field is of type 'void'
// (which is a zero-bit type that takes up no space at all!):
- if (fields[0].??? != void) {
+ if (fields[0].type != void) {
print(" {s}", .{@typeInfo(Narcissus).Struct.fields[0].name});
- if (field_???[???] != void) {
- print(" {s}", .{field_???[???]});
+ if (field_types[0] != void) {
+ print(" {s}", .{field_names[0]});
}
- if (fields[1].??? != void) {
+ if (fields[1].type != void) {
print(" {s}", .{@typeInfo(Narcissus).Struct.fields[1].name});
- if (field_???[???] != void) {
- print(" {s}", .{field_???[???]});
+ if (field_types[1] != void) {
+ print(" {s}", .{field_names[1]});
}
- if (fields[2].??? != void) {
+ if (fields[2].type != void) {
print(" {s}", .{@typeInfo(Narcissus).Struct.fields[2].name});
- if (field_???[???] != void) {
- print(" {s}", .{field_???[???]});
+ if (field_types[2] != void) {
+ print(" {s}", .{field_names[2]});
}
// Yuck, look at all that repeated code above! I don't know

View File

@@ -1,6 +1,6 @@
--- 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 @@
--- exercises/067_comptime2.zig 2026-05-04 15:38:52.565144012 +0200
+++ answers/067_comptime2.zig 2026-05-04 15:37:20.257213463 +0200
@@ -36,7 +36,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;
const a1: [count]u8 = .{'A'} ** count;
const a1: [count]u8 = @splat('A');

View File

@@ -1,11 +1,11 @@
--- exercises/071_comptime6.zig 2023-10-03 22:15:22.125574535 +0200
+++ answers/071_comptime6.zig 2023-10-05 20:04:07.162768879 +0200
@@ -40,7 +40,7 @@
const fields = @typeInfo(Narcissus).Struct.fields;
--- exercises/071_comptime6.zig 2026-06-01 15:35:27.223400223 +0200
+++ answers/071_comptime6.zig 2026-06-01 15:36:35.349728561 +0200
@@ -41,7 +41,7 @@
const field_names = @typeInfo(Narcissus).@"struct".field_names;
const field_types = @typeInfo(Narcissus).@"struct".field_types;
- ??? {
+ inline for (fields) |field| {
if (field.type != void) {
print(" {s}", .{field.name});
+ inline for (field_names, field_types) |field_name, field_type| {
if (field_type != void) {
print(" {s}", .{field_name});
}

View File

@@ -1,11 +1,35 @@
--- exercises/074_comptime9.zig 2023-10-03 22:15:22.125574535 +0200
+++ answers/074_comptime9.zig 2023-10-05 20:04:07.176102462 +0200
@@ -39,7 +39,7 @@
--- exercises/074_comptime9.zig 2026-05-04 17:11:05.144118157 +0200
+++ answers/074_comptime9.zig 2026-05-04 17:10:36.778519877 +0200
@@ -28,12 +28,12 @@
start, // Ready to start a new animal.
l, // This means we've seen an "l", so if we see an "m", we know it's a Llama.
};
- var state = State.start;
+ comptime var state = State.start;
// And here's the function. Note that the return value type
// depends on one of the input arguments!
-fn makeLlamas(count: usize) [count]u8 {
+fn makeLlamas(comptime count: usize) [count]u8 {
var temp: [count]u8 = undefined;
var i = 0;
// We return an array of animals representing the creature. (This is why we
// really needed the 'count' parameter. Arrays need a size.)
var animals: [count]Animal = undefined;
- var next_animal: usize = 0;
+ comptime var next_animal: usize = 0;
inline for (fmt) |char| {
@@ -57,7 +57,7 @@
//
// What do you think happens with Gators? Do they join with
// other animals or is this an error?
- 'g' => ???,
+ 'g' => @compileError("Gators refuse to join with other animals."),
else => @compileError(std.fmt.comptimePrint("No animal starts with '{c}'!", .{char})),
},
@@ -69,7 +69,7 @@
next_animal += 1;
// Something is missing here. After we finish a Llama, we
// need to be ready to _start_ over with a new animal...
- ???
+ state = .start;
},
else => @compileError("Only llamas start with 'l'!"),

View File

@@ -1,15 +1,17 @@
--- 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 @@
--- exercises/075_quiz8.zig 2026-05-04 15:51:48.254371574 +0200
+++ answers/075_quiz8.zig 2026-05-04 15:49:28.426445382 +0200
@@ -48,7 +48,13 @@
// instead.
//
// Please fill in the body of this function!
fn makePath(from: *Place, to: *Place, dist: u8) Path {
-
-fn makePath(from: *Place, to: *Place, dist: u8) Path {}
+fn makePath(from: *Place, to: *Place, dist: u8) Path {
+ return Path{
+ .from = from,
+ .to = to,
+ .dist = dist,
+ };
}
+}
// Using our new function, these path definitions take up considerably less
// space in our program now!

View File

@@ -1,5 +1,5 @@
--- exercises/076_sentinels.zig 2023-10-03 22:15:22.125574535 +0200
+++ answers/076_sentinels.zig 2023-10-05 20:04:07.186102649 +0200
--- exercises/076_sentinels.zig 2024-09-02 19:27:04.336781039 +0200
+++ answers/076_sentinels.zig 2024-09-02 19:26:15.709134934 +0200
@@ -82,7 +82,7 @@
print("Array:", .{});

View File

@@ -1,32 +1,32 @@
--- exercises/082_anonymous_structs3.zig 2023-10-03 22:15:22.125574535 +0200
+++ answers/082_anonymous_structs3.zig 2023-10-05 20:04:07.212769813 +0200
@@ -82,14 +82,14 @@
// @typeInfo(Circle).Struct.fields
--- exercises/082_anonymous_structs3.zig 2026-06-01 15:59:11.872467805 +0200
+++ answers/082_anonymous_structs3.zig 2026-06-01 15:58:38.004730144 +0200
@@ -82,17 +82,17 @@
// @typeInfo(Circle).@"struct".field_types
//
// This will be an array of StructFields.
- const fields = ???;
+ const fields = @typeInfo(@TypeOf(tuple)).Struct.fields;
// This will be an array of field types.
- const field_types = ???;
+ const field_types = @typeInfo(@TypeOf(tuple)).@"struct".field_types;
// This will be an array of field names.
- const field_names = ???;
+ const field_names = @typeInfo(@TypeOf(tuple)).@"struct".field_names;
// 2. Loop through each field. This must be done at compile
// time.
//
// Hint: remember 'inline' loops?
//
- for (fields) |field| {
+ inline for (fields) |field| {
- for (???, ???) |???, ???| {
+ inline for (field_types, field_names) |field_type, field_name| {
// 3. Print the field's name, type, and value.
//
// Each 'field' in this loop is one of these:
@@ -117,9 +117,9 @@
//
// The first field should print as: "0"(bool):true
// You'll need this builtin:
@@ -116,7 +116,7 @@
print("\"{s}\"({any}):{any} ", .{
- field.???,
- field.???,
field_name,
field_type,
- ???,
+ field.name,
+ field.type,
+ @field(tuple, field.name),
+ @field(tuple, field_name),
});
}
}

View File

@@ -1,11 +1,11 @@
--- exercises/084_async.zig 2023-10-03 22:15:22.125574535 +0200
+++ answers/084_async.zig 2023-10-05 20:04:07.219436606 +0200
@@ -48,7 +48,7 @@
pub fn main() void {
// Additional Hint: you can assign things to '_' when you
// don't intend to do anything with them.
- foo();
+ _ = async foo();
}
--- exercises/084_async.zig 2026-04-01 20:40:08.904999609 +0200
+++ answers/084_async.zig 2026-04-01 20:40:05.641933231 +0200
@@ -37,7 +37,7 @@
const std = @import("std");
fn foo() void {
pub fn main(init: std.process.Init) !void {
- const io = init.???;
+ const io = init.io;
// Get the current wall-clock time using the Io interface.
// Hint: Timestamp.now() takes an Io and a Clock type (.real = wall clock).

View File

@@ -1,5 +1,5 @@
--- exercises/092_interfaces.zig 2023-10-03 22:15:22.125574535 +0200
+++ answers/092_interfaces.zig 2023-10-05 20:04:07.259437354 +0200
--- exercises/084_interfaces.zig 2026-04-03 19:24:51.764327692 +0200
+++ answers/084_interfaces.zig 2026-04-03 19:27:31.552579474 +0200
@@ -106,7 +106,7 @@
for (my_insects) |insect| {
// Almost done! We want to print() each insect with a

View File

@@ -0,0 +1,11 @@
--- exercises/085_async.zig 2026-04-04 16:01:01.509555724 +0200
+++ answers/085_async.zig 2026-04-04 16:00:58.541495688 +0200
@@ -38,7 +38,7 @@
const std = @import("std");
pub fn main(init: std.process.Init) !void {
- const io = init.???;
+ const io = init.io;
// Get the current wall-clock time using the Io interface.
// Hint: Timestamp.now() takes an Io and a Clock type (.real = wall clock).

Some files were not shown because too many files have changed in this diff Show More