From 62f3a36e374790fdab0649d87cf03d44ea86dc80 Mon Sep 17 00:00:00 2001 From: Inga Date: Sat, 2 Dec 2023 01:04:29 +0000 Subject: [PATCH] day 1, part 2 --- day01-hard/build.zig | 70 ++++++++++++ day01-hard/sample.in | 4 + day01-hard/sample2.in | 7 ++ day01-hard/src/main.zig | 236 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 317 insertions(+) create mode 100644 day01-hard/build.zig create mode 100644 day01-hard/sample.in create mode 100644 day01-hard/sample2.in create mode 100644 day01-hard/src/main.zig diff --git a/day01-hard/build.zig b/day01-hard/build.zig new file mode 100644 index 0000000..3f6dceb --- /dev/null +++ b/day01-hard/build.zig @@ -0,0 +1,70 @@ +const std = @import("std"); + +// Although this function looks imperative, note that its job is to +// declaratively construct a build graph that will be executed by an external +// runner. +pub fn build(b: *std.Build) 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(.{}); + + // Standard optimization options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not + // set a preferred release mode, allowing the user to decide how to optimize. + const optimize = b.standardOptimizeOption(.{}); + + const exe = b.addExecutable(.{ + .name = "day01-hard", + // In this case the main source file is merely a path, however, in more + // complicated build scripts, this could be a generated file. + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); + + // This declares intent for the executable to be installed into the + // standard location when the user invokes the "install" step (the default + // step when running `zig build`). + b.installArtifact(exe); + + // This *creates* a Run step in the build graph, to be executed when another + // step is evaluated that depends on it. The next line below will establish + // such a dependency. + const run_cmd = b.addRunArtifact(exe); + + // By making the run step depend on the install step, it will be run from the + // installation directory rather than directly from within the cache directory. + // This is not necessary, however, if the application depends on other installed + // files, this ensures they will be present and in the expected location. + run_cmd.step.dependOn(b.getInstallStep()); + + // This allows the user to pass arguments to the application in the build + // command itself, like this: `zig build run -- arg1 arg2 etc` + if (b.args) |args| { + run_cmd.addArgs(args); + } + + // This creates a build step. It will be visible in the `zig build --help` menu, + // and can be selected like this: `zig build run` + // This will evaluate the `run` step rather than the default, which is "install". + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); + + // Creates a step for unit testing. This only builds the test executable + // but does not run it. + const unit_tests = b.addTest(.{ + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); + + const run_unit_tests = b.addRunArtifact(unit_tests); + + // Similar to creating the run step earlier, this exposes a `test` step to + // the `zig build --help` menu, providing a way for the user to request + // running the unit tests. + const test_step = b.step("test", "Run unit tests"); + test_step.dependOn(&run_unit_tests.step); +} diff --git a/day01-hard/sample.in b/day01-hard/sample.in new file mode 100644 index 0000000..1ba8437 --- /dev/null +++ b/day01-hard/sample.in @@ -0,0 +1,4 @@ +1abc2 +pqr3stu8vwx +a1b2c3d4e5f +treb7uchet \ No newline at end of file diff --git a/day01-hard/sample2.in b/day01-hard/sample2.in new file mode 100644 index 0000000..4316a6b --- /dev/null +++ b/day01-hard/sample2.in @@ -0,0 +1,7 @@ +two1nine +eightwothree +abcone2threexyz +xtwone3four +4nineeightseven2 +zoneight234 +7pqrstsixteen \ No newline at end of file diff --git a/day01-hard/src/main.zig b/day01-hard/src/main.zig new file mode 100644 index 0000000..f855805 --- /dev/null +++ b/day01-hard/src/main.zig @@ -0,0 +1,236 @@ +const std = @import("std"); + +// Cannot believe I'm doing this by hand, +// but both somewhat popular regex libraries for Zig +// have build scripts incompatible with latest Zig 0.11 (released on August 4th, 2023), +// and I'm not into trying to link this with regex.h + +fn get_digit_at_start(substr: []const u8) ?u8 { + return switch (substr[0]) { + '0'...'9' => substr[0] - '0', + 'o' => if (substr.len >= 3 and substr[1] == 'n' and substr[2] == 'e') 1 else null, + 't' => if (substr.len >= 3) + switch (substr[1]) { + 'w' => if (substr[2] == 'o') 2 else null, + 'h' => if (substr.len >= 5 and substr[2] == 'r' and substr[3] == 'e' and substr[4] == 'e') 3 else null, + else => null, + } + else + null, + 'f' => if (substr.len >= 4) + switch (substr[1]) { + 'o' => if (substr[2] == 'u' and substr[3] == 'r') 4 else null, + 'i' => if (substr[2] == 'v' and substr[3] == 'e') 5 else null, + else => null, + } + else + null, + 's' => if (substr.len >= 3) + switch (substr[1]) { + 'i' => if (substr[2] == 'x') 6 else null, + 'e' => if (substr.len >= 5 and substr[2] == 'v' and substr[3] == 'e' and substr[4] == 'n') 7 else null, + else => null, + } + else + null, + 'e' => if (substr.len >= 5 and substr[1] == 'i' and substr[2] == 'g' and substr[3] == 'h' and substr[4] == 't') 8 else null, + 'n' => if (substr.len >= 4 and substr[1] == 'i' and substr[2] == 'n' and substr[3] == 'e') 9 else null, + else => null, + }; +} + +fn get_digit_at_end(substr: []const u8) ?u8 { + const last = substr.len - 1; + return switch (substr[last]) { + '0'...'9' => substr[last] - '0', + 'e' => if (substr.len >= 3) + switch (substr[last - 1]) { + 'n' => switch (substr[last - 2]) { + 'o' => 1, + 'i' => if (substr.len >= 4 and substr[last - 3] == 'n') 9 else null, + else => null, + }, + 'e' => if (substr.len >= 5 and substr[last - 2] == 'r' and substr[last - 3] == 'h' and substr[last - 4] == 't') 3 else null, + 'v' => if (substr.len >= 4 and substr[last - 2] == 'i' and substr[last - 3] == 'f') 5 else null, + else => null, + } + else + null, + 'o' => if (substr.len >= 3 and substr[last - 1] == 'w' and substr[last - 2] == 't') 2 else null, + 'r' => if (substr.len >= 4 and substr[last - 1] == 'u' and substr[last - 2] == 'o' and substr[last - 3] == 'f') 4 else null, + 'x' => if (substr.len >= 3 and substr[last - 1] == 'i' and substr[last - 2] == 's') 6 else null, + 'n' => if (substr.len >= 5 and substr[last - 1] == 'e' and substr[last - 2] == 'v' and substr[last - 3] == 'e' and substr[last - 4] == 's') 7 else null, + 't' => if (substr.len >= 5 and substr[last - 1] == 'h' and substr[last - 2] == 'g' and substr[last - 3] == 'i' and substr[last - 4] == 'e') 8 else null, + else => null, + }; +} + +fn get_first_digit(str: []const u8) u8 { + for (0..str.len) |i| { + const digit = get_digit_at_start(str[i..]); + if (digit != null) { + return digit.?; + } + } + + return 0; +} + +fn get_last_digit(str: []const u8) u8 { + for (0..str.len) |i| { + const digit = get_digit_at_end(str[0 .. str.len - i]); + if (digit != null) { + return digit.?; + } + } + + return 0; +} + +fn get_value(str: []const u8) u8 { + const first_digit = get_first_digit(str); + const last_digit = get_last_digit(str); + return first_digit * 10 + last_digit; +} + +pub fn main() !void { + const stdout = std.io.getStdOut().writer(); + + const raw_in = std.io.getStdIn(); + var buffered_reader = std.io.bufferedReader(raw_in.reader()); + var reader = buffered_reader.reader(); + + var result: u32 = 0; + var line_buffer: [1000]u8 = undefined; + while (try reader.readUntilDelimiterOrEof(&line_buffer, '\n')) |line| { + result += get_value(line); + } + try stdout.print( + "{d}\n", + .{result}, + ); +} + +test "get digit at start" { + try std.testing.expectEqual(@as(?u8, 1), get_digit_at_start("one")); + try std.testing.expectEqual(@as(?u8, 1), get_digit_at_start("one!")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("on")); + + try std.testing.expectEqual(@as(?u8, 2), get_digit_at_start("two")); + try std.testing.expectEqual(@as(?u8, 2), get_digit_at_start("two!")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("tw")); + + try std.testing.expectEqual(@as(?u8, 3), get_digit_at_start("three")); + try std.testing.expectEqual(@as(?u8, 3), get_digit_at_start("three!")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("thre")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("thre!")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("thr!e")); + + try std.testing.expectEqual(@as(?u8, 4), get_digit_at_start("four")); + try std.testing.expectEqual(@as(?u8, 4), get_digit_at_start("four!")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("fou")); + + try std.testing.expectEqual(@as(?u8, 5), get_digit_at_start("five")); + try std.testing.expectEqual(@as(?u8, 5), get_digit_at_start("five!")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("fiv")); + + try std.testing.expectEqual(@as(?u8, 6), get_digit_at_start("six")); + try std.testing.expectEqual(@as(?u8, 6), get_digit_at_start("six!")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("si")); + + try std.testing.expectEqual(@as(?u8, 7), get_digit_at_start("seven")); + try std.testing.expectEqual(@as(?u8, 7), get_digit_at_start("seven!")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("seve")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("s!ven")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("sev!n")); + + try std.testing.expectEqual(@as(?u8, 8), get_digit_at_start("eight")); + try std.testing.expectEqual(@as(?u8, 8), get_digit_at_start("eight!")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("eigh")); + + try std.testing.expectEqual(@as(?u8, 9), get_digit_at_start("nine")); + try std.testing.expectEqual(@as(?u8, 9), get_digit_at_start("nine!")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("nin")); + + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("!!!!!!!")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("t!!!!!!")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("f!!!!!!")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("s!!!!!!")); + + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("t")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("f")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_start("s")); +} + +test "get digit at end" { + try std.testing.expectEqual(@as(?u8, 1), get_digit_at_end("one")); + try std.testing.expectEqual(@as(?u8, 1), get_digit_at_end("!one")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_end("ne")); + + try std.testing.expectEqual(@as(?u8, 2), get_digit_at_end("two")); + try std.testing.expectEqual(@as(?u8, 2), get_digit_at_end("!two")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_end("wo")); + + try std.testing.expectEqual(@as(?u8, 3), get_digit_at_end("three")); + try std.testing.expectEqual(@as(?u8, 3), get_digit_at_end("!three")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_end("hree")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_end("thre!")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_end("thr!e")); + + try std.testing.expectEqual(@as(?u8, 4), get_digit_at_end("four")); + try std.testing.expectEqual(@as(?u8, 4), get_digit_at_end("!four")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_end("our")); + + try std.testing.expectEqual(@as(?u8, 5), get_digit_at_end("five")); + try std.testing.expectEqual(@as(?u8, 5), get_digit_at_end("!five")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_end("ive")); + + try std.testing.expectEqual(@as(?u8, 6), get_digit_at_end("six")); + try std.testing.expectEqual(@as(?u8, 6), get_digit_at_end("!six")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_end("ix")); + + try std.testing.expectEqual(@as(?u8, 7), get_digit_at_end("seven")); + try std.testing.expectEqual(@as(?u8, 7), get_digit_at_end("!seven")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_end("even")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_end("s!ven")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_end("sev!n")); + + try std.testing.expectEqual(@as(?u8, 8), get_digit_at_end("eight")); + try std.testing.expectEqual(@as(?u8, 8), get_digit_at_end("!eight")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_end("ight")); + + try std.testing.expectEqual(@as(?u8, 9), get_digit_at_end("nine")); + try std.testing.expectEqual(@as(?u8, 9), get_digit_at_end("!nine")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_end("ine")); + + try std.testing.expectEqual(@as(?u8, null), get_digit_at_end("!!!!!!!")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_end("!!!!!!e")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_end("!!!!!ne")); + + try std.testing.expectEqual(@as(?u8, null), get_digit_at_end("e")); + try std.testing.expectEqual(@as(?u8, null), get_digit_at_end("ne")); +} + +test "get first digit" { + try std.testing.expectEqual(@as(?u8, 1), get_first_digit("1")); + try std.testing.expectEqual(@as(?u8, 1), get_first_digit("!1")); + try std.testing.expectEqual(@as(?u8, 1), get_first_digit("one")); + try std.testing.expectEqual(@as(?u8, 1), get_first_digit("onetwo")); + try std.testing.expectEqual(@as(?u8, 1), get_first_digit("oone")); + try std.testing.expectEqual(@as(?u8, 1), get_first_digit("onone")); + try std.testing.expectEqual(@as(?u8, 5), get_first_digit("fiveight")); + try std.testing.expectEqual(@as(?u8, 8), get_first_digit("seveight")); + try std.testing.expectEqual(@as(?u8, 0), get_first_digit("seveigh!")); +} + +test "get last digit" { + try std.testing.expectEqual(@as(?u8, 1), get_last_digit("1")); + try std.testing.expectEqual(@as(?u8, 1), get_last_digit("1!")); + try std.testing.expectEqual(@as(?u8, 1), get_last_digit("one")); + try std.testing.expectEqual(@as(?u8, 1), get_last_digit("twoone")); + try std.testing.expectEqual(@as(?u8, 1), get_last_digit("onee")); + try std.testing.expectEqual(@as(?u8, 1), get_last_digit("onene")); + try std.testing.expectEqual(@as(?u8, 8), get_last_digit("fiveight")); + try std.testing.expectEqual(@as(?u8, 7), get_last_digit("sevene")); + try std.testing.expectEqual(@as(?u8, 0), get_last_digit("!evene")); +}