summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Magnusson <mathias@magnusson.space>2025-12-01 14:04:18 +0100
committerMathias Magnusson <mathias@magnusson.space>2025-12-01 14:04:18 +0100
commitfb98b90b7da6d13594b0292b635cb85498583eb9 (patch)
treed576264c92888ca738725b23ccbb11b7636f74a3
parent2f31753057ab67f3a7ba9d25b83e01aefd90505b (diff)
downloadprogramming-problem-solving-fb98b90b7da6d13594b0292b635cb85498583eb9.tar.gz
aoc2025: copy zig project from 2024 & upgrade to 0.15.2
-rw-r--r--aoc25/.envrc1
-rw-r--r--aoc25/.gitignore3
-rw-r--r--aoc25/build.zig97
-rw-r--r--aoc25/build.zig.zon74
-rw-r--r--aoc25/tools/download_input.zig41
-rw-r--r--aoc25/tools/generate_main.zig43
6 files changed, 259 insertions, 0 deletions
diff --git a/aoc25/.envrc b/aoc25/.envrc
new file mode 100644
index 0000000..fe7c01a
--- /dev/null
+++ b/aoc25/.envrc
@@ -0,0 +1 @@
+dotenv
diff --git a/aoc25/.gitignore b/aoc25/.gitignore
new file mode 100644
index 0000000..d278b12
--- /dev/null
+++ b/aoc25/.gitignore
@@ -0,0 +1,3 @@
+.zig-cache/
+zig-out/
+.env
diff --git a/aoc25/build.zig b/aoc25/build.zig
new file mode 100644
index 0000000..0032005
--- /dev/null
+++ b/aoc25/build.zig
@@ -0,0 +1,97 @@
+const std = @import("std");
+
+pub fn build(b: *std.Build) void {
+ const target = b.standardTargetOptions(.{});
+
+ const optimize = b.standardOptimizeOption(.{});
+
+ const generate_main = b.addExecutable(.{
+ .name = "generate_main",
+ .root_module = b.createModule(.{
+ .root_source_file = b.path("tools/generate_main.zig"),
+ .target = b.graph.host,
+ .optimize = optimize,
+ }),
+ });
+
+ const download_input = b.addExecutable(.{
+ .name = "download_input",
+ .root_module = b.createModule(.{
+ .root_source_file = b.path("tools/download_input.zig"),
+ .target = b.graph.host,
+ .optimize = optimize,
+ }),
+ });
+
+ for (1..13) |day| {
+ const run_download_input = b.addRunArtifact(download_input);
+ run_download_input.addArg(b.fmt("{}", .{day}));
+ const input_path = run_download_input.addOutputFileArg(b.fmt("{}.txt", .{day}));
+ const path = b.path(b.fmt("src/day{}.zig", .{day}));
+
+ for ([_]usize{ 1, 2 }) |part| {
+ const name = b.fmt("day{}p{}", .{ day, part });
+
+ const run_generate_main = b.addRunArtifact(generate_main);
+ run_generate_main.addArg(b.fmt("{}", .{part}));
+ const main_path = run_generate_main.addOutputFileArg(b.fmt("{s}_main.zig", .{name}));
+
+ const exe = b.addExecutable(.{
+ .name = b.fmt("{s}", .{name}),
+ .root_module = b.createModule(.{
+ .root_source_file = main_path,
+ .target = target,
+ .optimize = optimize,
+ }),
+ });
+ exe.root_module.addAnonymousImport("solution", .{
+ .root_source_file = path,
+ .target = target,
+ .optimize = optimize,
+ });
+ exe.root_module.addAnonymousImport("input", .{
+ .root_source_file = input_path,
+ .target = target,
+ .optimize = optimize,
+ });
+
+ const install_artifact = b.addInstallArtifact(exe, .{});
+ const install_step = b.step(b.fmt("{s}-install", .{name}), b.fmt("Install {s} to the output directory", .{name}));
+ install_step.dependOn(&install_artifact.step);
+
+ // This *creates* a Run step in the build graph, to be executed when another
+ // step is evaluated that depends on it. The next line below will establish
+ // such a dependency.
+ const run_cmd = b.addRunArtifact(exe);
+
+ // This allows the user to pass arguments to the application in the build
+ // command itself, like this: `zig build run -- arg1 arg2 etc`
+ if (b.args) |args| {
+ run_cmd.addArgs(args);
+ }
+
+ // This creates a build step. It will be visible in the `zig build --help` menu,
+ // and can be selected like this: `zig build run`
+ // This will evaluate the `run` step rather than the default, which is "install".
+ const run_step = b.step(name, b.fmt("Run {s}", .{name}));
+ run_step.dependOn(&run_cmd.step);
+
+ const exe_unit_tests = b.addTest(.{
+ .root_module = b.createModule(.{
+ .root_source_file = path,
+ .target = target,
+ .optimize = optimize,
+ }),
+ .filters = &.{b.fmt("part{}", .{part})},
+ });
+
+ const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
+
+ // Similar to creating the run step earlier, this exposes a `test` step to
+ // the `zig build --help` menu, providing a way for the user to request
+ // running the unit tests.
+ const test_step = b.step(b.fmt("{s}-test", .{name}), b.fmt("Test {s}", .{name}));
+ test_step.dependOn(&run_exe_unit_tests.step);
+ }
+ }
+}
diff --git a/aoc25/build.zig.zon b/aoc25/build.zig.zon
new file mode 100644
index 0000000..3b389ae
--- /dev/null
+++ b/aoc25/build.zig.zon
@@ -0,0 +1,74 @@
+.{
+ // This is the default name used by packages depending on this one. For
+ // example, when a user runs `zig fetch --save <url>`, this field is used
+ // as the key in the `dependencies` table. Although the user can choose a
+ // different name, most users will stick with this provided value.
+ //
+ // It is redundant to include "zig" in this name because it is already
+ // within the Zig package namespace.
+ .name = .aoc25,
+
+ // This is a [Semantic Version](https://semver.org/).
+ // In a future version of Zig it will be used for package deduplication.
+ .version = "0.0.0",
+
+ .fingerprint = 0xf067ab9ea6793083,
+
+ // This field is optional.
+ // This is currently advisory only; Zig does not yet do anything
+ // with this value.
+ .minimum_zig_version = "0.15.2",
+
+ // This field is optional.
+ // Each dependency must either provide a `url` and `hash`, or a `path`.
+ // `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
+ // Once all dependencies are fetched, `zig build` no longer requires
+ // internet connectivity.
+ .dependencies = .{
+ // See `zig fetch --save <url>` for a command-line interface for adding dependencies.
+ //.example = .{
+ // // When updating this field to a new URL, be sure to delete the corresponding
+ // // `hash`, otherwise you are communicating that you expect to find the old hash at
+ // // the new URL.
+ // .url = "https://example.com/foo.tar.gz",
+ //
+ // // This is computed from the file contents of the directory of files that is
+ // // obtained after fetching `url` and applying the inclusion rules given by
+ // // `paths`.
+ // //
+ // // This field is the source of truth; packages do not come from a `url`; they
+ // // come from a `hash`. `url` is just one of many possible mirrors for how to
+ // // obtain a package matching this `hash`.
+ // //
+ // // Uses the [multihash](https://multiformats.io/multihash/) format.
+ // .hash = "...",
+ //
+ // // When this is provided, the package is found in a directory relative to the
+ // // build root. In this case the package's hash is irrelevant and therefore not
+ // // computed. This field and `url` are mutually exclusive.
+ // .path = "foo",
+
+ // // When this is set to `true`, a package is declared to be lazily
+ // // fetched. This makes the dependency only get fetched if it is
+ // // actually used.
+ // .lazy = false,
+ //},
+ },
+
+ // Specifies the set of files and directories that are included in this package.
+ // Only files and directories listed here are included in the `hash` that
+ // is computed for this package. Only files listed here will remain on disk
+ // when using the zig package manager. As a rule of thumb, one should list
+ // files required for compilation plus any license(s).
+ // Paths are relative to the build root. Use the empty string (`""`) to refer to
+ // the build root itself.
+ // A directory listed here means that all files within, recursively, are included.
+ .paths = .{
+ "build.zig",
+ "build.zig.zon",
+ "src",
+ // For example...
+ //"LICENSE",
+ //"README.md",
+ },
+}
diff --git a/aoc25/tools/download_input.zig b/aoc25/tools/download_input.zig
new file mode 100644
index 0000000..3fae78c
--- /dev/null
+++ b/aoc25/tools/download_input.zig
@@ -0,0 +1,41 @@
+const std = @import("std");
+
+pub fn main() !void {
+ std.debug.print("Downloading input from adventofcode.com\n", .{});
+
+ var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+ defer arena.deinit();
+ const allocator = arena.allocator();
+
+ const args = try std.process.argsAlloc(allocator);
+
+ if (args.len != 3) return error.InvalidArguments;
+
+ const day = try std.fmt.parseInt(u32, args[1], 10);
+ const output_file_path = args[2];
+
+ var output_file = try std.fs.cwd().createFile(output_file_path, .{});
+ defer output_file.close();
+ var output_buffer: [4096]u8 = undefined;
+ var output_writer = output_file.writer(&output_buffer);
+ var output = &output_writer.interface;
+
+ const url = try std.fmt.allocPrint(allocator, "https://adventofcode.com/2025/day/{}/input", .{day});
+ defer allocator.free(url);
+ const session_cookie_header = try std.fmt.allocPrint(allocator, "session={s}", .{
+ std.posix.getenv("AOC_SESSION") orelse return error.MissingAocSession,
+ });
+ defer allocator.free(session_cookie_header);
+ var client = std.http.Client{ .allocator = allocator };
+ const result = try client.fetch(.{
+ .location = .{ .url = url },
+ .response_writer = output,
+ .extra_headers = &[_]std.http.Header{
+ .{ .name = "Cookie", .value = session_cookie_header },
+ },
+ });
+ if (result.status != .ok) return error.InvalidStatusCode;
+
+ try output.flush();
+ return std.process.cleanExit();
+}
diff --git a/aoc25/tools/generate_main.zig b/aoc25/tools/generate_main.zig
new file mode 100644
index 0000000..f2ba9d0
--- /dev/null
+++ b/aoc25/tools/generate_main.zig
@@ -0,0 +1,43 @@
+const std = @import("std");
+
+pub fn main() !void {
+ var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+ defer arena.deinit();
+ const allocator = arena.allocator();
+
+ const args = try std.process.argsAlloc(allocator);
+
+ if (args.len != 3) return error.InvalidArguments;
+
+ const part = try std.fmt.parseInt(u32, args[1], 10);
+ const output_file_path = args[2];
+
+ var output_file = try std.fs.cwd().createFile(output_file_path, .{});
+ defer output_file.close();
+ var output_buffer: [512]u8 = undefined;
+ var output_writer = output_file.writer(&output_buffer);
+ const output = &output_writer.interface;
+
+ try output.print(
+ \\const std = @import("std");
+ \\const solution = @import("solution");
+ \\
+ \\pub fn main() !void {{
+ \\ const data = @embedFile("input");
+ \\
+ \\ var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+ \\ defer arena.deinit();
+ \\ const allocator = arena.allocator();
+ \\
+ \\ const input = try solution.parse(allocator, data);
+ \\ const output = try solution.part{}(allocator, input);
+ \\ var stdout_writer = std.fs.File.stdout().writer(&.{{}});
+ \\ const stdout = &stdout_writer.interface;
+ \\ try stdout.print("{{}}\n", .{{output}});
+ \\}}
+ ,
+ .{part},
+ );
+ try output.flush();
+ return std.process.cleanExit();
+}