Day 2: Red-Nosed Reports
Megathread guidelines
- Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
- You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://blocks.programming.dev if you prefer sending it through a URL
FAQ
- What is this?: Here is a post with a large amount of details: https://programming.dev/post/22323136
- Where do I participate?: https://adventofcode.com/
- Is there a leaderboard for the community?: We have a programming.dev leaderboard with the info on how to join in this post: https://programming.dev/post/6631465
You are viewing a single thread.
View all comments 1 point
#Zig
const std = @import("std");
const List = std.ArrayList;
const splitScalar = std.mem.splitScalar;
const parseInt = std.fmt.parseInt;
const print = std.debug.print;
const concat = std.mem.concat;
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const alloc = gpa.allocator();
const Answer = struct {
safe: u32,
tolerated: u32,
};
pub fn isSafe(levels: []i32) bool {
if (levels.len == 0) {
return false;
}
// slide window in pairs, advancing by one
var it = std.mem.window(i32, levels, 2, 1);
const first = it.first();
const decreasing = first[0] - first[1] > 0;
it.reset(); // rewind the iterator
while (it.next()) |slice| {
const lhs: i32 = slice[0];
const rhs: i32 = slice[1];
if (decreasing) {
if (lhs <= rhs) return false;
if (lhs - rhs < 1 or lhs - rhs > 3) return false;
} else {
if (rhs <= lhs) return false;
if (rhs - lhs < 1 or rhs - lhs > 3) return false;
}
}
return true;
}
pub fn solve(input: []const u8) !Answer {
var rows = splitScalar(u8, input, '\n');
// PART 1
// determine how many reports are safe
var safe_reports: u32 = 0;
var tolerated_reports: u32 = 0;
var unsafe_reports = List([]i32).init(alloc);
defer unsafe_reports.deinit();
while (rows.next()) |row| {
var levels = splitScalar(u8, row, ' ');
var report = List(i32).init(alloc);
defer report.deinit();
while (levels.next()) |level| {
const value = parseInt(i32, level, 10) catch continue;
report.append(value) catch continue;
}
if (isSafe(report.items)) {
safe_reports += 1;
} else {
try unsafe_reports.append(try alloc.dupe(i32, report.items));
}
}
// PART 2
// determine how many unsafe reports can be tolerated
for (unsafe_reports.items) |report| {
var index: usize = 0;
while (index < report.len) : (index += 1) {
// mutate report by removing one level
const mutated_report = concat(
alloc,
i32,
&[_][]const i32{ report[0..index], report[index + 1 ..] },
) catch report;
defer alloc.free(mutated_report);
if (isSafe(mutated_report)) {
tolerated_reports += 1;
break;
}
}
}
return Answer{ .safe = safe_reports, .tolerated = safe_reports + tolerated_reports };
}
pub fn main() !void {
const answer = try solve(@embedFile("input.txt"));
print("Part 1: {d}\n", .{answer.safe});
print("Part 2: {d}\n", .{answer.tolerated});
}
test "test input" {
const answer = try solve(@embedFile("test.txt"));
try std.testing.expectEqual(2, answer.safe);
try std.testing.expectEqual(4, answer.tolerated);