const std = @import("std"); const builtin = @import("builtin"); const Point = struct { x: u32, y: u32, }; const Input = struct { points: []Point, folds: []Point, }; pub fn readInput(allocator: std.mem.Allocator, reader: anytype) !Input { var points = std.ArrayList(Point).init(allocator); var folds = std.ArrayList(Point).init(allocator); while (true) { var line: []u8 = undefined; if (builtin.os.tag == .windows and !builtin.is_test) { // NOTE: Read another byte on windows due to two-byte eol. // NOTE: Check if in testing since tests only add single-byte eol in multiline strings. line = reader.readUntilDelimiterAlloc(allocator, '\r', 512) catch break; _ = try reader.readByte(); } else { line = reader.readUntilDelimiterAlloc(allocator, '\n', 512) catch break; } defer allocator.free(line); if (line.len == 0) { break; } var it = std.mem.split(u8, line, ","); var x = try std.fmt.parseInt(u32, it.next().?, 10); var y = try std.fmt.parseInt(u32, it.next().?, 10); try points.append(Point{ .x = x, .y = y, }); } while (true) { var line: []u8 = undefined; if (builtin.os.tag == .windows and !builtin.is_test) { // NOTE: Read another byte on windows due to two-byte eol. // NOTE: Check if in testing since tests only add single-byte eol in multiline strings. 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 it = std.mem.split(u8, line, "="); var p1 = it.next().?; var dir = p1[p1.len - 1]; var value = try std.fmt.parseInt(u32, it.next().?, 10); var fold = Point{ .x = 0, .y = 0, }; if (dir == 'x') { fold.x = value; } else { fold.y = value; } try folds.append(fold); } return Input{ .points = points.items, .folds = folds.items, }; } fn drawPoints(points: []Point) void { var result: u32 = 0; var min = Point{ .x = 99999, .y = 99999, }; var max = Point{ .x = 0, .y = 0, }; for (points) |point| { if (point.x < min.x) { min.x = point.x; } if (point.y < min.y) { min.y = point.y; } if (point.x > max.x) { max.x = point.x; } if (point.y > max.y) { max.y = point.y; } } var line: [2048]u8 = undefined; std.log.info("\npoints", .{}); var y: u32 = min.y; while (y <= max.y) : (y += 1) { var x: u32 = min.x; while (x <= max.x) : (x += 1) { var found = false; for (points) |point| { if (point.x == x and point.y == y) { found = true; result += 1; break; } } line[x] = if (found) '#' else '.'; } std.log.info("{s}", .{line[0..x]}); } } pub fn countPoints(points: []Point) u32 { var result: u32 = 0; var min = Point{ .x = 99999, .y = 99999, }; var max = Point{ .x = 0, .y = 0, }; for (points) |point| { if (point.x < min.x) { min.x = point.x; } if (point.y < min.y) { min.y = point.y; } if (point.x > max.x) { max.x = point.x; } if (point.y > max.y) { max.y = point.y; } } var y: u32 = min.y; while (y <= max.y) : (y += 1) { var x: u32 = min.x; while (x <= max.x) : (x += 1) { for (points) |point| { if (point.x == x and point.y == y) { result += 1; break; } } } } return result; } pub fn foldPoints(fold: Point, points: []Point) void { for (points) |point, i| { if (fold.x > fold.y) { if (point.x > fold.x) { points[i].x = fold.x - (point.x - fold.x); } } else { if (point.y > fold.y) { points[i].y = fold.y - (point.y - fold.y); } } } } pub fn task1(allocator: std.mem.Allocator, input: Input) !u32 { var result: u32 = 0; var points = try allocator.dupe(Point, input.points); defer allocator.free(points); var folds = try allocator.dupe(Point, input.folds); defer allocator.free(folds); foldPoints(folds[0], points); // drawPoints(points); result = countPoints(points); return result; } pub fn task2(allocator: std.mem.Allocator, input: Input) !u32 { var result: u32 = 0; var points = try allocator.dupe(Point, input.points); defer allocator.free(points); var folds = try allocator.dupe(Point, input.folds); defer allocator.free(folds); for (folds) |fold| { foldPoints(fold, points); } drawPoints(points); return result; } pub fn main() !void { var buffer: [2000000]u8 = undefined; var fixed_buffer = std.heap.FixedBufferAllocator.init(&buffer); const allocator = fixed_buffer.allocator(); const file = try std.fs.cwd().openFile("input.txt", .{ .read = true }); defer file.close(); const input = try readInput(allocator, file.reader()); const task_1_result = try task1(allocator, input); std.log.info("Task 1 result: {}", .{task_1_result}); const task_2_result = try task2(allocator, input); std.log.info("Task 2 result: {}", .{task_2_result}); }