diff options
author | Christian Segundo | 2022-12-05 17:00:08 +0100 |
---|---|---|
committer | Christian Segundo | 2022-12-05 22:16:11 +0100 |
commit | 061a5bae272f45db6dcde99746922735f9769d25 (patch) | |
tree | e4dd9b6d903930c5c1b76286b4a08beea6f59162 | |
parent | 8817203517907ef4248bde7474e6fb566515d6a7 (diff) | |
download | advent-of-zig-2022-061a5bae272f45db6dcde99746922735f9769d25.tar.gz |
add day 5
-rw-r--r-- | .github/workflows/benchmark.yml | 21 | ||||
-rw-r--r-- | Dockerfile | 15 | ||||
-rw-r--r-- | Makefile | 35 | ||||
-rw-r--r-- | README.md | 14 | ||||
-rwxr-xr-x | bin/aoc-2022 | bin | 0 -> 97651 bytes | |||
-rw-r--r-- | build.zig | 30 | ||||
l--------- | day-1/util | 1 | ||||
l--------- | day-2/util | 1 | ||||
l--------- | day-3/util | 1 | ||||
l--------- | day-4/util | 1 | ||||
-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.zig | 138 | ||||
-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_05 | 513 | ||||
-rw-r--r-- | main.zig | 115 | ||||
-rw-r--r-- | util/aoc.zig | 20 | ||||
-rw-r--r-- | util/mem.zig | 19 |
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 Binary files differnew file mode 100755 index 0000000..7d7dca3 --- /dev/null +++ b/bin/aoc-2022 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 @@ -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; -} |