const std = @import("std"); const builtin = @import("builtin"); // NOTE: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 const segment_counts = [_]u32{ 6, 2, 5, 5, 4, 5, 6, 3, 7, 6 }; pub const Display = struct { definitions: []const []const u8, digits: []const []const u8, }; fn readInputFile(allocator: std.mem.Allocator, filename: []const u8) ![]Display { var result = std.ArrayList(Display).init(allocator); const file = try std.fs.cwd().openFile(filename, .{ .read = true }); defer file.close(); const reader = file.reader(); while (true) { var line: []u8 = undefined; if (builtin.os.tag == .windows) { // NOTE: Read another byte on windows due to two-byte eol. line = reader.readUntilDelimiterAlloc(allocator, '\r', 512) catch break; _ = try reader.readByte(); } else { line = reader.readUntilDelimiterAlloc(allocator, '\n', 512) catch break; } defer allocator.free(line); var display: Display = undefined; var parts = std.mem.split(u8, line, " | "); var definitions = std.ArrayList([]u8).init(allocator); var it = std.mem.split(u8, parts.next().?, " "); while (it.next()) |slice| { var def = try allocator.dupe(u8, slice); try definitions.append(def); } display.definitions = definitions.items; var digits = std.ArrayList([]u8).init(allocator); it = std.mem.split(u8, parts.next().?, " "); while (it.next()) |slice| { var dig = try allocator.dupe(u8, slice); try digits.append(dig); } display.digits = digits.items; try result.append(display); } return result.items; } pub fn task1(input: []const Display) u32 { var result: u32 = 0; for (input) |display| { for (display.digits) |digit| { if (digit.len == segment_counts[1] or digit.len == segment_counts[4] or digit.len == segment_counts[7] or digit.len == segment_counts[8]) { result += 1; } } } return result; } fn findMatch(segment_count: u32, base_on: usize, match_count: u32, partial: []usize, display: *const Display) usize { skip: for (display.definitions) |digit, index| { for (partial) |p| { if (p == index) { continue :skip; } } if (digit.len == segment_count) { var found: u32 = 0; for (display.definitions[base_on]) |def| { for (digit) |dig| { if (def == dig) { found += 1; } } } if (found == match_count) { return index; } } } unreachable; } pub fn task2(allocator: std.mem.Allocator, input: []const Display) ![]u32 { var result = std.ArrayList(u32).init(allocator); for (input) |display| { var solution = [_]usize{99} ** 10; for (display.definitions) |digit, index| { if (digit.len == segment_counts[1]) { solution[1] = index; std.log.debug("1 {s}", .{digit}); } else if (digit.len == segment_counts[4]) { solution[4] = index; std.log.debug("4 {s}", .{digit}); } else if (digit.len == segment_counts[7]) { solution[7] = index; std.log.debug("7 {s}", .{digit}); } else if (digit.len == segment_counts[8]) { solution[8] = index; std.log.debug("8 {s}", .{digit}); } } solution[6] = findMatch(segment_counts[6], solution[1], 1, &solution, &display); std.log.debug("6 {s}", .{display.definitions[solution[6]]}); solution[0] = findMatch(segment_counts[0], solution[4], 3, &solution, &display); std.log.debug("0 {s}", .{display.definitions[solution[0]]}); solution[9] = findMatch(segment_counts[9], solution[0], 5, &solution, &display); std.log.debug("9 {s}", .{display.definitions[solution[9]]}); solution[5] = findMatch(segment_counts[5], solution[6], 5, &solution, &display); std.log.debug("5 {s}", .{display.definitions[solution[5]]}); solution[3] = findMatch(segment_counts[3], solution[9], 5, &solution, &display); std.log.debug("3 {s}", .{display.definitions[solution[3]]}); solution[2] = findMatch(segment_counts[2], solution[8], 5, &solution, &display); std.log.debug("2 {s}", .{display.definitions[solution[2]]}); std.log.debug("solution {any}", .{solution}); var solve_result: u32 = 0; solve: for (display.digits) |dig| { std.log.debug("looking for {s}", .{dig}); for (display.definitions) |def, def_index| { if (dig.len == def.len) { std.log.debug("potential {s}#{}", .{ def, def.len }); var count: u32 = 0; for (dig) |dig_char| { for (def) |def_char| { if (dig_char == def_char) { count += 1; } } } if (count == def.len) { std.log.debug("found! {s}#{}", .{ def, def.len }); for (solution) |sol, sol_index| { if (sol == def_index) { std.log.debug("={}", .{sol_index}); solve_result = (solve_result * 10) + @intCast(u32, sol_index); } } continue :solve; } } } } try result.append(solve_result); } return result.items; } pub fn main() !void { var buffer: [2000000]u8 = undefined; var fixed_buffer = std.heap.FixedBufferAllocator.init(&buffer); const allocator = fixed_buffer.allocator(); const input = try readInputFile(allocator, "input.txt"); const task_1_result = task1(input); std.log.info("Task 1 result: {}", .{task_1_result}); const task_2_result = try task2(allocator, input); var count: u32 = 0; for (task_2_result) |r| { count += r; } std.log.info("Task 2 result: {}", .{count}); }