summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Segundo2022-12-05 17:00:08 +0100
committerChristian Segundo2022-12-05 22:16:11 +0100
commit061a5bae272f45db6dcde99746922735f9769d25 (patch)
treee4dd9b6d903930c5c1b76286b4a08beea6f59162
parent8817203517907ef4248bde7474e6fb566515d6a7 (diff)
downloadadvent-of-zig-2022-061a5bae272f45db6dcde99746922735f9769d25.tar.gz
add day 5
-rw-r--r--.github/workflows/benchmark.yml21
-rw-r--r--Dockerfile15
-rw-r--r--Makefile35
-rw-r--r--README.md14
-rwxr-xr-xbin/aoc-2022bin0 -> 97651 bytes
-rw-r--r--build.zig30
l---------day-1/util1
l---------day-2/util1
l---------day-3/util1
l---------day-4/util1
-rw-r--r--day_01.zig (renamed from day-1/main.zig)25
-rw-r--r--day_02.zig (renamed from day-2/main.zig)10
-rw-r--r--day_03.zig (renamed from day-3/main.zig)25
-rw-r--r--day_04.zig (renamed from day-4/main.zig)9
-rw-r--r--day_05.zig138
-rw-r--r--inputs/day_01 (renamed from day-1/input)0
-rw-r--r--inputs/day_02 (renamed from day-2/input)0
-rw-r--r--inputs/day_03 (renamed from day-3/input)0
-rw-r--r--inputs/day_04 (renamed from day-4/input)0
-rw-r--r--inputs/day_05513
-rw-r--r--main.zig115
-rw-r--r--util/aoc.zig20
-rw-r--r--util/mem.zig19
23 files changed, 901 insertions, 92 deletions
diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml
new file mode 100644
index 0000000..f8dbc2b
--- /dev/null
+++ b/.github/workflows/benchmark.yml
@@ -0,0 +1,21 @@
+---
+name: Run benchmarks
+
+on:
+ workflow_dispatch:
+
+jobs:
+ update:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ ref: ${{ github.ref }}
+ fetch-depth: 0
+ - run: make docker-benchmark
+ - run: |
+ git config user.email 'actions@github.com'
+ git config user.name 'github-actions'
+ if git commit -am ':robot: Update README.md'; then
+ git push origin HEAD:${{ github.ref }}
+ fi
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..adfd1ab
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,15 @@
+FROM alpine:3.16
+
+ARG ZIG_VERSION
+
+RUN apk update && \
+ apk --no-cache add \
+ curl \
+ make \
+ musl-dev \
+ libarchive-tools && \
+ if echo ${ZIG_VERSION} | grep -q "dev"; then PREFIX=builds; else PREFIX="download/${ZIG_VERSION}"; fi && \
+ curl -s \
+ https://ziglang.org/${PREFIX}/zig-linux-x86_64-${ZIG_VERSION}.tar.xz |\
+ bsdtar -x -f - && \
+ mv zig-linux-x86_64-${ZIG_VERSION}/* /usr/local/bin/
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..6285dbf
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,35 @@
+ZIG_VERSION=0.11.0-dev.149+7733246d6
+IMAGE_NAME=zigci
+
+all: clean test fmt benchmark
+
+clean:
+ $(RM) -rf zig-cache bin README.md
+
+test:
+ zig build test
+
+build:
+ zig build -p .
+
+benchmark: build
+ echo '```' > README.md
+ ./bin/aoc-2022 2>> README.md
+ echo '```' >> README.md
+
+fmt:
+ find . -name "*.zig" -exec zig fmt --check {} \;
+
+docker-build:
+ docker build \
+ -t $(IMAGE_NAME) \
+ --build-arg ZIG_VERSION=$(ZIG_VERSION) \
+ -f Dockerfile .
+
+docker-%: docker-build
+ docker run \
+ --rm \
+ --privileged \
+ -v $(shell pwd):/data \
+ -w /data $(DOCKER_EXTRA_ARGS) \
+ $(IMAGE_NAME) sh -c "make $*"
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..de3da84
--- /dev/null
+++ b/README.md
@@ -0,0 +1,14 @@
+```
+
+day=1, puzzle_1=69912, input_bytes=10517, time=102µs
+day=1, puzzle_2=208180, input_bytes=10517, time=61µs
+
+day=2, puzzle_1=12855, input_bytes=10000, time=62µs
+day=2, puzzle_2=13726, input_bytes=10000, time=70µs
+
+day=3, puzzle_1=8039, input_bytes=9946, time=33µs
+day=3, puzzle_2=2510, input_bytes=9946, time=43µs
+
+day=4, puzzle_1=483, input_bytes=11399, time=195µs
+day=4, puzzle_2=874, input_bytes=11399, time=151µs
+```
diff --git a/bin/aoc-2022 b/bin/aoc-2022
new file mode 100755
index 0000000..7d7dca3
--- /dev/null
+++ b/bin/aoc-2022
Binary files differ
diff --git a/build.zig b/build.zig
new file mode 100644
index 0000000..ab47001
--- /dev/null
+++ b/build.zig
@@ -0,0 +1,30 @@
+const std = @import("std");
+
+pub fn build(b: *std.build.Builder) void {
+ // Standard target options allows the person running `zig build` to choose
+ // what target to build for. Here we do not override the defaults, which
+ // means any target is allowed, and the default is native. Other options
+ // for restricting supported target set are available.
+ const target = b.standardTargetOptions(.{});
+
+ const exe = b.addExecutable("aoc-2022", "main.zig");
+ exe.setTarget(target);
+ exe.setBuildMode(std.builtin.Mode.ReleaseFast);
+ exe.install();
+
+ const run_cmd = exe.run();
+ run_cmd.step.dependOn(b.getInstallStep());
+ if (b.args) |args| {
+ run_cmd.addArgs(args);
+ }
+
+ const run_step = b.step("run", "Run the app");
+ run_step.dependOn(&run_cmd.step);
+
+ const exe_tests = b.addTest("main.zig");
+ exe_tests.setTarget(target);
+ exe_tests.setBuildMode(std.builtin.Mode.Debug);
+
+ const test_step = b.step("test", "Run unit tests");
+ test_step.dependOn(&exe_tests.step);
+}
diff --git a/day-1/util b/day-1/util
deleted file mode 120000
index 40c3fc5..0000000
--- a/day-1/util
+++ /dev/null
@@ -1 +0,0 @@
-../util \ No newline at end of file
diff --git a/day-2/util b/day-2/util
deleted file mode 120000
index 40c3fc5..0000000
--- a/day-2/util
+++ /dev/null
@@ -1 +0,0 @@
-../util \ No newline at end of file
diff --git a/day-3/util b/day-3/util
deleted file mode 120000
index 40c3fc5..0000000
--- a/day-3/util
+++ /dev/null
@@ -1 +0,0 @@
-../util \ No newline at end of file
diff --git a/day-4/util b/day-4/util
deleted file mode 120000
index 40c3fc5..0000000
--- a/day-4/util
+++ /dev/null
@@ -1 +0,0 @@
-../util \ No newline at end of file
diff --git a/day-1/main.zig b/day_01.zig
index d985c9b..80bb649 100644
--- a/day-1/main.zig
+++ b/day_01.zig
@@ -1,7 +1,8 @@
const std = @import("std");
-const min_idx = @import("util/mem.zig").min_idx;
+const math = std.math;
+const Result = @import("util/aoc.zig").Result;
-pub fn puzzle_1(input: []const u8) !i32 {
+pub fn puzzle_1(input: []const u8) !Result {
var iter = std.mem.split(u8, input, "\n");
var count: i32 = 0;
var max: i32 = 0;
@@ -17,10 +18,10 @@ pub fn puzzle_1(input: []const u8) !i32 {
}
}
- return max;
+ return .{ .int = max };
}
-pub fn puzzle_2(input: []const u8) !i32 {
+pub fn puzzle_2(input: []const u8) !Result {
var iter = std.mem.split(u8, input, "\n");
var count: i32 = 0;
var max: [3]i32 = std.mem.zeroes([3]i32);
@@ -42,5 +43,19 @@ pub fn puzzle_2(input: []const u8) !i32 {
count += v;
}
- return count;
+ return .{ .int = count };
+}
+
+fn min_idx(comptime T: type, slice: []const T) usize {
+ var best = slice[0];
+ var idx: usize = 0;
+
+ for (slice[1..]) |item, i| {
+ const possible_best = math.min(best, item);
+ if (best > possible_best) {
+ best = possible_best;
+ idx = i + 1;
+ }
+ }
+ return idx;
}
diff --git a/day-2/main.zig b/day_02.zig
index 3289ad2..ce5e165 100644
--- a/day-2/main.zig
+++ b/day_02.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const slurp = @import("util/file.zig").slurp;
+const Result = @import("util/aoc.zig").Result;
const Hand = enum(u8) { Rock = 1, Paper = 2, Scissors = 3 };
const Outcome = enum(u8) { Win = 6, Draw = 3, Lose = 0 };
@@ -79,7 +79,7 @@ const match_impl = struct {
}
};
-pub fn puzzle_1(input: []const u8) u16 {
+pub fn puzzle_1(input: []const u8) Result {
var iter = std.mem.split(u8, input, "\n");
var score: u16 = 0;
@@ -91,10 +91,10 @@ pub fn puzzle_1(input: []const u8) u16 {
);
}
- return score;
+ return .{ .int = score };
}
-pub fn puzzle_2(input: []const u8) u16 {
+pub fn puzzle_2(input: []const u8) Result {
var iter = std.mem.split(u8, input, "\n");
var score: u16 = 0;
@@ -106,5 +106,5 @@ pub fn puzzle_2(input: []const u8) u16 {
);
}
- return score;
+ return .{ .int = score };
}
diff --git a/day-3/main.zig b/day_03.zig
index 57057bf..b33c5cf 100644
--- a/day-3/main.zig
+++ b/day_03.zig
@@ -1,6 +1,7 @@
const std = @import("std");
+const Result = @import("util/aoc.zig").Result;
-pub fn puzzle_1(input: []const u8) u16 {
+pub fn puzzle_1(input: []const u8) Result {
var iter = std.mem.split(u8, input, "\n");
var count: u16 = 0;
@@ -8,18 +9,34 @@ pub fn puzzle_1(input: []const u8) u16 {
var p1: u64 = 0;
var p2: u64 = 0;
+ // A note to whoever reads this in the future
+ // A to Z -> 65 to 90
+ // a to z -> 97 to 122
+ //
+ // u64 is ok
+ // 90 - 65 + 122 - 97 = 50
+
for (line[0 .. line.len / 2]) |_, i| {
p1 |= @as(u64, 1) << @intCast(u6, line[i] - 65); // 65 == 'A'
p2 |= @as(u64, 1) << @intCast(u6, line[i + line.len / 2] - 65);
}
+ // Example
+ //
+ // p1: 0000000101100010001000110000000000011000000011000010000100
+ // p2: 1000001000000000000110000000000000000001011001100001100000
+ //
+ // &: 0000000000000000000000000000000000000000000001000000000000 = 46 0s
+ //
+ // 65 + 63 - 46 = 82 = R
+
count += char_to_priority(@intCast(u8, 65 + 63) - @clz(p1 & p2));
}
- return count;
+ return .{ .int = count };
}
-pub fn puzzle_2(input: []const u8) u16 {
+pub fn puzzle_2(input: []const u8) Result {
var iter = std.mem.split(u8, input, "\n");
var count: u16 = 0;
@@ -36,7 +53,7 @@ pub fn puzzle_2(input: []const u8) u16 {
count += char_to_priority(@intCast(u8, 65 + 63) - @clz(parts[0] & parts[1] & parts[2]));
}
- return count;
+ return .{ .int = count };
}
fn char_to_priority(char: u8) u8 {
diff --git a/day-4/main.zig b/day_04.zig
index 6c0d193..0fa2fdb 100644
--- a/day-4/main.zig
+++ b/day_04.zig
@@ -1,6 +1,7 @@
const std = @import("std");
+const Result = @import("util/aoc.zig").Result;
-pub fn puzzle_1(input: []const u8) !u16 {
+pub fn puzzle_1(input: []const u8) !Result {
var iter = std.mem.split(u8, input, "\n");
var count: u16 = 0;
@@ -12,10 +13,10 @@ pub fn puzzle_1(input: []const u8) !u16 {
count += 1;
}
- return count;
+ return .{ .int = count };
}
-pub fn puzzle_2(input: []const u8) !u16 {
+pub fn puzzle_2(input: []const u8) !Result {
var iter = std.mem.split(u8, input, "\n");
var count: u16 = 0;
@@ -27,7 +28,7 @@ pub fn puzzle_2(input: []const u8) !u16 {
count += 1;
}
- return count;
+ return .{ .int = count };
}
fn parse_range(line: []const u8) ![2][2]u8 {
diff --git a/day_05.zig b/day_05.zig
new file mode 100644
index 0000000..884fd81
--- /dev/null
+++ b/day_05.zig
@@ -0,0 +1,138 @@
+const std = @import("std");
+const Result = @import("util/aoc.zig").Result;
+
+const MAX_HEIGHT = 100;
+
+const Command = struct { From: u8, To: u8, Crates: u8 };
+const Data = struct {
+ Commands: []Command,
+ Crates: [][MAX_HEIGHT]u8,
+
+ fn deinit(self: Data, allocator: std.mem.Allocator) void {
+ allocator.free(self.Commands);
+ allocator.free(self.Crates);
+ }
+};
+
+pub fn puzzle_1(allocator: std.mem.Allocator, input: []const u8) !Result {
+ var data = try parse_input(allocator, input);
+ defer data.deinit(allocator);
+
+ for (data.Commands) |command| {
+ var command_crates = command.Crates;
+
+ while (command_crates > 0) : (command_crates -= 1) {
+ if (command_crates == 0) break;
+ const tmp = data.Crates[command.From][len(data.Crates[command.From]) - 1];
+ data.Crates[command.From][len(data.Crates[command.From]) - 1] = 0;
+ data.Crates[command.To][len(data.Crates[command.To])] = tmp;
+ }
+ }
+
+ return build_answer(allocator, data.Crates);
+}
+
+pub fn puzzle_2(allocator: std.mem.Allocator, input: []const u8) !Result {
+ var data = try parse_input(allocator, input);
+ defer data.deinit(allocator);
+
+ for (data.Commands) |command| {
+ var command_crates = command.Crates;
+
+ const crate_stack = blk: {
+ var r = std.mem.zeroes([MAX_HEIGHT]u8);
+ var idx: usize = 0;
+
+ while (command_crates > 0) : (command_crates -= 1) {
+ if (command_crates == 0) break;
+ r[idx] = data.Crates[command.From][len(data.Crates[command.From]) - 1];
+ data.Crates[command.From][len(data.Crates[command.From]) - 1] = 0;
+ idx += 1;
+ }
+
+ break :blk r;
+ };
+ var crate_stack_height = len(crate_stack);
+
+ while (true) {
+ data.Crates[command.To][len(data.Crates[command.To])] = crate_stack[crate_stack_height];
+ if (crate_stack_height == 0) break;
+ crate_stack_height -= 1;
+ }
+ }
+
+ return build_answer(allocator, data.Crates);
+}
+
+fn build_answer(allocator: std.mem.Allocator, crates: [][MAX_HEIGHT]u8) !Result {
+ var i: usize = 0;
+ var r = try std.ArrayList(u8).initCapacity(allocator, crates.len);
+ while (i < crates.len) : (i += 1) {
+ r.appendAssumeCapacity(crates[i][len(crates[i]) - 1]);
+ }
+
+ return .{ .string = r.toOwnedSlice() };
+}
+
+fn parse_input(allocator: std.mem.Allocator, input: []const u8) !Data {
+ var iter = std.mem.split(u8, input, "\n");
+
+ var floor: u8 = 0;
+ var rows: u8 = 0;
+
+ while (iter.next()) |line| : (floor += 1) {
+ if (line[1] == '1') {
+ var rows_iter = std.mem.splitBackwards(u8, line, " ");
+ _ = rows_iter.next();
+ rows = try std.fmt.parseInt(u8, rows_iter.next() orelse unreachable, 0);
+ iter.reset();
+ break;
+ }
+ }
+
+ var crates = blk: {
+ var r = try std.ArrayList([MAX_HEIGHT]u8).initCapacity(allocator, rows);
+ var i: usize = 0;
+ while (i < rows) : (i += 1) r.appendAssumeCapacity(std.mem.zeroes([MAX_HEIGHT]u8));
+ break :blk r.toOwnedSlice();
+ };
+
+ while (iter.next()) |line| : (floor -= 1) {
+ if (floor == 0) break;
+
+ var row: usize = 0;
+ var offset: usize = 1;
+ while (row < rows) : (row += 1) {
+ if (line[offset] != ' ')
+ crates[row][floor - 1] = line[offset];
+ offset += 4;
+ }
+ }
+
+ // There is an extra line between floor and commands
+ iter.index = iter.index.? + 1;
+ var commands = std.ArrayList(Command).init(allocator);
+ var i: usize = 0;
+ while (iter.next()) |line| : (i += 1) {
+ var command: Command = undefined;
+ var line_iter = std.mem.split(u8, line, " ");
+ _ = line_iter.next(); // move
+ command.Crates = try std.fmt.parseInt(u8, line_iter.next() orelse unreachable, 0);
+ _ = line_iter.next(); // from
+ command.From = try std.fmt.parseInt(u8, line_iter.next() orelse unreachable, 0) - 1;
+ _ = line_iter.next(); // to
+ command.To = try std.fmt.parseInt(u8, line_iter.next() orelse unreachable, 0) - 1;
+ try commands.append(command);
+ }
+ return .{ .Commands = commands.toOwnedSlice(), .Crates = crates };
+}
+
+fn len(row: [MAX_HEIGHT]u8) usize {
+ for (row) |v, i| {
+ if (v == 0) {
+ if (i > 0) return i;
+ return 0;
+ }
+ }
+ unreachable;
+}
diff --git a/day-1/input b/inputs/day_01
index 6c1f923..6c1f923 100644
--- a/day-1/input
+++ b/inputs/day_01
diff --git a/day-2/input b/inputs/day_02
index e49a6c4..e49a6c4 100644
--- a/day-2/input
+++ b/inputs/day_02
diff --git a/day-3/input b/inputs/day_03
index fca63f0..fca63f0 100644
--- a/day-3/input
+++ b/inputs/day_03
diff --git a/day-4/input b/inputs/day_04
index cbdde37..cbdde37 100644
--- a/day-4/input
+++ b/inputs/day_04
diff --git a/inputs/day_05 b/inputs/day_05
new file mode 100644
index 0000000..a572b71
--- /dev/null
+++ b/inputs/day_05
@@ -0,0 +1,513 @@
+[G] [D] [R]
+[W] [V] [C] [T] [M]
+[L] [P] [Z] [Q] [F] [V]
+[J] [S] [D] [J] [M] [T] [V]
+[B] [M] [H] [L] [Z] [J] [B] [S]
+[R] [C] [T] [C] [T] [R] [D] [R] [D]
+[T] [W] [Z] [T] [P] [B] [B] [H] [P]
+[D] [S] [R] [D] [G] [F] [S] [L] [Q]
+ 1 2 3 4 5 6 7 8 9
+
+move 1 from 3 to 5
+move 5 from 5 to 4
+move 6 from 7 to 3
+move 6 from 1 to 3
+move 1 from 1 to 9
+move 1 from 1 to 4
+move 3 from 6 to 9
+move 2 from 7 to 5
+move 1 from 5 to 7
+move 1 from 7 to 2
+move 2 from 2 to 5
+move 2 from 6 to 3
+move 6 from 8 to 9
+move 7 from 3 to 9
+move 1 from 8 to 7
+move 8 from 9 to 7
+move 5 from 4 to 8
+move 1 from 6 to 2
+move 2 from 8 to 4
+move 9 from 9 to 1
+move 2 from 8 to 5
+move 1 from 8 to 5
+move 5 from 9 to 2
+move 1 from 6 to 8
+move 5 from 1 to 7
+move 1 from 8 to 2
+move 2 from 1 to 7
+move 1 from 2 to 6
+move 4 from 5 to 4
+move 2 from 1 to 4
+move 13 from 7 to 8
+move 3 from 8 to 6
+move 2 from 6 to 8
+move 10 from 3 to 5
+move 2 from 7 to 6
+move 3 from 5 to 6
+move 10 from 8 to 1
+move 1 from 8 to 6
+move 6 from 2 to 4
+move 1 from 5 to 8
+move 5 from 6 to 3
+move 2 from 8 to 6
+move 1 from 7 to 9
+move 2 from 2 to 7
+move 3 from 5 to 1
+move 2 from 7 to 2
+move 6 from 6 to 3
+move 7 from 5 to 6
+move 5 from 3 to 2
+move 10 from 1 to 8
+move 2 from 1 to 3
+move 8 from 3 to 7
+move 9 from 4 to 8
+move 1 from 9 to 2
+move 2 from 7 to 8
+move 4 from 6 to 9
+move 1 from 4 to 9
+move 5 from 7 to 4
+move 3 from 6 to 5
+move 1 from 1 to 5
+move 14 from 4 to 8
+move 3 from 9 to 7
+move 4 from 5 to 9
+move 2 from 4 to 1
+move 27 from 8 to 6
+move 2 from 7 to 2
+move 2 from 7 to 4
+move 4 from 2 to 9
+move 7 from 8 to 4
+move 10 from 4 to 1
+move 18 from 6 to 5
+move 6 from 9 to 2
+move 1 from 9 to 5
+move 11 from 2 to 6
+move 2 from 5 to 4
+move 1 from 2 to 8
+move 2 from 4 to 9
+move 2 from 8 to 3
+move 1 from 6 to 8
+move 4 from 9 to 7
+move 4 from 7 to 8
+move 7 from 5 to 1
+move 4 from 6 to 3
+move 2 from 3 to 7
+move 6 from 5 to 3
+move 2 from 8 to 2
+move 14 from 6 to 2
+move 3 from 8 to 1
+move 15 from 2 to 3
+move 1 from 6 to 1
+move 14 from 3 to 2
+move 2 from 2 to 5
+move 1 from 9 to 3
+move 13 from 1 to 3
+move 4 from 2 to 6
+move 10 from 1 to 3
+move 2 from 6 to 9
+move 6 from 2 to 9
+move 6 from 5 to 2
+move 2 from 6 to 8
+move 7 from 9 to 5
+move 1 from 5 to 8
+move 2 from 7 to 6
+move 34 from 3 to 6
+move 19 from 6 to 2
+move 12 from 6 to 9
+move 3 from 6 to 3
+move 2 from 3 to 2
+move 1 from 6 to 5
+move 17 from 2 to 8
+move 2 from 3 to 2
+move 8 from 9 to 4
+move 7 from 5 to 2
+move 5 from 4 to 1
+move 4 from 1 to 6
+move 1 from 1 to 6
+move 6 from 6 to 8
+move 2 from 8 to 4
+move 17 from 8 to 6
+move 2 from 4 to 5
+move 17 from 6 to 9
+move 22 from 9 to 7
+move 1 from 5 to 2
+move 20 from 2 to 7
+move 29 from 7 to 9
+move 1 from 4 to 7
+move 3 from 8 to 3
+move 1 from 8 to 5
+move 3 from 8 to 2
+move 2 from 2 to 4
+move 27 from 9 to 7
+move 2 from 3 to 2
+move 1 from 5 to 2
+move 18 from 7 to 5
+move 1 from 3 to 2
+move 1 from 5 to 6
+move 18 from 5 to 3
+move 1 from 6 to 3
+move 2 from 9 to 5
+move 10 from 3 to 5
+move 4 from 3 to 6
+move 1 from 7 to 1
+move 1 from 5 to 1
+move 6 from 7 to 6
+move 1 from 6 to 2
+move 4 from 4 to 8
+move 5 from 5 to 4
+move 1 from 3 to 8
+move 2 from 1 to 8
+move 2 from 2 to 5
+move 3 from 3 to 8
+move 6 from 8 to 2
+move 1 from 3 to 9
+move 1 from 6 to 3
+move 6 from 2 to 8
+move 7 from 8 to 4
+move 8 from 5 to 2
+move 5 from 4 to 6
+move 2 from 8 to 3
+move 2 from 3 to 9
+move 1 from 3 to 9
+move 2 from 7 to 1
+move 2 from 1 to 2
+move 12 from 2 to 4
+move 1 from 9 to 7
+move 1 from 6 to 2
+move 9 from 7 to 9
+move 1 from 8 to 2
+move 9 from 9 to 8
+move 6 from 7 to 8
+move 4 from 4 to 1
+move 6 from 2 to 5
+move 1 from 4 to 9
+move 3 from 1 to 9
+move 6 from 4 to 5
+move 5 from 8 to 9
+move 8 from 4 to 6
+move 3 from 9 to 8
+move 1 from 9 to 3
+move 3 from 8 to 3
+move 5 from 9 to 2
+move 3 from 2 to 6
+move 3 from 6 to 9
+move 3 from 6 to 2
+move 4 from 2 to 6
+move 6 from 9 to 7
+move 1 from 1 to 8
+move 8 from 8 to 5
+move 20 from 5 to 3
+move 2 from 2 to 8
+move 6 from 7 to 1
+move 10 from 6 to 3
+move 4 from 6 to 7
+move 4 from 1 to 9
+move 2 from 1 to 2
+move 3 from 6 to 9
+move 5 from 8 to 3
+move 3 from 7 to 9
+move 17 from 3 to 2
+move 1 from 6 to 2
+move 2 from 6 to 9
+move 1 from 6 to 4
+move 12 from 9 to 2
+move 1 from 4 to 7
+move 8 from 3 to 8
+move 8 from 8 to 9
+move 7 from 9 to 2
+move 1 from 9 to 7
+move 18 from 2 to 9
+move 1 from 7 to 2
+move 2 from 7 to 1
+move 1 from 1 to 2
+move 4 from 2 to 7
+move 15 from 9 to 3
+move 1 from 9 to 1
+move 2 from 1 to 8
+move 6 from 2 to 4
+move 8 from 2 to 1
+move 2 from 8 to 5
+move 2 from 9 to 3
+move 4 from 4 to 1
+move 2 from 5 to 8
+move 2 from 8 to 9
+move 14 from 3 to 1
+move 2 from 9 to 7
+move 2 from 4 to 3
+move 1 from 2 to 9
+move 5 from 7 to 9
+move 21 from 1 to 9
+move 2 from 1 to 6
+move 3 from 2 to 4
+move 1 from 7 to 3
+move 19 from 9 to 5
+move 1 from 2 to 7
+move 1 from 7 to 2
+move 3 from 4 to 2
+move 19 from 5 to 7
+move 2 from 2 to 5
+move 1 from 5 to 3
+move 1 from 3 to 4
+move 8 from 9 to 4
+move 1 from 6 to 3
+move 1 from 2 to 6
+move 1 from 2 to 1
+move 8 from 7 to 3
+move 5 from 4 to 7
+move 2 from 6 to 4
+move 1 from 5 to 9
+move 1 from 1 to 6
+move 1 from 1 to 2
+move 2 from 4 to 7
+move 1 from 4 to 2
+move 2 from 4 to 9
+move 1 from 6 to 8
+move 1 from 1 to 5
+move 1 from 8 to 6
+move 1 from 1 to 4
+move 25 from 3 to 1
+move 1 from 4 to 2
+move 2 from 3 to 6
+move 3 from 1 to 9
+move 6 from 9 to 8
+move 1 from 6 to 3
+move 1 from 2 to 9
+move 15 from 7 to 6
+move 2 from 2 to 6
+move 1 from 3 to 8
+move 1 from 1 to 4
+move 6 from 8 to 4
+move 1 from 3 to 8
+move 1 from 8 to 5
+move 2 from 5 to 2
+move 8 from 6 to 7
+move 1 from 8 to 7
+move 1 from 9 to 4
+move 9 from 4 to 5
+move 19 from 1 to 3
+move 9 from 3 to 5
+move 6 from 7 to 2
+move 2 from 1 to 7
+move 7 from 2 to 4
+move 7 from 5 to 6
+move 5 from 4 to 3
+move 3 from 5 to 8
+move 1 from 2 to 4
+move 2 from 4 to 8
+move 14 from 6 to 1
+move 6 from 5 to 6
+move 1 from 5 to 2
+move 7 from 1 to 6
+move 1 from 2 to 4
+move 4 from 6 to 4
+move 1 from 5 to 4
+move 2 from 1 to 9
+move 2 from 9 to 4
+move 2 from 1 to 8
+move 9 from 3 to 6
+move 3 from 7 to 4
+move 4 from 8 to 6
+move 3 from 7 to 6
+move 1 from 7 to 2
+move 1 from 7 to 5
+move 3 from 8 to 4
+move 26 from 6 to 1
+move 8 from 1 to 2
+move 1 from 6 to 4
+move 5 from 2 to 7
+move 2 from 2 to 4
+move 10 from 4 to 7
+move 1 from 6 to 1
+move 22 from 1 to 2
+move 1 from 6 to 1
+move 6 from 4 to 7
+move 1 from 5 to 1
+move 1 from 1 to 2
+move 21 from 7 to 2
+move 38 from 2 to 3
+move 8 from 2 to 6
+move 2 from 4 to 8
+move 2 from 8 to 2
+move 1 from 1 to 3
+move 1 from 2 to 8
+move 1 from 2 to 5
+move 6 from 6 to 4
+move 2 from 4 to 2
+move 2 from 2 to 6
+move 1 from 8 to 2
+move 28 from 3 to 1
+move 11 from 1 to 2
+move 8 from 1 to 7
+move 4 from 6 to 4
+move 8 from 3 to 1
+move 8 from 2 to 5
+move 6 from 5 to 4
+move 2 from 5 to 4
+move 8 from 3 to 4
+move 22 from 4 to 1
+move 2 from 3 to 5
+move 33 from 1 to 5
+move 26 from 5 to 6
+move 4 from 5 to 7
+move 2 from 2 to 7
+move 2 from 7 to 2
+move 2 from 7 to 8
+move 2 from 8 to 3
+move 6 from 1 to 3
+move 5 from 5 to 1
+move 1 from 5 to 7
+move 7 from 7 to 5
+move 4 from 5 to 6
+move 5 from 1 to 8
+move 4 from 2 to 4
+move 2 from 7 to 4
+move 2 from 7 to 3
+move 5 from 4 to 6
+move 1 from 8 to 2
+move 1 from 2 to 4
+move 10 from 3 to 6
+move 44 from 6 to 9
+move 2 from 5 to 7
+move 1 from 5 to 8
+move 41 from 9 to 1
+move 1 from 6 to 4
+move 2 from 8 to 1
+move 1 from 7 to 3
+move 1 from 3 to 8
+move 2 from 9 to 8
+move 29 from 1 to 9
+move 2 from 1 to 5
+move 2 from 8 to 3
+move 1 from 3 to 5
+move 2 from 5 to 9
+move 1 from 5 to 7
+move 25 from 9 to 2
+move 10 from 2 to 1
+move 1 from 7 to 8
+move 2 from 4 to 1
+move 2 from 8 to 9
+move 1 from 8 to 6
+move 4 from 2 to 4
+move 4 from 2 to 5
+move 1 from 6 to 5
+move 1 from 2 to 7
+move 2 from 4 to 1
+move 18 from 1 to 3
+move 8 from 9 to 4
+move 15 from 3 to 9
+move 3 from 4 to 8
+move 4 from 5 to 8
+move 4 from 2 to 4
+move 10 from 9 to 4
+move 4 from 8 to 5
+move 2 from 7 to 2
+move 11 from 4 to 9
+move 12 from 4 to 9
+move 2 from 5 to 7
+move 4 from 2 to 4
+move 5 from 8 to 1
+move 1 from 5 to 6
+move 1 from 4 to 6
+move 1 from 3 to 9
+move 1 from 5 to 7
+move 4 from 1 to 6
+move 6 from 1 to 5
+move 6 from 5 to 9
+move 3 from 7 to 6
+move 9 from 6 to 5
+move 8 from 5 to 2
+move 7 from 2 to 3
+move 1 from 3 to 1
+move 7 from 3 to 5
+move 2 from 4 to 1
+move 1 from 2 to 6
+move 2 from 1 to 3
+move 8 from 5 to 9
+move 3 from 1 to 3
+move 1 from 6 to 1
+move 2 from 4 to 1
+move 1 from 5 to 2
+move 2 from 1 to 6
+move 2 from 6 to 3
+move 2 from 3 to 2
+move 2 from 2 to 4
+move 1 from 2 to 6
+move 3 from 3 to 9
+move 2 from 4 to 8
+move 3 from 3 to 1
+move 4 from 1 to 7
+move 2 from 8 to 4
+move 7 from 9 to 6
+move 1 from 1 to 4
+move 11 from 9 to 7
+move 3 from 9 to 3
+move 14 from 9 to 5
+move 6 from 6 to 5
+move 4 from 5 to 9
+move 10 from 7 to 6
+move 1 from 3 to 7
+move 2 from 4 to 1
+move 4 from 7 to 9
+move 9 from 6 to 1
+move 3 from 6 to 5
+move 15 from 9 to 1
+move 1 from 4 to 7
+move 4 from 9 to 7
+move 12 from 5 to 1
+move 3 from 7 to 3
+move 4 from 7 to 2
+move 1 from 9 to 3
+move 22 from 1 to 2
+move 21 from 2 to 6
+move 3 from 1 to 9
+move 1 from 3 to 7
+move 1 from 7 to 3
+move 1 from 3 to 2
+move 8 from 1 to 4
+move 1 from 9 to 2
+move 7 from 4 to 8
+move 3 from 3 to 9
+move 3 from 3 to 5
+move 4 from 2 to 3
+move 1 from 1 to 3
+move 4 from 8 to 5
+move 2 from 8 to 3
+move 5 from 3 to 2
+move 6 from 5 to 3
+move 2 from 5 to 8
+move 2 from 1 to 7
+move 2 from 7 to 4
+move 15 from 6 to 9
+move 8 from 3 to 1
+move 3 from 5 to 9
+move 2 from 4 to 9
+move 8 from 1 to 3
+move 8 from 9 to 8
+move 1 from 1 to 4
+move 3 from 5 to 9
+move 4 from 8 to 1
+move 1 from 3 to 9
+move 2 from 4 to 3
+move 2 from 8 to 6
+move 3 from 8 to 7
+move 8 from 2 to 5
+move 3 from 5 to 2
+move 4 from 3 to 4
+move 3 from 6 to 1
+move 2 from 5 to 9
+move 4 from 4 to 1
+move 2 from 5 to 6
+move 1 from 5 to 4
+move 2 from 2 to 1
+move 4 from 3 to 9
+move 1 from 7 to 3
+move 2 from 7 to 4
+move 2 from 4 to 7
+move 1 from 6 to 7
+move 1 from 2 to 8
+move 2 from 3 to 9
+move 14 from 1 to 8
+move 1 from 6 to 2
+move 2 from 7 to 1
+move 3 from 8 to 3
+move 6 from 8 to 5
diff --git a/main.zig b/main.zig
index 6609a2f..3d0ecb4 100644
--- a/main.zig
+++ b/main.zig
@@ -1,10 +1,72 @@
const std = @import("std");
+const Result = @import("util/aoc.zig").Result;
+
+const t = [_]struct {
+ day: type,
+ expect: []const Result,
+ input: []const u8,
+}{
+ .{ .day = @import("day_01.zig"), .input = @embedFile("inputs/day_01"), .expect = &[_]Result{ .{ .int = 69912 }, .{ .int = 208180 } } },
+ .{ .day = @import("day_02.zig"), .input = @embedFile("inputs/day_02"), .expect = &[_]Result{ .{ .int = 12855 }, .{ .int = 13726 } } },
+ .{ .day = @import("day_03.zig"), .input = @embedFile("inputs/day_03"), .expect = &[_]Result{ .{ .int = 8039 }, .{ .int = 2510 } } },
+ .{ .day = @import("day_04.zig"), .input = @embedFile("inputs/day_04"), .expect = &[_]Result{ .{ .int = 483 }, .{ .int = 874 } } },
+ .{ .day = @import("day_05.zig"), .input = @embedFile("inputs/day_05"), .expect = &[_]Result{ .{ .string = "SHMSDGZVC" }, .{ .string = "VRZGHDFBQ" } } },
+};
+
+pub fn main() !void {
+ var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+ defer arena.deinit();
+ const allocator = arena.allocator();
+ return run_all(allocator);
+}
test {
std.testing.refAllDecls(@This());
}
-fn solve(allocator: std.mem.Allocator, puzzle: anytype, input: []const u8) !i32 {
+fn run_all(allocator: std.mem.Allocator) !void {
+ inline for (t) |aoc_day, day| {
+ std.debug.print("\n", .{});
+ inline for (aoc_day.expect) |expect, idx| {
+ const fn_name = comptimePrint("puzzle_{d}", .{idx + 1});
+ const puzzle = @field(aoc_day.day, fn_name);
+ const start_time = try std.time.Instant.now();
+
+ const result = try solve(
+ allocator,
+ puzzle,
+ aoc_day.input[0 .. aoc_day.input.len - 1], // remove the last '^\n$'
+ );
+ defer result.deinit(allocator);
+
+ const end_time = try std.time.Instant.now();
+ const elapsed_us = end_time.since(start_time) / std.time.ns_per_us;
+
+ std.debug.print("day={d}, input_bytes={d}, time={d}µs, ", .{
+ day + 1,
+ aoc_day.input.len,
+ elapsed_us,
+ });
+
+ switch (result) {
+ .string => |s| std.debug.print("puzzle_{d}={s}", .{ idx + 1, s }),
+ .int => |i| std.debug.print("puzzle_{d}={d}", .{ idx + 1, i }),
+ }
+
+ if (!expect.cmp(result)) {
+ switch (expect) {
+ .string => |s| std.debug.print(", expected={s}\n", .{s}),
+ .int => |i| std.debug.print(", expected={d}\n", .{i}),
+ }
+ return error.UnexpectedValue;
+ }
+
+ std.debug.print("\n", .{});
+ }
+ }
+}
+
+fn solve(allocator: std.mem.Allocator, puzzle: anytype, input: []const u8) !Result {
return blk: {
switch (@typeInfo(@TypeOf(puzzle))) {
.Fn => |f| {
@@ -39,56 +101,7 @@ inline fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [std.fmt
}
test "test" {
- const t = [_]struct {
- day: type,
- expect: []const i32,
- input: []const u8,
- }{
- .{ .day = @import("day-1/main.zig"), .input = @embedFile("day-1/input"), .expect = &[_]i32{ 69912, 208180 } },
- .{ .day = @import("day-2/main.zig"), .input = @embedFile("day-2/input"), .expect = &[_]i32{ 12855, 13726 } },
- .{ .day = @import("day-3/main.zig"), .input = @embedFile("day-3/input"), .expect = &[_]i32{ 8039, 2510 } },
- .{ .day = @import("day-4/main.zig"), .input = @embedFile("day-4/input"), .expect = &[_]i32{ 483, 874 } },
- };
-
std.debug.print("\n", .{});
-
- inline for (t) |aoc_day, day| {
- std.debug.print("\n", .{});
- inline for (aoc_day.expect) |expected, idx| {
- const fn_name = comptimePrint("puzzle_{d}", .{idx + 1});
- const puzzle = @field(aoc_day.day, fn_name);
- const start_time = try std.time.Instant.now();
-
- const result = try solve(
- testing_allocator,
- puzzle,
- aoc_day.input[0 .. aoc_day.input.len - 1], // remove the last '^\n$'
- );
-
- const end_time = try std.time.Instant.now();
- const elapsed_us = end_time.since(start_time) / std.time.ns_per_us;
-
- if (result == expected) {
- std.debug.print("day={d}, puzzle_{d}={d}, input_bytes={d}, time={d}µs\n", .{
- day + 1,
- idx + 1,
- result,
- aoc_day.input.len,
- elapsed_us,
- });
- } else {
- std.debug.print("day={d}, puzzle_{d}={d}, input_bytes={d}, time={d}µs, expected={d}\n", .{
- day + 1,
- idx + 1,
- result,
- aoc_day.input.len,
- elapsed_us,
- expected,
- });
- return error.UnexpectedValue;
- }
- }
- }
-
+ try run_all(testing_allocator);
std.debug.print("\n", .{});
}
diff --git a/util/aoc.zig b/util/aoc.zig
new file mode 100644
index 0000000..0c3e668
--- /dev/null
+++ b/util/aoc.zig
@@ -0,0 +1,20 @@
+const std = @import("std");
+
+pub const Result = union(enum) {
+ int: i32,
+ string: []const u8,
+
+ pub fn cmp(self: Result, result: Result) bool {
+ switch (self) {
+ .int => |i| return i == result.int,
+ .string => |s| return std.mem.eql(u8, s, result.string),
+ }
+ }
+
+ pub fn deinit(self: Result, allocator: std.mem.Allocator) void {
+ switch (self) {
+ .string => |s| return allocator.free(s),
+ else => {},
+ }
+ }
+};
diff --git a/util/mem.zig b/util/mem.zig
deleted file mode 100644
index 728db44..0000000
--- a/util/mem.zig
+++ /dev/null
@@ -1,19 +0,0 @@
-const std = @import("std");
-
-const math = std.math;
-const testing_allocator = std.testing.allocator;
-
-/// Returns the position of the smallest number in a slice.
-pub fn min_idx(comptime T: type, slice: []const T) usize {
- var best = slice[0];
- var idx: usize = 0;
-
- for (slice[1..]) |item, i| {
- const possible_best = math.min(best, item);
- if (best > possible_best) {
- best = possible_best;
- idx = i + 1;
- }
- }
- return idx;
-}