solve day 3
This commit is contained in:
parent
59ac1720b9
commit
b863e1b2aa
146
src/day3.zig
Normal file
146
src/day3.zig
Normal file
@ -0,0 +1,146 @@
|
||||
const aoc = @import("./aoc.zig");
|
||||
const std = @import("std");
|
||||
const Point = @import("./point.zig").Point;
|
||||
|
||||
const PointU32 = Point(u32);
|
||||
const PointList = std.ArrayList(PointU32);
|
||||
|
||||
fn find_number_start(line: []const u8, from: u32) u32 {
|
||||
var i = from;
|
||||
while (i > 0) : (i -= 1) {
|
||||
if (!std.ascii.isDigit(line[i-1])) { break; }
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
fn find_number_end(line: []const u8, from: u32) u32 {
|
||||
var i = from;
|
||||
while (i < line.len-1) : (i += 1) {
|
||||
if (!std.ascii.isDigit(line[i+1])) { break; }
|
||||
}
|
||||
return i+1;
|
||||
}
|
||||
|
||||
fn append_unique(list: *PointList, point: PointU32) !void {
|
||||
for (list.items) |item| {
|
||||
if (item.eql(&point)) { return; }
|
||||
}
|
||||
try list.append(point);
|
||||
}
|
||||
|
||||
fn find_neighbouring_numbers(found_list: *PointList, lines: [][]const u8, x: usize, y: usize) !void {
|
||||
const neighbours = .{
|
||||
.{ -1, -1 }, .{ 0, -1 }, .{ 1, -1 },
|
||||
.{ -1, 0 }, .{ 1, 0 },
|
||||
.{ -1, 1 }, .{ 0, 1 }, .{ 1, 1 },
|
||||
};
|
||||
|
||||
inline for (neighbours) |offset| {
|
||||
const nx = @as(i32, @intCast(x)) + offset[0];
|
||||
const ny = @as(i32, @intCast(y)) + offset[1];
|
||||
if ((nx >= 0 or ny >= 0 or nx < lines[y].len or ny < lines.len)) {
|
||||
const nx_u32: u32 = @intCast(nx);
|
||||
const ny_u32: u32 = @intCast(ny);
|
||||
if (std.ascii.isDigit(lines[ny_u32][nx_u32])) {
|
||||
const number_start = find_number_start(lines[ny_u32], nx_u32);
|
||||
try append_unique(found_list, .{ .x = number_start, .y = ny_u32 });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const lines = input.lines;
|
||||
const allocator = input.allocator;
|
||||
|
||||
var numbers = PointList.init(allocator);
|
||||
defer numbers.deinit();
|
||||
|
||||
for (lines, 0..) |line, y| {
|
||||
for (line, 0..) |c, x| {
|
||||
if (std.ascii.isDigit(c) or c == '.') { continue; }
|
||||
|
||||
try find_neighbouring_numbers(&numbers, lines, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
var sum: u32 = 0;
|
||||
for (numbers.items) |number_pos| {
|
||||
const line = lines[number_pos.y];
|
||||
const number_end = find_number_end(line, number_pos.x);
|
||||
const number_str = line[number_pos.x..number_end];
|
||||
sum += try std.fmt.parseInt(u32, number_str, 10);
|
||||
}
|
||||
|
||||
return .{ .uint = sum };
|
||||
}
|
||||
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const lines = input.lines;
|
||||
const allocator = input.allocator;
|
||||
|
||||
var sum: u32 = 0;
|
||||
for (lines, 0..) |line, y| {
|
||||
for (line, 0..) |c, x| {
|
||||
if (c != '*') { continue; }
|
||||
|
||||
var numbers = PointList.init(allocator);
|
||||
defer numbers.deinit();
|
||||
|
||||
try find_neighbouring_numbers(&numbers, lines, x, y);
|
||||
|
||||
if (numbers.items.len != 2) continue;
|
||||
|
||||
var gear_ratio: u32 = 1;
|
||||
for (numbers.items) |number_pos| {
|
||||
const number_line = lines[number_pos.y];
|
||||
const number_end = find_number_end(number_line, number_pos.x);
|
||||
const number_str = number_line[number_pos.x..number_end];
|
||||
const number = try std.fmt.parseInt(u32, number_str, 10);
|
||||
gear_ratio *= number;
|
||||
}
|
||||
|
||||
sum += gear_ratio;
|
||||
}
|
||||
}
|
||||
|
||||
return .{ .uint = sum };
|
||||
}
|
||||
|
||||
test "part 1 example" {
|
||||
var lines = [_][]const u8{
|
||||
"467..114..",
|
||||
"...*......",
|
||||
"..35..633.",
|
||||
"......#...",
|
||||
"617*......",
|
||||
".....+.58.",
|
||||
"..592.....",
|
||||
"......755.",
|
||||
"...$.*....",
|
||||
".664.598.."
|
||||
};
|
||||
var input = aoc.Input{ .lines = &lines, .allocator = std.testing.allocator };
|
||||
var actual = try part1(&input);
|
||||
var expected: u32 = 4361;
|
||||
try std.testing.expectEqual(expected, actual.uint);
|
||||
}
|
||||
|
||||
test "part 2 example" {
|
||||
var lines = [_][]const u8{
|
||||
"467..114..",
|
||||
"...*......",
|
||||
"..35..633.",
|
||||
"......#...",
|
||||
"617*......",
|
||||
".....+.58.",
|
||||
"..592.....",
|
||||
"......755.",
|
||||
"...$.*....",
|
||||
".664.598.."
|
||||
};
|
||||
var input = aoc.Input{ .lines = &lines, .allocator = std.testing.allocator };
|
||||
var actual = try part2(&input);
|
||||
var expected: u32 = 467835;
|
||||
try std.testing.expectEqual(expected, actual.uint);
|
||||
}
|
@ -21,7 +21,8 @@ fn create_day(comptime module: anytype) aoc.Day {
|
||||
|
||||
const Days = [_]aoc.Day{
|
||||
create_day(@import("day1.zig")),
|
||||
create_day(@import("day2.zig"))
|
||||
create_day(@import("day2.zig")),
|
||||
create_day(@import("day3.zig"))
|
||||
};
|
||||
|
||||
pub fn main() !u8 {
|
||||
@ -98,4 +99,5 @@ pub fn main() !u8 {
|
||||
test {
|
||||
_ = @import("day1.zig");
|
||||
_ = @import("day2.zig");
|
||||
_ = @import("day3.zig");
|
||||
}
|
||||
|
12
src/point.zig
Normal file
12
src/point.zig
Normal file
@ -0,0 +1,12 @@
|
||||
pub fn Point(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
x: T,
|
||||
y: T,
|
||||
|
||||
pub fn eql(self: *const Self, other: *const Self) bool {
|
||||
return self.x == other.x and self.y == other.y;
|
||||
}
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user