aozig is an Advent of Code wrapper for Zig projects.
This repository also includes 2023 & 2025 examples (src/2023, src/2025) so you can see a complete setup in action.
Each puzzle module lives at src/<year>/dayN.zig next to its input dayN.txt. The runtime expects the following interface:
pub fn parse(data: []const u8) !T– mandatory parser for part 1 (and part 2 if you don’t defineparse2).pub fn solve1(parsed: T) U– part 1 solver.pub fn solve2(parsed_or_other: anytype) U– part 2 solver. If you defineparse2, the runtime feeds its result intosolve2; otherwise it reuses the value returned byparse.pub fn parse2(data: []const u8) !T2– optional specialised parser solely for part 2.- Optional
pub var alloc: std.mem.Allocator = ...;– if present the runtime assigns the day-specific allocator before calling any parse/solve function.
zig build run [-- <args>]: Executes every discovered day (or just the selected one; see build flags below). Inside the executable you can also pass:
bench [runs]– measures parse/solve timings. Defaultruns=10.heap– estimates the memory required<number>– run a single day directly, bypassing-Dday.
zig build test: Runs unit tests for every selected day module. Each dayN.zig can contain test "name" { … } blocks as usual.
-Dyear=2025– choose whichsrc/<year>directory to use (defaults to whatever you set inConfig.default_year).-Dday=5– restricts discovery to a single day. The build helper filters bothrunandtestto that day and forwards5to the executable when you don’t provide custom args.
repo/
├─ build.zig
├─ build.zon
├─ src/
│ ├─ 2025/
│ │ ├─ day1.zig
│ │ ├─ day1.txt
│ │ └─ …
│ └─ 2023/
│ └─ …
└─ .token # Advent of Code session token used for input downloads
.token must contain your Advent of Code session cookie. The helper only downloads an input the first time its dayN.txt is missing.
zig fetch --save git+https://github.com/Sh4d1/aozig#mainzig fetch prints a content hash and amends your build.zon like:
.{
.dependencies = .{
.aozig = .{
.url = "git+https://github.com/Sh4d1/aozig#main",
.hash = "1220…", // from zig fetch output
},
},
}Then wire it into build.zig:
const std = @import("std");
const aozig = @import("aozig");
pub fn build(b: *std.Build) !void {
const dep = b.dependency("aozig", .{});
try aozig.defaultBuild(b, .{
.default_year = 2025,
.binary_name = "aoc",
.runtime_dependency = dep,
});
}defaultBuild installs the executable, generates the entrypoint that calls aozig.run, ensures inputs exist, and registers run/test steps.
aozig.Config fields:
default_year: which folder to use when-Dyearis omitted.src_root: root directory scanned foryear/dayNfiles (defaults tosrc).binary_name: name of the produced executable (mainif unspecified).runtime_dependency: provide when you depend onaozigviazig fetch.runtime_module: override the module used at runtime (defaults to the sameaozigsource the build script imports).
Create a .token file in your project root containing your Advent of Code session cookie. To get it:
- Log in to https://adventofcode.com
- Open browser DevTools (F12)
- Go to Application/Storage > Cookies
- Copy the value of the 'session' cookie
- Save it to
.token
It might be a good idea to run it with -Doptimize=ReleaseFast!
# Run 100 iterations for better statistics
zig build run -- bench 100
# Check minimum heap usage for a specific day
zig build run -Dday=5 -- heap
# Profile a single day
zig build run -Dday=5The benchmark output shows:
- Min/Max: Best and worst case timings
- Mean: Average time across all runs
- Median: Middle value (more robust against outliers)
- Stddev: Consistency of your solution (lower is better)
Create new day files quickly:
# Create day 5 for the default year
zig build -Dnew=5
# Create day 10 for a specific year
zig build -Dnew=10 -Dyear=2024Happy Advent of Coding!