const std = @import("std"); const Char = enum(u4) { Zero = 0, One = 1, Two = 2, Three = 3, Four = 4, Five = 5, Six = 6, Seven = 7, Eight = 8, Nine = 9, Dot = 12, Symbol = 13, }; const CharInfo = struct { adjacents: [8]Char, this: Char, fn isAdjacentToSymbol(self: *const CharInfo) bool { for (0..8) |i| { if (self.adjacents[i] == .Symbol) { return true; } } return false; } }; const State = struct { number: u32 = 0, is_adjacent_to_symbol: bool = false, fn addDigit(self: *State, char_info: CharInfo) void { self.number = self.number * 10 + @intFromEnum(char_info.this); self.is_adjacent_to_symbol = self.is_adjacent_to_symbol or char_info.isAdjacentToSymbol(); } }; fn solve(engine: [][]const CharInfo) u32 { var result: u32 = 0; var current_state = State{}; for (engine) |line| { //std.debug.print("handling new line\n", .{}); for (line) |char_info| { //std.debug.print("handling: {s}({s})\n", .{ [_]u8{char_info.this}, char_info.adjacents }); switch (char_info.this) { .Zero, .One, .Two, .Three, .Four, .Five, .Six, .Seven, .Eight, .Nine => { current_state.addDigit(char_info); }, .Dot, .Symbol => { if (current_state.is_adjacent_to_symbol) { //std.debug.print("adding: {d}\n", .{current_state.number}); result += current_state.number; } current_state = State{}; }, } } if (current_state.is_adjacent_to_symbol) { //std.debug.print("end of line; adding: {d}\n", .{current_state.number}); result += current_state.number; } current_state = State{}; } return result; } fn charLinesToCharInfoLines(allocator: std.mem.Allocator, char_lines: [][]const Char) ![][]const CharInfo { var char_info_lines = try allocator.alloc([]CharInfo, char_lines.len); for (0..char_lines.len) |i| { const char_line = char_lines[i]; var char_info_line = try allocator.alloc(CharInfo, char_line.len); for (0..char_line.len) |j| { char_info_line[j] = CharInfo{ .this = char_line[j], .adjacents = .{ if (i > 0 and j > 0) char_lines[i - 1][j - 1] else .Dot, if (i > 0) char_lines[i - 1][j] else .Dot, if (i > 0 and j + 1 < char_line.len) char_lines[i - 1][j + 1] else .Dot, if (j > 0) char_line[j - 1] else .Dot, if (j + 1 < char_line.len) char_line[j + 1] else .Dot, if (i + 1 < char_lines.len and j > 0) char_lines[i + 1][j - 1] else .Dot, if (i + 1 < char_lines.len) char_lines[i + 1][j] else .Dot, if (i + 1 < char_lines.len and j + 1 < char_line.len) char_lines[i + 1][j + 1] else .Dot, } }; } char_info_lines[i] = char_info_line; } return char_info_lines; } fn readInput(allocator: std.mem.Allocator, reader: anytype) ![][]const Char { var lines = std.ArrayList([]Char).init(allocator); var line_buffer: [1000]u8 = undefined; while (try reader.readUntilDelimiterOrEof(&line_buffer, '\n')) |line_ref| { var line = try allocator.alloc(Char, line_ref.len); for (line_ref, line) |raw_char, *char| { char.* = switch (raw_char) { '0'...'9' => @enumFromInt(raw_char - '0'), '.' => .Dot, else => .Symbol, }; } try lines.append(line); } return lines.items; } 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 allocator_buffer: [1_000_000]u8 = undefined; var fba = std.heap.FixedBufferAllocator.init(&allocator_buffer); var allocator = fba.allocator(); var lines_arena = std.heap.ArenaAllocator.init(allocator); const lines_allocator = lines_arena.allocator(); const char_lines = try readInput(lines_allocator, reader); var info_lines_arena = std.heap.ArenaAllocator.init(allocator); const info_lines_allocator = info_lines_arena.allocator(); const info_lines = try charLinesToCharInfoLines(info_lines_allocator, char_lines); lines_arena.deinit(); const result = solve(info_lines); info_lines_arena.deinit(); try stdout.print("{d}\n", .{result}); }