YIAN7Z2GNJPLAEXUSSJNSOG64GPUDGUYBB77WZKDOH42AMXACDZAC const std = @import("std");const fetch = @import("fetch");const Str = []const u8;const opts = fetch.Options{.year = 2024,.days = 1,};const aoc2024 = struct {const day01 = @import("day01.zig");};test {_ = @import("day01.zig");}pub fn main() anyerror!void {var gpa = std.heap.GeneralPurposeAllocator(.{}){};defer _ = gpa.deinit();const allocator = gpa.allocator();if (!fetch.checkInputs(opts.days)) {try fetch.fetchInputs(allocator, opts);}try solveAll(allocator);}fn solveAll(allocator: std.mem.Allocator) anyerror!void {var timer = try std.time.Timer.start();var time_sum: usize = 0;var buffer = std.io.bufferedWriter(std.io.getStdOut().writer());const stdout = buffer.writer();try stdout.print("{s:<8}{s:>45}{s:>20}\n", .{ "Day", "Result", "Time" });comptime var day: u5 = 0;inline while (day < opts.days) : (day += 1) {comptime var buf: [5]u8 = undefined;const day_str = comptime try std.fmt.bufPrint(&buf, "day{d:0>2}", .{day + 1});timer.reset();const first_res = @field(aoc2024, day_str).first(allocator) catch unreachable;const first_time = timer.read() / std.time.ns_per_us;time_sum += first_time;{const runtime_buffer = buf; // comptime -> runtime hackswitch (@TypeOf(first_res)) {Str => try stdout.print("{s}a: {s:>45}{d:>20} us\n", .{ runtime_buffer, first_res, first_time }),usize, isize => try stdout.print("{s}a: {d:>45}{d:>20} us\n", .{ runtime_buffer, first_res, first_time }),else => try stdout.print("{s}a: {s:>45}{d:>20} us\n", .{ runtime_buffer, "", first_time }),}}if (day < 24) {timer.reset();const second_res = @field(aoc2024, day_str).second(allocator) catch unreachable;const second_time = timer.read() / std.time.ns_per_us;time_sum += second_time;{const runtime_buffer = buf; // comptime -> runtime hackswitch (@TypeOf(second_res)) {Str => try stdout.print("{s}b: {s:>45}{d:>20} us\n", .{ runtime_buffer, second_res, second_time }),usize, isize => try stdout.print("{s}b: {d:>45}{d:>20} us\n", .{ runtime_buffer, second_res, second_time }),else => try stdout.print("{s}b: {s:>45}{d:>20} us\n", .{ runtime_buffer, "", second_time }),}}}}try stdout.print("Total time: {d} ms\n", .{time_sum / std.time.us_per_ms});try buffer.flush();}
const std = @import("std");const INPUTS_DIR = "inputs";const SESSION_FILE = "session.txt";const MAX_INPUT_SIZE = 512 * 512; // Maximum allowed input size (bytes)pub const Options = struct {year: usize,days: usize,};pub fn fetchInputs(allocator: std.mem.Allocator, opts: Options) !void {const cwd = std.fs.cwd();cwd.makeDir(INPUTS_DIR) catch |err| {switch (err) {error.PathAlreadyExists => {},else => return err,}};const session = cwd.readFileAlloc(allocator, SESSION_FILE, 256) catch |err| {std.log.err("Unable to open '{s}'.\nMake sure to copy the session cookie value to this file to download the user specific input files.", .{SESSION_FILE});return err;};defer allocator.free(session);for (1..opts.days + 1) |day| {const file_name = try std.fmt.allocPrint(allocator, "{s}/day{d:0>2}.txt", .{ INPUTS_DIR, day });defer allocator.free(file_name);const fd = cwd.openFile(file_name, std.fs.File.OpenFlags{}) catch |err| {switch (err) {error.FileNotFound => {try fetchDay(allocator, opts, session, day);continue;},else => return err,}};defer fd.close();}}fn fetchDay(allocator: std.mem.Allocator, opts: Options, session: []const u8, day: usize) !void {var client = std.http.Client{ .allocator = allocator };defer client.deinit();std.debug.print("Downloading day{d:0>2}\r", .{day});const url = try std.fmt.allocPrint(allocator,"https://adventofcode.com/{d}/day/{d}/input",.{ opts.year, day },);defer allocator.free(url);const uri = try std.Uri.parse(url);var headers = std.ArrayList(std.http.Header).init(allocator);defer headers.deinit();try headers.append(.{.name = "Cookie",.value = try std.fmt.allocPrint(allocator, "session={s}", .{session}),});defer {for (headers.items) |header| {allocator.free(header.value);}}var sh: [512]u8 = undefined;var req = try client.open(.GET, uri, .{.server_header_buffer = &sh,.extra_headers = headers.items,});defer req.deinit();try req.send();try req.finish();try req.wait();const body = try req.reader().readAllAlloc(allocator, MAX_INPUT_SIZE);defer allocator.free(body);if (req.response.status != std.http.Status.ok) {std.log.err("{}", .{req.response.status});std.log.err("{s}", .{body});return error.HttpRequestError;}const file_name = try std.fmt.allocPrint(allocator, "{s}/day{d:0>2}.txt", .{ INPUTS_DIR, day });defer allocator.free(file_name);try std.fs.cwd().writeFile(std.fs.Dir.WriteFileOptions{.sub_path = file_name,.data = body,.flags = .{ .mode = 0o644 },});}/// Checks if `INPUTS_DIR` exists and all the input files are available.pub fn checkInputs(days: usize) bool {const cwd = std.fs.cwd();const inputs = cwd.openDir(INPUTS_DIR, std.fs.Dir.OpenDirOptions{.iterate = true,}) catch {return false;};var counter: usize = 0;var it = inputs.iterate();while (it.next() catch unreachable) |_| : (counter += 1) {}if (counter == days) return true else return false;}
.{.name = "aoc2024",.version = "0.0.0",.minimum_zig_version = "0.13.0",// 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,//},},.paths = .{"build.zig","build.zig.zon","src",// For example...//"LICENSE",//"README.md",},}
const std = @import("std");pub fn build(b: *std.Build) void {const fetch_module = b.createModule(std.Build.Module.CreateOptions{.root_source_file = std.Build.LazyPath{.src_path = .{ .owner = b, .sub_path = "fetch.zig" },},});const target = b.standardTargetOptions(.{});const optimize = b.standardOptimizeOption(.{});const exe = b.addExecutable(std.Build.ExecutableOptions{.name = "aoc2024",.root_source_file = std.Build.LazyPath{.src_path = .{ .owner = b, .sub_path = "src/main.zig" },},.target = target,.optimize = optimize,});exe.root_module.addImport("fetch", fetch_module);b.installArtifact(exe);const run_cmd = b.addRunArtifact(exe);run_cmd.step.dependOn(b.getInstallStep());if (b.args) |args| {run_cmd.addArgs(args);}const run_step = b.step("run", "Run all solver");run_step.dependOn(&run_cmd.step);const exe_tests = b.addTest(std.Build.TestOptions{.root_source_file = std.Build.LazyPath{.src_path = .{ .owner = b, .sub_path = "src/main.zig" },},.target = target,.optimize = optimize,});const test_cmd = b.addRunArtifact(exe_tests);const test_step = b.step("test", "Run unit tests");test_step.dependOn(&test_cmd.step);}