From 26bdbeab996046bc528f64f8e63c7d13972fe854 Mon Sep 17 00:00:00 2001 From: Jeremy Kaplan Date: Sun, 1 Dec 2024 22:50:10 -0800 Subject: [PATCH] 2024 Day 2 Part 2 --- 2024/src/day02.py | 59 +++++++++++++++++++++++++++++++++ 2024/src/day02.zig | 82 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 120 insertions(+), 21 deletions(-) create mode 100644 2024/src/day02.py diff --git a/2024/src/day02.py b/2024/src/day02.py new file mode 100644 index 0000000..8b25036 --- /dev/null +++ b/2024/src/day02.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 + +import os + + +def relpath(path: str) -> str: + return os.path.join(os.path.dirname(__file__), path) + + +reports = [] +with open(relpath("../input/day02.txt")) as f: + for line in f.readlines(): + report = [int(i) for i in line.strip().split()] + reports.append(report) + +Report = list[int] + + +def sign(x: int) -> int: + if x > 0: + return +1 + if x < 0: + return -1 + return 0 + + +def is_safe(report: Report) -> bool: + return first_problem(report) is None + + +def first_problem(report: Report) -> int | None: + direction = sign(report[1] - report[0]) + for i, (prev, next) in enumerate(zip(report[:-1], report[1:])): + diff = next - prev + if direction != sign(diff) or abs(diff) < 1 or abs(diff) > 3: + return i + + +def is_safe_tolerant(report: Report) -> bool: + if is_safe(report): + return True + + for i in range(len(report)): + if is_safe(report[:i] + report[i+1:]): + return True + + return False + + +n = 0 +m = 0 +for report in reports: + if is_safe(report): + n += 1 + if is_safe_tolerant(report): + m += 1 + +print(n) +print(m) diff --git a/2024/src/day02.zig b/2024/src/day02.zig index 42fb34c..dfc481d 100644 --- a/2024/src/day02.zig +++ b/2024/src/day02.zig @@ -6,6 +6,7 @@ pub fn main() !void { defer _ = gpa.deinit(); const allocator = gpa.allocator(); + // const file = try std.fs.cwd().openFile("input/test.txt", .{}); const file = try std.fs.cwd().openFile("input/day02.txt", .{}); defer file.close(); @@ -25,6 +26,7 @@ pub fn main() !void { } try stdout.print("{d}\n", .{part1(reports)}); + try stdout.print("{d}\n", .{try part2(allocator, reports)}); try bw.flush(); for (reports.items) |r| { @@ -33,14 +35,14 @@ pub fn main() !void { } const Report = struct { - levels: std.ArrayList(u32), + levels: std.ArrayList(i32), fn parse(allocator: std.mem.Allocator, line: std.ArrayList(u8)) !Report { - var levels = std.ArrayList(u32).init(allocator); + var levels = std.ArrayList(i32).init(allocator); var it = std.mem.tokenizeScalar(u8, line.items, ' '); while (it.next()) |level| { - const i = try std.fmt.parseInt(u32, level, 10); + const i = try std.fmt.parseInt(i32, level, 10); try levels.append(i); } @@ -52,41 +54,69 @@ const Report = struct { } fn is_safe(self: Report) bool { + return self.first_problem() == null; + } + + fn first_problem(self: Report) ?usize { var prev = self.levels.items[0]; - const sign = self.levels.items[1] > self.levels.items[0]; + const sign = Sign.of(self.levels.items[1] - self.levels.items[0]); var i: usize = 1; while (i < self.levels.items.len) { const next = self.levels.items[i]; - const diff = abs_diff(next, prev); + const diff = next - prev; - if ((next > prev) != sign) { - return false; - } - - if (diff < 1 or diff > 3) { - return false; + if (Sign.of(diff) != sign or @abs(diff) < 1 or @abs(diff) > 3) { + return i; } prev = next; i += 1; } - return true; + return null; + } + + fn is_safe_tolerant(self: Report, allocator: std.mem.Allocator) !bool { + if (self.is_safe()) { + return true; + } + + for (0..self.levels.items.len) |i| { + var fixed = std.ArrayList(i32).init(allocator); + defer fixed.deinit(); + + try fixed.appendSlice(self.levels.items[0..i]); + try fixed.appendSlice(self.levels.items[i + 1 ..]); + + if (is_safe(Report{ .levels = fixed })) { + return true; + } + } + + return false; } }; -fn abs_diff(a: u32, b: u32) u32 { - if (a > b) { - return a - b; - } else { - return b - a; - } -} +const Sign = enum { + pos, + neg, + zero, -fn part1(reports: std.ArrayList(Report)) u32 { - var n: u32 = 0; + fn of(i: i32) Sign { + if (i > 0) { + return .pos; + } + if (i < 0) { + return .neg; + } + return .zero; + } +}; + +fn part1(reports: std.ArrayList(Report)) i32 { + var n: i32 = 0; for (reports.items) |report| { if (report.is_safe()) { n += 1; @@ -95,3 +125,13 @@ fn part1(reports: std.ArrayList(Report)) u32 { return n; } + +fn part2(allocator: std.mem.Allocator, reports: std.ArrayList(Report)) !i32 { + var n: i32 = 0; + for (reports.items) |report| { + if (report.is_safe() or try report.is_safe_tolerant(allocator)) { + n += 1; + } + } + return n; +}