add framework for adding solutions
This commit is contained in:
parent
784b3a003b
commit
59ac1720b9
20
src/aoc.zig
Normal file
20
src/aoc.zig
Normal file
@ -0,0 +1,20 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
pub const Input = struct {
|
||||
allocator: Allocator,
|
||||
lines: [][]const u8
|
||||
};
|
||||
|
||||
pub const Result = union(enum) {
|
||||
float: f32,
|
||||
uint: u32,
|
||||
int: i32,
|
||||
text: [64:0]u8
|
||||
};
|
||||
|
||||
pub const Solver = *const fn(input: *Input) anyerror!Result;
|
||||
pub const Day = struct {
|
||||
part1: ?Solver,
|
||||
part2: ?Solver
|
||||
};
|
63
src/cli.zig
Normal file
63
src/cli.zig
Normal file
@ -0,0 +1,63 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Self = @This();
|
||||
|
||||
allocator: Allocator,
|
||||
day: u32,
|
||||
part: u32,
|
||||
input_file: []u8,
|
||||
|
||||
fn print_usage(program: []const u8) void {
|
||||
std.debug.print("Usage: {s} <day> <part> [input.txt]\n", .{program});
|
||||
}
|
||||
|
||||
pub fn init(allocator: Allocator) !Self {
|
||||
var args = std.process.args();
|
||||
|
||||
const program = try allocator.dupe(u8, args.next().?);
|
||||
defer allocator.free(program);
|
||||
|
||||
var day: u32 = 0;
|
||||
var part: u32 = 0;
|
||||
var input_file = try allocator.dupe(u8, "input.txt");
|
||||
var i: u32 = 0;
|
||||
while (args.next()) |arg| {
|
||||
if (i == 0) {
|
||||
day = std.fmt.parseInt(u32, arg, 10) catch {
|
||||
std.debug.print("ERROR: Invalid day '{s}'\n", .{arg});
|
||||
return error.cli;
|
||||
};
|
||||
} else if (i == 1) {
|
||||
part = std.fmt.parseInt(u32, arg, 10) catch {
|
||||
std.debug.print("ERROR: Invalid part '{s}'\n", .{arg});
|
||||
return error.cli;
|
||||
};
|
||||
|
||||
if (!(part == 1 or part == 2)) {
|
||||
std.debug.print("ERROR: Part can only be 1 or 2\n", .{});
|
||||
return error.cli;
|
||||
}
|
||||
} else if (i == 2) {
|
||||
allocator.free(input_file);
|
||||
input_file = try allocator.dupe(u8, arg);
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if (i < 2) {
|
||||
print_usage(program);
|
||||
return error.cli;
|
||||
}
|
||||
|
||||
return Self{
|
||||
.allocator = allocator,
|
||||
.day = day,
|
||||
.part = part,
|
||||
.input_file = input_file
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.allocator.free(self.input_file);
|
||||
}
|
28
src/day1.zig
28
src/day1.zig
@ -1,8 +1,12 @@
|
||||
const std = @import("std");
|
||||
const aoc = @import("./aoc.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const digits = [_][]const u8{ "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
|
||||
|
||||
pub fn part1(lines: [][]const u8) u32 {
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const lines = input.lines;
|
||||
|
||||
var sum: u32 = 0;
|
||||
for (lines) |line| {
|
||||
var first_digit: u8 = 0;
|
||||
@ -23,10 +27,12 @@ pub fn part1(lines: [][]const u8) u32 {
|
||||
sum += number;
|
||||
}
|
||||
|
||||
return sum;
|
||||
return .{ .uint = sum };
|
||||
}
|
||||
|
||||
pub fn part2(lines: [][]const u8) u32 {
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const lines = input.lines;
|
||||
|
||||
var sum: u32 = 0;
|
||||
for (lines) |line| {
|
||||
var first_digit: u8 = 0;
|
||||
@ -84,23 +90,24 @@ pub fn part2(lines: [][]const u8) u32 {
|
||||
sum += number;
|
||||
}
|
||||
|
||||
return sum;
|
||||
return .{ .uint = sum };
|
||||
}
|
||||
|
||||
test "part 1 example" {
|
||||
var input = [_][]const u8{
|
||||
var lines = [_][]const u8{
|
||||
"1abc2",
|
||||
"pqr3stu8vwx",
|
||||
"a1b2c3d4e5f",
|
||||
"treb7uchet",
|
||||
};
|
||||
var actual = part1(&input);
|
||||
var input = aoc.Input{ .lines = &lines, .allocator = std.testing.allocator };
|
||||
var actual = try part1(&input);
|
||||
var expected: u32 = 142;
|
||||
try std.testing.expectEqual(expected, actual);
|
||||
try std.testing.expectEqual(expected, actual.uint);
|
||||
}
|
||||
|
||||
test "part 2 example" {
|
||||
var input = [_][]const u8{
|
||||
var lines = [_][]const u8{
|
||||
"two1nine",
|
||||
"eightwothree",
|
||||
"abcone2threexyz",
|
||||
@ -109,7 +116,8 @@ test "part 2 example" {
|
||||
"zoneight234",
|
||||
"7pqrstsixteen",
|
||||
};
|
||||
var actual = part2(&input);
|
||||
var input = aoc.Input{ .lines = &lines, .allocator = std.testing.allocator };
|
||||
var actual = try part2(&input);
|
||||
var expected: u32 = 281;
|
||||
try std.testing.expectEqual(expected, actual);
|
||||
try std.testing.expectEqual(expected, actual.uint);
|
||||
}
|
||||
|
29
src/day2.zig
29
src/day2.zig
@ -1,4 +1,5 @@
|
||||
const std = @import("std");
|
||||
const aoc = @import("./aoc.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const Cube = enum { Red, Green, Blue };
|
||||
@ -49,7 +50,10 @@ fn parse_games(allocator: Allocator, lines: [][]const u8) ![]Game {
|
||||
return games;
|
||||
}
|
||||
|
||||
pub fn part1(allocator: Allocator, lines: [][]const u8) !u32 {
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const lines = input.lines;
|
||||
const allocator = input.allocator;
|
||||
|
||||
var games = try parse_games(allocator, lines);
|
||||
defer allocator.free(games);
|
||||
|
||||
@ -58,7 +62,6 @@ pub fn part1(allocator: Allocator, lines: [][]const u8) !u32 {
|
||||
const max_blue = 14;
|
||||
var sum: u32 = 0;
|
||||
for (1.., games) |idx, game| {
|
||||
|
||||
var possible = true;
|
||||
for (game.sets[0..game.set_count]) |cube_set| {
|
||||
if ((cube_set.get(.Red) > max_red) or (cube_set.get(.Blue) > max_blue) or (cube_set.get(.Green) > max_green)) {
|
||||
@ -72,10 +75,12 @@ pub fn part1(allocator: Allocator, lines: [][]const u8) !u32 {
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
return .{ .uint = sum };
|
||||
}
|
||||
|
||||
pub fn part2(allocator: Allocator, lines: [][]const u8) !u32 {
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const lines = input.lines;
|
||||
const allocator = input.allocator;
|
||||
var games = try parse_games(allocator, lines);
|
||||
defer allocator.free(games);
|
||||
|
||||
@ -94,31 +99,33 @@ pub fn part2(allocator: Allocator, lines: [][]const u8) !u32 {
|
||||
sum += max_red*max_green*max_blue;
|
||||
}
|
||||
|
||||
return sum;
|
||||
return .{ .uint = sum };
|
||||
}
|
||||
|
||||
test "part 1 example" {
|
||||
var input = [_][]const u8{
|
||||
var lines = [_][]const u8{
|
||||
"Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green",
|
||||
"Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue",
|
||||
"Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red",
|
||||
"Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red",
|
||||
"Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green"
|
||||
};
|
||||
var actual = try part1(std.testing.allocator, &input);
|
||||
var input = aoc.Input{ .lines = &lines, .allocator = std.testing.allocator };
|
||||
var actual = try part1(&input);
|
||||
var expected: u32 = 8;
|
||||
try std.testing.expectEqual(expected, actual);
|
||||
try std.testing.expectEqual(expected, actual.uint);
|
||||
}
|
||||
|
||||
test "part 2 example" {
|
||||
var input = [_][]const u8{
|
||||
var lines = [_][]const u8{
|
||||
"Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green",
|
||||
"Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue",
|
||||
"Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red",
|
||||
"Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red",
|
||||
"Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green"
|
||||
};
|
||||
var actual = try part2(std.testing.allocator, &input);
|
||||
var input = aoc.Input{ .lines = &lines, .allocator = std.testing.allocator };
|
||||
var actual = try part2(&input);
|
||||
var expected: u32 = 2286;
|
||||
try std.testing.expectEqual(expected, actual);
|
||||
try std.testing.expectEqual(expected, actual.uint);
|
||||
}
|
||||
|
78
src/main.zig
78
src/main.zig
@ -1,17 +1,60 @@
|
||||
const std = @import("std");
|
||||
const aoc = @import("./aoc.zig");
|
||||
const cli = @import("./cli.zig");
|
||||
|
||||
const StringArray = std.ArrayList([]const u8);
|
||||
const DayHashMap = std.StringHashMap(aoc.Day);
|
||||
|
||||
const Day1 = @import("./day1.zig");
|
||||
const Day2 = @import("./day2.zig");
|
||||
fn create_day(comptime module: anytype) aoc.Day {
|
||||
var part1: ?aoc.Solver = null;
|
||||
if (@hasDecl(module, "part1")) {
|
||||
part1 = @field(module, "part1");
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
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"))
|
||||
};
|
||||
|
||||
pub fn main() !u8 {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const allocator = gpa.allocator();
|
||||
defer {
|
||||
if (gpa.deinit() == .leak) @panic("Leaked memory");
|
||||
}
|
||||
|
||||
var file = try std.fs.cwd().openFile("input.txt", .{});
|
||||
var args = cli.init(allocator) catch |err| switch (err) {
|
||||
error.cli => return 255,
|
||||
else => return err
|
||||
} ;
|
||||
defer args.deinit();
|
||||
|
||||
if (args.day > Days.len) {
|
||||
std.debug.print("ERROR: Day {} does not exist\n", .{args.day});
|
||||
return 255;
|
||||
}
|
||||
|
||||
var 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());
|
||||
@ -31,9 +74,28 @@ pub fn main() !void {
|
||||
try lines.append(try allocator.dupe(u8, trimmed_line));
|
||||
}
|
||||
|
||||
// std.debug.print("day1: {d}\n", .{Day1.part1(lines.items)});
|
||||
// std.debug.print("day2: {d}\n", .{Day1.part2(lines.items)});
|
||||
var input = aoc.Input{ .allocator = allocator, .lines = lines.items };
|
||||
|
||||
std.debug.print("day1: {d}\n", .{try Day2.part1(allocator, lines.items)});
|
||||
std.debug.print("day2: {d}\n", .{try Day2.part2(allocator, lines.items)});
|
||||
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;
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
.uint => std.debug.print("{}\n", .{result.uint}),
|
||||
.float => std.debug.print("{}\n", .{result.float}),
|
||||
.int => std.debug.print("{}\n", .{result.int}),
|
||||
.text => std.debug.print("{s}\n", .{result.text}),
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
test {
|
||||
_ = @import("day1.zig");
|
||||
_ = @import("day2.zig");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user