Compare commits
12 Commits
30d638ca51
...
main
Author | SHA1 | Date | |
---|---|---|---|
aeea7ee99c
|
|||
6065242de9
|
|||
a684d9b238
|
|||
992673f784
|
|||
0b6eda2892
|
|||
b9bff3998e
|
|||
b13d5bb5f9
|
|||
06ce20853a
|
|||
794dddf854
|
|||
fa7a9aab14
|
|||
d80a39e7dc
|
|||
3e8dca665f
|
170
src/day10.zig
Normal file
170
src/day10.zig
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const util = @import("util.zig");
|
||||||
|
const mem = std.mem;
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
const input = @embedFile("data/day10.txt");
|
||||||
|
const sln = try solve(util.gpa, input);
|
||||||
|
try printPipes(std.io.getStdOut(), input);
|
||||||
|
std.debug.print("{d}\n", .{sln.a});
|
||||||
|
std.debug.print("{d}\n", .{sln.b});
|
||||||
|
}
|
||||||
|
|
||||||
|
const Solution = struct {
|
||||||
|
a: usize,
|
||||||
|
b: usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Direction = enum(u2) {
|
||||||
|
up,
|
||||||
|
down,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn Walker(comptime T: type) type {
|
||||||
|
return struct {
|
||||||
|
r: T,
|
||||||
|
c: T,
|
||||||
|
facing: Direction,
|
||||||
|
|
||||||
|
fn init(r: T, c: T) @This() {
|
||||||
|
return .{ .r = r, .c = c, .facing = .up };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn walk(self: *@This(), grid: [][]u8) void {
|
||||||
|
self.walkSpace(grid[self.r][self.c]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn walkSpace(self: *@This(), char: u8) void {
|
||||||
|
switch (char) {
|
||||||
|
'S' => {},
|
||||||
|
'|' => assert(self.facing == .up or self.facing == .down),
|
||||||
|
'-' => assert(self.facing == .left or self.facing == .right),
|
||||||
|
'L' => switch (self.facing) {
|
||||||
|
.down => self.turn(.right),
|
||||||
|
.left => self.turn(.up),
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
'J' => switch (self.facing) {
|
||||||
|
.down => self.turn(.left),
|
||||||
|
.right => self.turn(.up),
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
'7' => switch (self.facing) {
|
||||||
|
.up => self.turn(.left),
|
||||||
|
.right => self.turn(.down),
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
'F' => switch (self.facing) {
|
||||||
|
.up => self.turn(.right),
|
||||||
|
.left => self.turn(.down),
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
self.fwd();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn move(self: *@This(), row: i32, col: i32) void {
|
||||||
|
self.*.r += row;
|
||||||
|
self.*.c += col;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fwd(self: *@This()) void {
|
||||||
|
switch (self.facing) {
|
||||||
|
.up => self.move(-1, 0),
|
||||||
|
.down => self.move(1, 0),
|
||||||
|
.left => self.move(0, -1),
|
||||||
|
.right => self.move(0, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn turn(self: *@This(), dir: Direction) void {
|
||||||
|
self.*.facing = dir;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve(alloc: mem.Allocator, input: []const u8) !Solution {
|
||||||
|
_ = alloc;
|
||||||
|
var grid: [][]u8 = undefined; // try alloc.alloc(u8, mem.count(u8, input, &[_]u8{'\n'}));
|
||||||
|
|
||||||
|
var s_found = false;
|
||||||
|
var sr: u32 = 0;
|
||||||
|
var sc: u32 = 0;
|
||||||
|
|
||||||
|
var it = util.splitLines(input);
|
||||||
|
var curr_row: u32 = 0;
|
||||||
|
while (it.next()) |line| {
|
||||||
|
if (line.len == 0) continue;
|
||||||
|
// grid[curr_row] = line;
|
||||||
|
|
||||||
|
if (!s_found) {
|
||||||
|
if (mem.indexOfScalar(u8, line, 'S')) |col| {
|
||||||
|
_ = col;
|
||||||
|
sr = curr_row;
|
||||||
|
// sc = col;
|
||||||
|
s_found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find actual starting position.
|
||||||
|
var walker = Walker(u32).init(sr, sc);
|
||||||
|
if (mem.indexOfScalar(u8, "|7F", grid[sr - 1][sc])) |_| {
|
||||||
|
walker.facing = .up;
|
||||||
|
} else if (mem.indexOfScalar(u8, "|JL", grid[sr + 1][sc])) |_| {
|
||||||
|
walker.facing = .down;
|
||||||
|
} else if (mem.indexOfScalar(u8, "-LF", grid[sr][sc - 1])) |_| {
|
||||||
|
walker.facing = .left;
|
||||||
|
} else if (mem.indexOfScalar(u8, "-J7", grid[sr][sc + 1])) |_| {
|
||||||
|
walker.facing = .right;
|
||||||
|
}
|
||||||
|
|
||||||
|
var steps: u32 = 1;
|
||||||
|
while (true) {
|
||||||
|
steps += 1;
|
||||||
|
if (grid[walker.r][walker.c] == 'S') break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ .a = steps / 2, .b = 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn printPipes(writer: anytype, input: []const u8) !void {
|
||||||
|
for (input) |char| {
|
||||||
|
_ = switch (char) {
|
||||||
|
'|' => try writer.write("│"),
|
||||||
|
'-' => try writer.write("─"),
|
||||||
|
'L' => try writer.write("└"),
|
||||||
|
'J' => try writer.write("┘"),
|
||||||
|
'7' => try writer.write("┐"),
|
||||||
|
'F' => try writer.write("┌"),
|
||||||
|
'.' => try writer.write(" "),
|
||||||
|
'S' => try writer.write("o"),
|
||||||
|
'\n' => try writer.write("\n"),
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "silver" {
|
||||||
|
const input =
|
||||||
|
\\-L|F7
|
||||||
|
\\7S-7|
|
||||||
|
\\L|7||
|
||||||
|
\\-L-J|
|
||||||
|
\\L|-JF
|
||||||
|
;
|
||||||
|
const sln = try solve(std.testing.allocator, input);
|
||||||
|
try std.testing.expectEqual(@as(usize, 6), sln.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "gold" {
|
||||||
|
const input =
|
||||||
|
\\
|
||||||
|
;
|
||||||
|
const sln = try solve(std.testing.allocator, input);
|
||||||
|
try std.testing.expectEqual(@as(usize, 0), sln.b);
|
||||||
|
}
|
140
src/day12.zig
140
src/day12.zig
@ -14,21 +14,126 @@ const Solution = struct {
|
|||||||
b: usize,
|
b: usize,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn solve(alloc: mem.Allocator, input: []const u8) !Solution {
|
fn hash(alloc: mem.Allocator, pattern: []const u8, groups: []const u8, curr_group: u8) ![]u8 {
|
||||||
_ = alloc;
|
var a = try std.ArrayList(u8).initCapacity(alloc, pattern.len + groups.len + 1);
|
||||||
|
try a.appendSlice(pattern);
|
||||||
var it = util.splitLines(input);
|
try a.appendSlice(groups);
|
||||||
while (it.next()) |line| {
|
try a.append(curr_group);
|
||||||
if (line.len == 0) continue;
|
return try a.toOwnedSlice();
|
||||||
|
|
||||||
var lit = util.splitSpace(line);
|
|
||||||
const record = lit.next().?;
|
|
||||||
_ = record;
|
|
||||||
const groups = lit.next().?;
|
|
||||||
_ = groups;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return .{ .a = 0, .b = 0 };
|
var memo: std.StringHashMap(usize) = undefined;
|
||||||
|
|
||||||
|
fn clone(comptime T: type, alloc: mem.Allocator, s: []const T) ![]T {
|
||||||
|
var a = try alloc.alloc(T, s.len);
|
||||||
|
@memcpy(a, s);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solvePattern(alloc: mem.Allocator, pattern: []const u8, groups: []const u8, curr_group: u8) !usize {
|
||||||
|
const h = try hash(alloc, pattern, groups, curr_group);
|
||||||
|
if (memo.get(h)) |m| {
|
||||||
|
alloc.free(h);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pattern.len == 0) {
|
||||||
|
return if (groups.len == 0) 1 else 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const res: usize = b: {
|
||||||
|
switch (pattern[0]) {
|
||||||
|
'#' => {
|
||||||
|
// Too many #
|
||||||
|
if (groups.len == 0 or curr_group >= groups[0]) {
|
||||||
|
break :b 0;
|
||||||
|
}
|
||||||
|
// Special-case last #
|
||||||
|
if (pattern.len == 1 and groups.len == 1 and groups[0] == curr_group + 1) {
|
||||||
|
break :b 1;
|
||||||
|
}
|
||||||
|
break :b try solvePattern(alloc, pattern[1..], groups, curr_group + 1);
|
||||||
|
},
|
||||||
|
'.' => {
|
||||||
|
if (curr_group > 0) {
|
||||||
|
if (groups.len == 0 or curr_group != groups[0]) {
|
||||||
|
// Too many #
|
||||||
|
break :b 0;
|
||||||
|
} else {
|
||||||
|
// Group done
|
||||||
|
break :b try solvePattern(alloc, pattern[1..], groups[1..], 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Not growing a group, skip.
|
||||||
|
break :b try solvePattern(alloc, pattern[1..], groups, 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'?' => {
|
||||||
|
const p1 = try clone(u8, alloc, pattern);
|
||||||
|
defer alloc.free(p1);
|
||||||
|
const p2 = try clone(u8, alloc, pattern);
|
||||||
|
defer alloc.free(p2);
|
||||||
|
|
||||||
|
p1[0] = '#';
|
||||||
|
p2[0] = '.';
|
||||||
|
|
||||||
|
break :b try solvePattern(alloc, p1, groups, curr_group) +
|
||||||
|
try solvePattern(alloc, p2, groups, curr_group);
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try memo.put(h, res);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unfold(alloc: mem.Allocator, input: []const u8, sep: u8) ![]const u8 {
|
||||||
|
var buf = try std.ArrayList(u8).initCapacity(alloc, input.len * 5 + 5);
|
||||||
|
for (0..5) |i| {
|
||||||
|
if (i > 0 and sep > 0) try buf.append(sep);
|
||||||
|
try buf.appendSlice(input);
|
||||||
|
}
|
||||||
|
return try buf.toOwnedSlice();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve(alloc: mem.Allocator, input: []const u8) !Solution {
|
||||||
|
memo = std.StringHashMap(usize).init(alloc);
|
||||||
|
defer memo.deinit();
|
||||||
|
|
||||||
|
var sum1: usize = 0;
|
||||||
|
var sum2: usize = 0;
|
||||||
|
|
||||||
|
var it = util.splitLines(input);
|
||||||
|
var i: usize = 1;
|
||||||
|
while (it.next()) |line| {
|
||||||
|
if (line.len == 0) continue;
|
||||||
|
std.debug.print("line {} ", .{i});
|
||||||
|
|
||||||
|
var lit = util.splitSpace(line);
|
||||||
|
const pattern = lit.next().?;
|
||||||
|
const raw_groups = lit.next().?;
|
||||||
|
const groups = try util.parseIntsScalar(u8, alloc, raw_groups, .{ .sep = ',' });
|
||||||
|
defer alloc.free(groups);
|
||||||
|
|
||||||
|
const unfolded_pattern = try unfold(alloc, pattern, '?');
|
||||||
|
const unfolded_groups = try unfold(alloc, groups, 0);
|
||||||
|
defer alloc.free(unfolded_pattern);
|
||||||
|
defer alloc.free(unfolded_groups);
|
||||||
|
|
||||||
|
sum1 += try solvePattern(alloc, pattern, groups, 0);
|
||||||
|
sum2 += try solvePattern(alloc, unfolded_pattern, unfolded_groups, 0);
|
||||||
|
std.debug.print("{} {}\n", .{ sum1, sum2 });
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mkeys = memo.keyIterator();
|
||||||
|
while (mkeys.next()) |k| {
|
||||||
|
alloc.free(k.*);
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ .a = sum1, .b = sum2 };
|
||||||
}
|
}
|
||||||
|
|
||||||
test "silver" {
|
test "silver" {
|
||||||
@ -46,8 +151,13 @@ test "silver" {
|
|||||||
|
|
||||||
test "gold" {
|
test "gold" {
|
||||||
const input =
|
const input =
|
||||||
\\
|
\\???.### 1,1,3
|
||||||
|
\\.??..??...?##. 1,1,3
|
||||||
|
\\?#?#?#?#?#?#?#? 1,3,1,6
|
||||||
|
\\????.#...#... 4,1,1
|
||||||
|
\\????.######..#####. 1,6,5
|
||||||
|
\\?###???????? 3,2,1
|
||||||
;
|
;
|
||||||
const sln = try solve(std.testing.allocator, input);
|
const sln = try solve(std.testing.allocator, input);
|
||||||
try std.testing.expectEqual(@as(usize, 0), sln.b);
|
try std.testing.expectEqual(@as(usize, 525152), sln.b);
|
||||||
}
|
}
|
||||||
|
136
src/day13.zig
Normal file
136
src/day13.zig
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const util = @import("util.zig");
|
||||||
|
const mem = std.mem;
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
const input = @embedFile("data/day13.txt");
|
||||||
|
const sln = try solve(util.gpa, input);
|
||||||
|
std.debug.print("{d}\n", .{sln.a});
|
||||||
|
std.debug.print("{d}\n", .{sln.b});
|
||||||
|
}
|
||||||
|
|
||||||
|
const Solution = struct {
|
||||||
|
a: usize,
|
||||||
|
b: usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn transpose(alloc: mem.Allocator, grid: []const []const u8) ![]const []const u8 {
|
||||||
|
std.debug.assert(grid.len > 0 and grid[0].len > 0);
|
||||||
|
var g = try alloc.alloc([]u8, grid[0].len);
|
||||||
|
for (0..grid[0].len) |i| {
|
||||||
|
g[i] = try alloc.alloc(u8, grid.len);
|
||||||
|
}
|
||||||
|
for (0..grid.len) |i| {
|
||||||
|
for (0..grid[i].len) |j| {
|
||||||
|
g[j][i] = grid[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn findReflection(input: []const []const u8, err_tolerance: usize) ?usize {
|
||||||
|
if (input.len == 0) return 0;
|
||||||
|
|
||||||
|
const h = input.len;
|
||||||
|
const w = input[0].len;
|
||||||
|
|
||||||
|
for (0..h - 1) |scan| {
|
||||||
|
var offset: usize = 0;
|
||||||
|
var col: usize = 0;
|
||||||
|
var errors: usize = 0;
|
||||||
|
while (true) {
|
||||||
|
if (input[scan - offset][col] != input[scan + offset + 1][col]) {
|
||||||
|
errors += 1;
|
||||||
|
}
|
||||||
|
if (errors > err_tolerance + 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
col = (col + 1) % w;
|
||||||
|
if (col == 0) offset += 1;
|
||||||
|
if (scan < offset or scan + offset + 1 >= h) {
|
||||||
|
if (errors == err_tolerance) return scan + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve(alloc: mem.Allocator, input: []const u8) !Solution {
|
||||||
|
var curr_pattern = std.ArrayList([]const u8).init(alloc);
|
||||||
|
defer curr_pattern.deinit();
|
||||||
|
|
||||||
|
var it = util.splitLines(input);
|
||||||
|
var sums = [2]usize{ 0, 0 };
|
||||||
|
while (it.next()) |line| {
|
||||||
|
if (line.len == 0) {
|
||||||
|
const pattern = try curr_pattern.toOwnedSlice();
|
||||||
|
defer alloc.free(pattern);
|
||||||
|
for (0..2) |et| {
|
||||||
|
if (findReflection(pattern, et)) |score| {
|
||||||
|
sums[et] += 100 * score;
|
||||||
|
} else {
|
||||||
|
const t = try transpose(alloc, pattern);
|
||||||
|
sums[et] += findReflection(t, et) orelse unreachable;
|
||||||
|
|
||||||
|
// Ew.
|
||||||
|
for (t) |r| {
|
||||||
|
alloc.free(r);
|
||||||
|
}
|
||||||
|
alloc.free(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try curr_pattern.append(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ .a = sums[0], .b = sums[1] };
|
||||||
|
}
|
||||||
|
|
||||||
|
test "silver" {
|
||||||
|
const input =
|
||||||
|
\\#.##..##.
|
||||||
|
\\..#.##.#.
|
||||||
|
\\##......#
|
||||||
|
\\##......#
|
||||||
|
\\..#.##.#.
|
||||||
|
\\..##..##.
|
||||||
|
\\#.#.##.#.
|
||||||
|
\\
|
||||||
|
\\#...##..#
|
||||||
|
\\#....#..#
|
||||||
|
\\..##..###
|
||||||
|
\\#####.##.
|
||||||
|
\\#####.##.
|
||||||
|
\\..##..###
|
||||||
|
\\#....#..#
|
||||||
|
\\
|
||||||
|
;
|
||||||
|
const sln = try solve(std.testing.allocator, input);
|
||||||
|
try std.testing.expectEqual(@as(usize, 405), sln.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "gold" {
|
||||||
|
const input =
|
||||||
|
\\#.##..##.
|
||||||
|
\\..#.##.#.
|
||||||
|
\\##......#
|
||||||
|
\\##......#
|
||||||
|
\\..#.##.#.
|
||||||
|
\\..##..##.
|
||||||
|
\\#.#.##.#.
|
||||||
|
\\
|
||||||
|
\\#...##..#
|
||||||
|
\\#....#..#
|
||||||
|
\\..##..###
|
||||||
|
\\#####.##.
|
||||||
|
\\#####.##.
|
||||||
|
\\..##..###
|
||||||
|
\\#....#..#
|
||||||
|
\\
|
||||||
|
;
|
||||||
|
const sln = try solve(std.testing.allocator, input);
|
||||||
|
try std.testing.expectEqual(@as(usize, 400), sln.b);
|
||||||
|
}
|
94
src/day14.zig
Normal file
94
src/day14.zig
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const util = @import("util.zig");
|
||||||
|
const mem = std.mem;
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
const input = @embedFile("data/day14.txt");
|
||||||
|
const sln = try solve(util.gpa, input);
|
||||||
|
std.debug.print("{d}\n", .{sln.a});
|
||||||
|
std.debug.print("{d}\n", .{sln.b});
|
||||||
|
}
|
||||||
|
|
||||||
|
const Solution = struct {
|
||||||
|
a: usize,
|
||||||
|
b: usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn northWeight(alloc: mem.Allocator, grid: [][]u8) !usize {
|
||||||
|
var next_slot = try alloc.alloc(u32, grid[0].len);
|
||||||
|
defer alloc.free(next_slot);
|
||||||
|
@memset(next_slot, 0);
|
||||||
|
|
||||||
|
var weight: usize = 0;
|
||||||
|
for (grid, 0..) |line, row| {
|
||||||
|
for (line, 0..) |char, col| {
|
||||||
|
switch (char) {
|
||||||
|
'O' => {
|
||||||
|
weight += grid.len - next_slot[col];
|
||||||
|
next_slot[col] += 1;
|
||||||
|
},
|
||||||
|
'#' => next_slot[col] = @as(u32, @intCast(row)) + 1,
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spin(grid: [][]u8, n: usize) void {
|
||||||
|
_ = grid;
|
||||||
|
for (0..n) |_| {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve(alloc: mem.Allocator, input: []const u8) !Solution {
|
||||||
|
var height = mem.count(u8, input, &[_]u8{'\n'});
|
||||||
|
if (input[input.len - 1] != '\n') height += 1;
|
||||||
|
|
||||||
|
var grid = try alloc.alloc([]u8, height);
|
||||||
|
defer alloc.free(grid);
|
||||||
|
|
||||||
|
var it = util.splitLines(input);
|
||||||
|
var row: u32 = 0;
|
||||||
|
while (it.next()) |line| {
|
||||||
|
if (line.len == 0) continue;
|
||||||
|
grid[row] = try alloc.alloc(u8, line.len);
|
||||||
|
@memcpy(grid[row], line);
|
||||||
|
row += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const w = try northWeight(alloc, grid);
|
||||||
|
spin(grid, 1000000000);
|
||||||
|
const v = try northWeight(alloc, grid);
|
||||||
|
_ = v;
|
||||||
|
|
||||||
|
for (grid) |line| {
|
||||||
|
alloc.free(line);
|
||||||
|
}
|
||||||
|
return .{ .a = w, .b = 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
test "silver" {
|
||||||
|
const input =
|
||||||
|
\\O....#....
|
||||||
|
\\O.OO#....#
|
||||||
|
\\.....##...
|
||||||
|
\\OO.#O....O
|
||||||
|
\\.O.....O#.
|
||||||
|
\\O.#..O.#.#
|
||||||
|
\\..O..#O..O
|
||||||
|
\\.......O..
|
||||||
|
\\#....###..
|
||||||
|
\\#OO..#....
|
||||||
|
;
|
||||||
|
const sln = try solve(std.testing.allocator, input);
|
||||||
|
try std.testing.expectEqual(@as(usize, 136), sln.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "gold" {
|
||||||
|
const input =
|
||||||
|
\\
|
||||||
|
;
|
||||||
|
_ = input;
|
||||||
|
// const sln = try solve(std.testing.allocator, input);
|
||||||
|
// try std.testing.expectEqual(@as(usize, 0), sln.b);
|
||||||
|
}
|
91
src/day15.zig
Normal file
91
src/day15.zig
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const util = @import("util.zig");
|
||||||
|
const mem = std.mem;
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
const input = @embedFile("data/day15.txt");
|
||||||
|
const sln = try solve(util.gpa, input);
|
||||||
|
std.debug.print("{d}\n", .{sln.a});
|
||||||
|
std.debug.print("{d}\n", .{sln.b});
|
||||||
|
}
|
||||||
|
|
||||||
|
const Solution = struct {
|
||||||
|
a: usize,
|
||||||
|
b: usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn hash(input: []const u8) u32 {
|
||||||
|
var v: u32 = 0;
|
||||||
|
for (input) |c| {
|
||||||
|
v = ((v + c) * 17) % 256;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SAHM = std.StringArrayHashMap(u8);
|
||||||
|
|
||||||
|
fn solve(alloc: mem.Allocator, input: []const u8) !Solution {
|
||||||
|
const trimmed = mem.trimRight(u8, input, "\n\r");
|
||||||
|
|
||||||
|
var hash_sum: u32 = 0;
|
||||||
|
var it = util.split(trimmed, ',');
|
||||||
|
while (it.next()) |line| {
|
||||||
|
if (line.len == 0) continue;
|
||||||
|
hash_sum += hash(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
var boxes: [256]?SAHM = [_]?SAHM{null} ** 256;
|
||||||
|
it = util.split(trimmed, ',');
|
||||||
|
while (it.next()) |line| {
|
||||||
|
if (line.len == 0) continue;
|
||||||
|
const op = mem.indexOfAny(u8, line, "-=") orelse unreachable;
|
||||||
|
const label = line[0..op];
|
||||||
|
const label_hash = hash(label);
|
||||||
|
|
||||||
|
var box = &(boxes[label_hash] orelse init: {
|
||||||
|
var b = SAHM.init(alloc);
|
||||||
|
boxes[label_hash] = b;
|
||||||
|
break :init b;
|
||||||
|
});
|
||||||
|
|
||||||
|
switch (line[op]) {
|
||||||
|
'-' => _ = box.orderedRemove(label),
|
||||||
|
'=' => try box.put(label, try std.fmt.parseInt(u8, line[op + 1 ..], 10)),
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var focus: usize = 0;
|
||||||
|
for (boxes, 1..) |maybe_box, box_n| {
|
||||||
|
var box = maybe_box orelse continue;
|
||||||
|
var box_it = box.iterator();
|
||||||
|
var lens_n: usize = 1;
|
||||||
|
while (box_it.next()) |entry| {
|
||||||
|
focus += box_n * lens_n * entry.value_ptr.*;
|
||||||
|
lens_n += 1;
|
||||||
|
}
|
||||||
|
box.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ .a = hash_sum, .b = focus };
|
||||||
|
}
|
||||||
|
|
||||||
|
test "sample hash" {
|
||||||
|
try std.testing.expectEqual(@as(usize, 52), hash("HASH"));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "silver" {
|
||||||
|
const input =
|
||||||
|
\\rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7
|
||||||
|
;
|
||||||
|
const sln = try solve(std.testing.allocator, input);
|
||||||
|
try std.testing.expectEqual(@as(usize, 1320), sln.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "gold" {
|
||||||
|
const input =
|
||||||
|
\\rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7
|
||||||
|
;
|
||||||
|
const sln = try solve(std.testing.allocator, input);
|
||||||
|
try std.testing.expectEqual(@as(usize, 145), sln.b);
|
||||||
|
}
|
159
src/day16.zig
Normal file
159
src/day16.zig
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const util = @import("util.zig");
|
||||||
|
const mem = std.mem;
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
const input = @embedFile("data/day16.txt");
|
||||||
|
const sln = try solve(util.gpa, input);
|
||||||
|
std.debug.print("{d}\n", .{sln.a});
|
||||||
|
std.debug.print("{d}\n", .{sln.b});
|
||||||
|
}
|
||||||
|
|
||||||
|
const Solution = struct {
|
||||||
|
a: usize,
|
||||||
|
b: usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Direction = enum {
|
||||||
|
up,
|
||||||
|
right,
|
||||||
|
down,
|
||||||
|
left,
|
||||||
|
|
||||||
|
fn x(self: @This()) isize {
|
||||||
|
return switch (self) {
|
||||||
|
.up, .down => 0,
|
||||||
|
.left => -1,
|
||||||
|
.right => 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn y(self: @This()) isize {
|
||||||
|
return switch (self) {
|
||||||
|
.left, .right => 0,
|
||||||
|
.up => -1,
|
||||||
|
.down => 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rotate(self: @This(), nineties: usize) Direction {
|
||||||
|
return @enumFromInt((@intFromEnum(self) + nineties) % std.enums.values(@This()).len);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Point = struct {
|
||||||
|
x: isize,
|
||||||
|
y: isize,
|
||||||
|
dir: Direction,
|
||||||
|
};
|
||||||
|
|
||||||
|
var states: std.AutoArrayHashMap(Point, void) = undefined;
|
||||||
|
|
||||||
|
fn run(alloc: mem.Allocator, grid: [][]u8, visited: [][]bool, init_x: isize, init_y: isize, init_dir: Direction) !void {
|
||||||
|
var x = init_x;
|
||||||
|
var y = init_y;
|
||||||
|
var dir = init_dir;
|
||||||
|
|
||||||
|
while (0 <= x and x < grid[0].len - 1 and 0 <= y and y < grid.len - 1) {
|
||||||
|
visited[@intCast(y)][@intCast(x)] = true;
|
||||||
|
var looped = try states.getOrPut(.{ .x = x, .y = y, .dir = dir });
|
||||||
|
if (looped.found_existing) break;
|
||||||
|
// std.debug.print("-----\n", .{});
|
||||||
|
// std.debug.print("{} {} {}\n", .{ x, y, dir });
|
||||||
|
// std.time.sleep(1_000_000_000);
|
||||||
|
switch (grid[@intCast(y)][@intCast(x)]) {
|
||||||
|
'.' => {
|
||||||
|
x += dir.x();
|
||||||
|
y += dir.y();
|
||||||
|
},
|
||||||
|
'|' => {
|
||||||
|
switch (dir) {
|
||||||
|
.up, .down => y += dir.y(),
|
||||||
|
.left, .right => {
|
||||||
|
try run(alloc, grid, visited, x, y - 1, .up);
|
||||||
|
try run(alloc, grid, visited, x, y + 1, .down);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'-' => {
|
||||||
|
switch (dir) {
|
||||||
|
.left, .right => x += dir.x(),
|
||||||
|
.up, .down => {
|
||||||
|
try run(alloc, grid, visited, x - 1, y, .left);
|
||||||
|
try run(alloc, grid, visited, x + 1, y, .right);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'/' => {
|
||||||
|
switch (dir) {
|
||||||
|
.left, .right => dir = dir.rotate(3),
|
||||||
|
.up, .down => dir = dir.rotate(1),
|
||||||
|
}
|
||||||
|
x += dir.x();
|
||||||
|
y += dir.y();
|
||||||
|
},
|
||||||
|
'\\' => {
|
||||||
|
switch (dir) {
|
||||||
|
.left, .right => dir = dir.rotate(1),
|
||||||
|
.up, .down => dir = dir.rotate(3),
|
||||||
|
}
|
||||||
|
x += dir.x();
|
||||||
|
y += dir.y();
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve(alloc: mem.Allocator, comptime input: []const u8) !Solution {
|
||||||
|
const trimmed = mem.trimRight(u8, input, "\n\r");
|
||||||
|
const w = mem.indexOfScalar(u8, trimmed, '\n') orelse unreachable;
|
||||||
|
const h = mem.count(u8, trimmed, "\n");
|
||||||
|
|
||||||
|
var visited = try util.allocGrid(bool, alloc, w, h, false);
|
||||||
|
const grid = try util.toGridOwned(alloc, trimmed, '\n');
|
||||||
|
|
||||||
|
states = std.AutoArrayHashMap(Point, void).init(alloc);
|
||||||
|
defer states.deinit();
|
||||||
|
try run(alloc, grid, visited, 0, 0, .right);
|
||||||
|
|
||||||
|
var energized: usize = 0;
|
||||||
|
for (visited) |row| {
|
||||||
|
for (row) |cell| {
|
||||||
|
if (cell) energized += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (grid) |row| {
|
||||||
|
alloc.free(row);
|
||||||
|
}
|
||||||
|
for (visited) |row| {
|
||||||
|
alloc.free(row);
|
||||||
|
}
|
||||||
|
alloc.free(grid);
|
||||||
|
alloc.free(visited);
|
||||||
|
return .{ .a = energized, .b = 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
const sample =
|
||||||
|
\\.|...\....
|
||||||
|
\\|.-.\.....
|
||||||
|
\\.....|-...
|
||||||
|
\\........|.
|
||||||
|
\\..........
|
||||||
|
\\.........\
|
||||||
|
\\..../.\\..
|
||||||
|
\\.-.-/..|..
|
||||||
|
\\.|....-|.\
|
||||||
|
\\..//.|....
|
||||||
|
;
|
||||||
|
|
||||||
|
test "silver" {
|
||||||
|
const sln = try solve(std.testing.allocator, sample);
|
||||||
|
try std.testing.expectEqual(@as(usize, 46), sln.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "gold" {
|
||||||
|
// const sln = try solve(std.testing.allocator, input);
|
||||||
|
// try std.testing.expectEqual(@as(usize, 0), sln.b);
|
||||||
|
}
|
28
src/util.zig
28
src/util.zig
@ -35,3 +35,31 @@ pub fn splitLines(buffer: []const u8) mem.SplitIterator(u8, .scalar) {
|
|||||||
pub fn splitSpace(buffer: []const u8) mem.SplitIterator(u8, .scalar) {
|
pub fn splitSpace(buffer: []const u8) mem.SplitIterator(u8, .scalar) {
|
||||||
return split(buffer, ' ');
|
return split(buffer, ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn allocGrid(comptime T: type, alloc: mem.Allocator, w: usize, h: usize, init: T) ![][]T {
|
||||||
|
var grid = try alloc.alloc([]T, h);
|
||||||
|
for (0..h) |i| {
|
||||||
|
grid[i] = try alloc.alloc(T, w);
|
||||||
|
@memset(grid[i], init);
|
||||||
|
}
|
||||||
|
return grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toGridOwned(alloc: mem.Allocator, buffer: []const u8, sep: u8) ![][]u8 {
|
||||||
|
if (buffer.len == 0) return error.Empty;
|
||||||
|
const w = mem.indexOfScalar(u8, buffer, sep) orelse unreachable;
|
||||||
|
var h = mem.count(u8, buffer, &[_]u8{sep});
|
||||||
|
if (buffer[buffer.len - 1] != sep) h += 1;
|
||||||
|
|
||||||
|
var grid = try alloc.alloc([]u8, h);
|
||||||
|
|
||||||
|
var it = split(buffer, sep);
|
||||||
|
var i: usize = 0;
|
||||||
|
while (it.next()) |line| {
|
||||||
|
grid[i] = try alloc.alloc(u8, w);
|
||||||
|
@memcpy(grid[i], line);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return grid;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user