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.
112 lines
3.7 KiB
Zig
112 lines
3.7 KiB
Zig
11 months ago
|
const std = @import("std");
|
||
|
const lib = @import("lib.zig");
|
||
|
|
||
|
const Number = struct { row: usize, col: usize, length: usize, value: u32 };
|
||
|
|
||
|
pub fn main() !void {
|
||
|
const content = @embedFile("data.txt");
|
||
|
const grid = try lib.splitArrayIntoArrayList(content, "\n");
|
||
|
defer grid.deinit();
|
||
|
|
||
|
const numbers = try parseNumbers(grid);
|
||
|
|
||
|
var total1: u128 = 0;
|
||
|
|
||
|
for (numbers.items) |n| {
|
||
|
if (numberTouchesSymbol(n, grid)) {
|
||
|
total1 += n.value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
std.debug.print("total1 {d}\n", .{total1});
|
||
|
|
||
|
var total2: u128 = 0;
|
||
|
for (grid.items, 0..) |line, row| {
|
||
|
for (line, 0..) |val, col| {
|
||
|
if (val == '*') {
|
||
|
total2 += try findGearRatio(row, col, numbers);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
std.debug.print("total2 {d}\n", .{total2});
|
||
|
}
|
||
|
|
||
|
fn findGearRatio(row: usize, col: usize, numbers: std.ArrayList(Number)) !u32 {
|
||
|
const touching = try findNumbersTouchingCell(row, col, numbers);
|
||
|
if (touching.items.len != 2) {
|
||
|
return 0;
|
||
|
}
|
||
|
return touching.items[0].value * touching.items[1].value;
|
||
|
}
|
||
|
|
||
|
fn findNumbersTouchingCell(row: usize, col: usize, numbers: std.ArrayList(Number)) !std.ArrayList(Number) {
|
||
|
const allocator = std.heap.page_allocator;
|
||
|
var touching = std.ArrayList(Number).init(allocator);
|
||
|
|
||
|
for (numbers.items) |n| {
|
||
|
// itreate over each digit in the number
|
||
|
for (0..n.length) |i| {
|
||
|
// TODO: upgrade to Zig .12 to get @abs
|
||
|
// if (@abs(n.row - row) < 1 and @abs(n.col + i - col) < 1) {
|
||
|
if ((n.row == row or n.row + 1 == row or n.row == row + 1) and (n.col + i == col or n.col + 1 + i == col or n.col + i == col + 1)) {
|
||
|
try touching.append(n);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return touching;
|
||
|
}
|
||
|
|
||
|
fn numberTouchesSymbol(n: Number, grid: std.ArrayList([]const u8)) bool {
|
||
|
const items = grid.items;
|
||
|
const width = items[0].len;
|
||
|
const height = items.len - 1; // TODO: fix extra crap when i read files..
|
||
|
|
||
|
// itreate over each digit in the number
|
||
|
for (0..n.length) |i| {
|
||
|
// over the 3 nearest rows
|
||
|
for (0..3) |r| {
|
||
|
// and the 3 nearest columns
|
||
|
for (0..3) |c| {
|
||
|
const outOfBounds = (r == 0 and n.row == 0) or (c == 0 and n.col + i == 0) or (r == 2 and n.row + 1 == height) or (c == 2 and n.col + i + 1 == width);
|
||
|
|
||
|
if (!outOfBounds) {
|
||
|
const row = n.row + r - 1;
|
||
|
const col = n.col + c + i - 1;
|
||
|
const val = items[row][col];
|
||
|
if (!std.ascii.isDigit(val) and val != '.') {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
fn parseNumbers(grid: std.ArrayList([]const u8)) !std.ArrayList(Number) {
|
||
|
const allocator = std.heap.page_allocator;
|
||
|
var numbers = std.ArrayList(Number).init(allocator);
|
||
|
|
||
|
for (grid.items, 0..) |line, row| {
|
||
|
var numList = std.ArrayList(u8).init(allocator);
|
||
|
defer numList.deinit();
|
||
|
|
||
|
for (line, 0..) |val, col| {
|
||
|
if (std.ascii.isDigit(val)) {
|
||
|
try numList.append(val);
|
||
|
}
|
||
|
|
||
|
// if we have a number started, and we've encountered a non-digit (or the end of the grid)
|
||
|
if (numList.items.len != 0 and (!std.ascii.isDigit(val) or col == line.len - 1)) {
|
||
|
const parsed = try std.fmt.parseInt(u32, numList.items, 10);
|
||
|
const length = numList.items.len;
|
||
|
try numbers.append(Number{ .row = row, .col = col - length, .length = length, .value = parsed });
|
||
|
numList.items.len = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return numbers;
|
||
|
}
|