210 lines
6.2 KiB
Zig
210 lines
6.2 KiB
Zig
const std = @import("std");
|
|
const aoc = @import("./aoc.zig");
|
|
const cli = @import("./cli.zig");
|
|
|
|
const Allocator = std.mem.Allocator;
|
|
const StringArray = std.ArrayList([]const u8);
|
|
const DayHashMap = std.StringHashMap(aoc.Day);
|
|
|
|
fn create_day(comptime module: anytype) aoc.Day {
|
|
var part1: ?aoc.Solver = null;
|
|
if (@hasDecl(module, "part1")) {
|
|
part1 = @field(module, "part1");
|
|
}
|
|
|
|
var part2: ?aoc.Solver = null;
|
|
if (@hasDecl(module, "part2")) {
|
|
part2 = @field(module, "part2");
|
|
}
|
|
|
|
return .{ .part1 = part1, .part2 = part2 };
|
|
}
|
|
|
|
const Days = [_]aoc.Day{
|
|
create_day(@import("./day1.zig")),
|
|
create_day(@import("./day2.zig")),
|
|
create_day(@import("./day3.zig")),
|
|
create_day(@import("./day4.zig")),
|
|
create_day(@import("./day5.zig")),
|
|
create_day(@import("./day6.zig")),
|
|
create_day(@import("./day7.zig")),
|
|
create_day(@import("./day8.zig")),
|
|
create_day(@import("./day9.zig")),
|
|
create_day(@import("./day10.zig")),
|
|
create_day(@import("./day11.zig")),
|
|
create_day(@import("./day12.zig")),
|
|
create_day(@import("./day13.zig")),
|
|
create_day(@import("./day14.zig")),
|
|
create_day(@import("./day15.zig")),
|
|
create_day(@import("./day16.zig")),
|
|
create_day(@import("./day17.zig")),
|
|
create_day(@import("./day18.zig")),
|
|
create_day(@import("./day19.zig")),
|
|
create_day(@import("./day20.zig")),
|
|
create_day(@import("./day21.zig")),
|
|
};
|
|
|
|
fn kilobytes(count: u32) u32 {
|
|
return count * 1024;
|
|
}
|
|
|
|
fn run(allocator: Allocator, args: *cli) !u8 {
|
|
if (args.day > Days.len) {
|
|
std.debug.print("ERROR: Day {} does not exist\n", .{args.day});
|
|
return 255;
|
|
}
|
|
|
|
const day = Days[args.day-1];
|
|
if ((args.part == 1 and day.part1 == null) or (args.part == 2 and day.part2 == null)) {
|
|
std.debug.print("ERROR: Part {} for day {} does not exist\n", .{args.part, args.day});
|
|
return 255;
|
|
}
|
|
|
|
var file = std.fs.cwd().openFile(args.input_file, .{}) catch |err| switch (err) {
|
|
error.FileNotFound => {
|
|
std.debug.print("ERROR: Input file '{s}' does not exist\n", .{args.input_file});
|
|
return 255;
|
|
},
|
|
else => return err
|
|
};
|
|
defer file.close();
|
|
|
|
var buf_reader = std.io.bufferedReader(file.reader());
|
|
var reader = buf_reader.reader();
|
|
|
|
var lines = StringArray.init(allocator);
|
|
defer {
|
|
for (lines.items) |line| {
|
|
allocator.free(line);
|
|
}
|
|
lines.deinit();
|
|
}
|
|
|
|
while (try reader.readUntilDelimiterOrEofAlloc(allocator, '\n', kilobytes(32))) |line| {
|
|
try lines.append(std.mem.trimRight(u8, line, &.{'\r'}));
|
|
}
|
|
|
|
var input = aoc.Input{ .allocator = allocator, .lines = lines.items };
|
|
|
|
const start_time = std.time.microTimestamp();
|
|
var result: aoc.Result = undefined;
|
|
if (args.part == 1) {
|
|
result = try day.part1.?(&input);
|
|
} else if (args.part == 2) {
|
|
result = try day.part2.?(&input);
|
|
} else {
|
|
unreachable;
|
|
}
|
|
const end_time = std.time.microTimestamp();
|
|
|
|
switch (result) {
|
|
.uint => std.debug.print("{}\n", .{result.uint}),
|
|
.int => std.debug.print("{}\n", .{result.int}),
|
|
}
|
|
|
|
const duration = end_time - start_time;
|
|
std.debug.print("Time taken: {}ms ({}us)\n", .{@divTrunc(duration, std.time.us_per_ms), duration});
|
|
|
|
return 0;
|
|
}
|
|
|
|
fn get_input(allocator: Allocator, args: *cli) !u8 {
|
|
var client = std.http.Client{ .allocator = allocator };
|
|
defer client.deinit();
|
|
|
|
if (!try std.process.hasEnvVar(allocator, "AOC_SESSION")) {
|
|
std.debug.print("ERROR: Missing environment variable AOC_SESSION\n", .{});
|
|
return 255;
|
|
}
|
|
|
|
const aoc_session = try std.process.getEnvVarOwned(allocator, "AOC_SESSION");
|
|
defer allocator.free(aoc_session);
|
|
|
|
const cookie_header = try std.fmt.allocPrint(allocator, "session={s}", .{aoc_session});
|
|
defer allocator.free(cookie_header);
|
|
|
|
const url_str = try std.fmt.allocPrint(allocator, "https://adventofcode.com/2023/day/{}/input", .{args.day});
|
|
defer allocator.free(url_str);
|
|
|
|
const uri = std.Uri.parse(url_str) catch unreachable;
|
|
|
|
var server_header_buffer: [1024]u8 = undefined;
|
|
var request = try client.open(.GET, uri, .{
|
|
.server_header_buffer = &server_header_buffer,
|
|
.extra_headers = &.{
|
|
.{ .name = "cookie", .value = cookie_header },
|
|
.{ .name = "accept", .value = "*/*" },
|
|
}
|
|
});
|
|
defer request.deinit();
|
|
|
|
try request.send();
|
|
try request.wait();
|
|
|
|
if (request.response.status != .ok) {
|
|
if (request.response.status == .not_found) {
|
|
std.debug.print("ERROR: Day not found\n", .{});
|
|
} else if (request.response.status == .bad_request) {
|
|
std.debug.print("ERROR: Invalid session token\n", .{});
|
|
} else {
|
|
std.debug.print("ERROR: unknown error, status code {}\n", .{request.response.status});
|
|
}
|
|
|
|
return 255;
|
|
}
|
|
|
|
const body = try request.reader().readAllAlloc(allocator, kilobytes(128));
|
|
defer allocator.free(body);
|
|
|
|
var file = try std.fs.cwd().createFile(args.input_file, .{ });
|
|
defer file.close();
|
|
|
|
try file.writeAll(body);
|
|
|
|
return 0;
|
|
}
|
|
|
|
pub fn main() !u8 {
|
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
|
const allocator = gpa.allocator();
|
|
defer {
|
|
if (gpa.deinit() == .leak) @panic("Leaked memory");
|
|
}
|
|
|
|
var args = cli.init(allocator) catch |err| switch (err) {
|
|
error.cli => return 255,
|
|
else => return err
|
|
} ;
|
|
defer args.deinit();
|
|
|
|
if (args.action == .Run) {
|
|
return run(allocator, &args);
|
|
} else {
|
|
return get_input(allocator, &args);
|
|
}
|
|
}
|
|
|
|
test {
|
|
_ = @import("./day1.zig");
|
|
_ = @import("./day2.zig");
|
|
_ = @import("./day3.zig");
|
|
_ = @import("./day4.zig");
|
|
_ = @import("./day5.zig");
|
|
_ = @import("./day6.zig");
|
|
_ = @import("./day7.zig");
|
|
_ = @import("./day8.zig");
|
|
_ = @import("./day9.zig");
|
|
_ = @import("./day10.zig");
|
|
_ = @import("./day11.zig");
|
|
_ = @import("./day12.zig");
|
|
_ = @import("./day13.zig");
|
|
_ = @import("./day14.zig");
|
|
_ = @import("./day15.zig");
|
|
_ = @import("./day16.zig");
|
|
_ = @import("./day17.zig");
|
|
_ = @import("./day18.zig");
|
|
_ = @import("./day19.zig");
|
|
_ = @import("./day20.zig");
|
|
_ = @import("./day21.zig");
|
|
}
|