128 lines
4.0 KiB
Zig
128 lines
4.0 KiB
Zig
const std = @import("std");
|
|
const print = std.debug.print;
|
|
const util = @import("util.zig");
|
|
|
|
pub fn main() !void {
|
|
const output = try part_one();
|
|
print("{}\n", .{output});
|
|
}
|
|
|
|
pub fn part_one() !u32 {
|
|
const isTestCase = true;
|
|
// Reading the input...
|
|
// Making use of example here: https://cookbook.ziglang.cc/01-01-read-file-line-by-line.html
|
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
|
defer _ = gpa.deinit();
|
|
const allocator = gpa.allocator();
|
|
|
|
const path = try util.getInputFile("02", isTestCase);
|
|
const file = try std.fs.cwd().openFile(path, .{});
|
|
defer file.close();
|
|
|
|
// Wrap the file reader in a buffered reader.
|
|
// Since it's usually faster to read a bunch of bytes at once.
|
|
var buf_reader = std.io.bufferedReader(file.reader());
|
|
const reader = buf_reader.reader();
|
|
|
|
var line = std.ArrayList(u8).init(allocator);
|
|
defer line.deinit();
|
|
|
|
const writer = line.writer();
|
|
var line_no: usize = 0;
|
|
|
|
var safe_count: u32 = 0;
|
|
|
|
while (reader.streamUntilDelimiter(writer, '\n', null)) {
|
|
defer line.clearRetainingCapacity();
|
|
line_no += 1;
|
|
|
|
const report = try parseLineToNumbers(line.items, allocator);
|
|
if (try is_safe(report)) {
|
|
safe_count += 1;
|
|
}
|
|
report.deinit();
|
|
|
|
|
|
} else |err| switch (err) {
|
|
error.EndOfStream => { // end of file
|
|
if (line.items.len > 0) {
|
|
line_no += 1;
|
|
print("{d}--{s}\n", .{ line_no, line.items });
|
|
}
|
|
},
|
|
else => return err, // Propagate error
|
|
}
|
|
return safe_count;
|
|
}
|
|
|
|
pub const IllegalDataError = error{
|
|
TooSmall
|
|
};
|
|
|
|
// The logic given is:
|
|
// - "Levels are either all increasing or all decreasing"
|
|
// - "Adjacent levels differ by at least one and at most three"
|
|
//
|
|
// which can be rephrased (so as to avoid having to pass through the state of "is this an all-increasing or
|
|
// all-decreasing report?") as:
|
|
// - "The first pair of levels is within 1-3"
|
|
// - "For all triples in the report, both pairs have the same direction, and the final pair is within 1-3"
|
|
fn is_safe(reportAsArray: std.ArrayList(u32)) !bool {
|
|
const report = reportAsArray.items;
|
|
// Legality-check that the report contains at least two levels
|
|
if (report.len < 2) {
|
|
return IllegalDataError.TooSmall;
|
|
}
|
|
// First, check that the first pair of levels is within 1-3
|
|
const diff_of_first_pair = util.diffOfNumbers(report[0], report[1]);
|
|
if ((diff_of_first_pair < 1) or (diff_of_first_pair > 3)) {
|
|
return false;
|
|
}
|
|
|
|
// Early return if the report contains only 2 levels
|
|
if (report.len < 3) {
|
|
return true;
|
|
}
|
|
|
|
// We know that the report contains at least 3 levels, so we can start a sliding comparison.
|
|
var i: u32 = 0;
|
|
while (i < (report.len - 2)) {
|
|
if (
|
|
(report[i] > report[i+1]) and (report[i+1] < report[i+2])
|
|
or
|
|
(report[i] < report[i+1] and (report[i+1] > report[i+2]))
|
|
) {
|
|
return false;
|
|
}
|
|
const diff_of_second_pair = util.diffOfNumbers(report[i+1], report[i+2]);
|
|
if ((diff_of_second_pair < 1) or (diff_of_second_pair > 3)) {
|
|
return false;
|
|
}
|
|
i+=1;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// TODO - probably extract this to utils?
|
|
// (Though note that this differs from the example in 01.zig)
|
|
fn parseLineToNumbers(line: []u8, allocator: std.mem.Allocator) !std.ArrayList(u32) {
|
|
var numbers = std.ArrayList(u32).init(allocator);
|
|
// Feels _weird_ to be explicitly `deinit`-ing memory! This language is so fucked up.
|
|
|
|
// https://stackoverflow.com/a/79199470/1040915
|
|
var it = std.mem.splitScalar(u8, line, ' ');
|
|
while (it.next()) |chunk| {
|
|
print("Trying to parse {any}\n", .{chunk});
|
|
const parsed = try std.fmt.parseInt(u32, chunk, 10);
|
|
print("Parsed it to {}\n", .{parsed});
|
|
try numbers.append(parsed);
|
|
}
|
|
return numbers;
|
|
}
|
|
|
|
const expect = std.testing.expect;
|
|
|
|
test "part one" {
|
|
try expect(try part_one() == 2);
|
|
} |