You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
119 lines
3.4 KiB
Zig
119 lines
3.4 KiB
Zig
12 months ago
|
const std = @import("std");
|
||
|
|
||
|
pub fn main() !void {
|
||
|
const file = try std.fs.cwd().openFile("./data.txt", .{});
|
||
|
defer file.close();
|
||
|
|
||
|
var buffer: [30000]u8 = undefined;
|
||
|
_ = try file.readAll(&buffer);
|
||
|
|
||
|
var it = std.mem.split(u8, &buffer, "\n");
|
||
|
|
||
|
var total1: u64 = 0;
|
||
|
var total2: u64 = 0;
|
||
|
|
||
|
while (it.next()) |line| {
|
||
|
if (!std.ascii.isAlphanumeric(line[0])) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
var game: u64 = 0;
|
||
|
var busted: bool = false;
|
||
|
|
||
|
var min_red: u64 = 1;
|
||
|
var min_green: u64 = 1;
|
||
|
var min_blue: u64 = 1;
|
||
|
|
||
|
// Split the row on colons
|
||
|
var parts = std.mem.split(u8, line, ": ");
|
||
|
|
||
|
while (parts.next()) |part| {
|
||
|
// if it contais "Game", parse out the game ID
|
||
|
if (std.mem.eql(u8, part[0..4], "Game")) {
|
||
|
game = try std.fmt.parseInt(u8, part[5..], 10);
|
||
|
} else {
|
||
|
// Split the turns up by semicolons
|
||
|
var turns = std.mem.split(u8, part, "; ");
|
||
|
|
||
|
var red: u64 = 0;
|
||
|
var green: u64 = 0;
|
||
|
var blue: u64 = 0;
|
||
|
|
||
|
while (turns.next()) |turn| {
|
||
|
// Split the colors up by commas
|
||
|
var colors = std.mem.split(u8, turn, ", ");
|
||
|
|
||
|
while (colors.next()) |color| {
|
||
|
const idx = findIdx(color, ' ').?;
|
||
|
const num = try std.fmt.parseInt(u8, color[0..idx], 10);
|
||
|
|
||
|
if (endsWith(color, "red")) {
|
||
|
if (num > min_red) {
|
||
|
min_red = num;
|
||
|
}
|
||
|
if (num > 12) {
|
||
|
busted = true;
|
||
|
}
|
||
|
red += num;
|
||
|
} else if (endsWith(color, "green")) {
|
||
|
if (num > min_green) {
|
||
|
min_green = num;
|
||
|
}
|
||
|
if (num > 13) {
|
||
|
busted = true;
|
||
|
}
|
||
|
green += num;
|
||
|
} else if (endsWith(color, "blue")) {
|
||
|
if (num > min_blue) {
|
||
|
min_blue = num;
|
||
|
}
|
||
|
if (num > 14) {
|
||
|
busted = true;
|
||
|
}
|
||
|
blue += num;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!busted) {
|
||
|
total1 += game;
|
||
|
}
|
||
|
|
||
|
const power: u64 = min_red * min_green * min_blue;
|
||
|
total2 += power;
|
||
|
}
|
||
|
|
||
|
std.debug.print("part 1 total: {any}\n", .{total1});
|
||
|
std.debug.print("part 2 total: {any}\n", .{total2});
|
||
|
}
|
||
|
|
||
|
// does the outer string end with the inner string
|
||
|
fn endsWith(outer: []const u8, inner: []const u8) bool {
|
||
|
if (outer.len < inner.len) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
const offset = outer.len - inner.len;
|
||
|
|
||
|
for (inner, 0..) |c, idx| {
|
||
|
if (c != outer[idx + offset]) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// find the index of char in string
|
||
|
fn findIdx(string: []const u8, char: u8) ?usize {
|
||
|
for (string, 0..) |c, idx| {
|
||
|
if (c == char) {
|
||
|
return idx;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|