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")); } test "get value" { // Oopsie! Thankfully the author of the puzzle didn't see this coming 🤪 try std.testing.expectEqual(@as(?u8, 21), get_value("twone")); try std.testing.expectEqual(@as(?u8, 58), get_value("fiveight")); }