solve day 14
This commit is contained in:
parent
c36f8c6805
commit
31c2a661c2
@ -195,7 +195,7 @@ pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
return .{ .uint = sum_min_distances(galaxies.items) };
|
||||
}
|
||||
|
||||
const example_input = [_][]u8{
|
||||
const example_input = [_][]const u8{
|
||||
"...#......",
|
||||
".......#..",
|
||||
"#.........",
|
||||
|
@ -208,7 +208,7 @@ pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
return .{ .uint = result };
|
||||
}
|
||||
|
||||
const example_input = &.{
|
||||
const example_input = [_][]const u8{
|
||||
"#.##..##.",
|
||||
"..#.##.#.",
|
||||
"##......#",
|
||||
|
233
src/day14.zig
Normal file
233
src/day14.zig
Normal file
@ -0,0 +1,233 @@
|
||||
const std = @import("std");
|
||||
const aoc = @import("./aoc.zig");
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const PointU32 = @import("./point.zig").Point(u32);
|
||||
|
||||
const Tile = enum {
|
||||
Empty,
|
||||
Rock,
|
||||
Wall
|
||||
};
|
||||
|
||||
const Input = struct {
|
||||
tiles: std.ArrayList(Tile),
|
||||
width: u32,
|
||||
height: u32,
|
||||
|
||||
fn init(allocator: Allocator) Input {
|
||||
return Input{
|
||||
.tiles = std.ArrayList(Tile).init(allocator),
|
||||
.width = 0,
|
||||
.height = 0,
|
||||
};
|
||||
}
|
||||
|
||||
fn deinit(self: Input) void {
|
||||
self.tiles.deinit();
|
||||
}
|
||||
|
||||
fn get_idx(self: Input, x: u32, y: u32) usize {
|
||||
assert(x < self.width);
|
||||
assert(y < self.height);
|
||||
return y * self.width + x;
|
||||
}
|
||||
|
||||
fn get(self: Input, x: u32, y: u32) Tile {
|
||||
return self.tiles.items[self.get_idx(x, y)];
|
||||
}
|
||||
|
||||
fn set(self: Input, x: u32, y: u32, tile: Tile) void {
|
||||
self.tiles.items[self.get_idx(x, y)] = tile;
|
||||
}
|
||||
|
||||
fn in_bounds(self: Input, x: i32, y: i32) bool {
|
||||
return (0 <= x and x < self.width) and (0 <= y and y < self.height);
|
||||
}
|
||||
|
||||
fn print(self: Input) void {
|
||||
for (0..self.height) |y| {
|
||||
for (0..self.height) |x| {
|
||||
const idx = y * self.width + x;
|
||||
const tile = self.tiles.items[idx];
|
||||
const symbol: u8 = switch (tile) {
|
||||
.Empty => '.',
|
||||
.Wall => '#',
|
||||
.Rock => 'O'
|
||||
};
|
||||
|
||||
std.debug.print("{c}", .{symbol});
|
||||
}
|
||||
std.debug.print("\n", .{});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fn parse_input(allocator: Allocator, lines: []const []const u8) !Input {
|
||||
var parsed = Input.init(allocator);
|
||||
errdefer parsed.deinit();
|
||||
parsed.width = @intCast(lines[0].len);
|
||||
parsed.height = @intCast(lines.len);
|
||||
|
||||
try parsed.tiles.ensureTotalCapacity(parsed.width * parsed.height);
|
||||
|
||||
for (lines) |line| {
|
||||
for (line) |symbol| {
|
||||
const tile = switch (symbol) {
|
||||
'O' => Tile.Rock,
|
||||
'.' => Tile.Empty,
|
||||
'#' => Tile.Wall,
|
||||
else => return error.InvalidTile
|
||||
};
|
||||
|
||||
try parsed.tiles.append(tile);
|
||||
}
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
fn slide_rock(input: Input, x: u32, y: u32, dir_x: i32, dir_y: i32) void {
|
||||
assert(input.get(x, y) == .Rock);
|
||||
|
||||
var new_x = x;
|
||||
var new_y = y;
|
||||
while (true) {
|
||||
const next_x = @as(i32, @intCast(new_x)) + dir_x;
|
||||
const next_y = @as(i32, @intCast(new_y)) + dir_y;
|
||||
if (!input.in_bounds(next_x, next_y)) break;
|
||||
if (input.get(@intCast(next_x), @intCast(next_y)) != .Empty) break;
|
||||
|
||||
new_x = @intCast(next_x);
|
||||
new_y = @intCast(next_y);
|
||||
}
|
||||
|
||||
input.set(x, y, .Empty);
|
||||
input.set(new_x, new_y, .Rock);
|
||||
}
|
||||
|
||||
fn slide_rocks(input: Input, dir_x: i32, dir_y: i32) void {
|
||||
if (dir_y != 0) {
|
||||
// Column-based
|
||||
for (0..input.height) |oy| {
|
||||
for (0..input.width) |ox| {
|
||||
const x: u32 = @intCast(ox);
|
||||
const y: u32 = @intCast(@as(i32, @intCast(oy)) * (-dir_y) + @divExact(dir_y + 1, 2) * @as(i32, @intCast(input.height-1)));
|
||||
if (input.get(x, y) == .Rock) {
|
||||
slide_rock(input, x, y, dir_x, dir_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Row-based
|
||||
for (0..input.width) |ox| {
|
||||
for (0..input.height) |oy| {
|
||||
const x: u32 = @intCast(@as(i32, @intCast(ox)) * (-dir_x) + @divExact(dir_x + 1, 2) * @as(i32, @intCast(input.width-1)));
|
||||
const y: u32 = @intCast(oy);
|
||||
if (input.get(x, y) == .Rock) {
|
||||
slide_rock(input, x, y, dir_x, dir_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cycle_slide(input: Input) void {
|
||||
const dirs = &.{
|
||||
.{ .x = 0, .y = -1 }, // North
|
||||
.{ .x = -1, .y = 0 }, // West
|
||||
.{ .x = 0, .y = 1 }, // South
|
||||
.{ .x = 1, .y = 0 }, // East
|
||||
};
|
||||
|
||||
inline for (dirs) |dir| {
|
||||
slide_rocks(input, dir.x, dir.y);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_total_load(input: Input) u64 {
|
||||
var result: u64 = 0;
|
||||
for (0..input.height) |y| {
|
||||
var count: u32 = 0;
|
||||
for (0..input.width) |x| {
|
||||
if (input.get(@intCast(x), @intCast(y)) == .Rock) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
result += count * (input.height - y);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn part1(input: *aoc.Input) !aoc.Result {
|
||||
const parsed = try parse_input(input.allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
slide_rocks(parsed, 0, -1);
|
||||
|
||||
return .{ .uint = get_total_load(parsed) };
|
||||
}
|
||||
|
||||
pub fn part2(input: *aoc.Input) !aoc.Result {
|
||||
const target_cycle_count = 1000000000;
|
||||
|
||||
const allocator = input.allocator;
|
||||
const parsed = try parse_input(allocator, input.lines);
|
||||
defer parsed.deinit();
|
||||
|
||||
var seen = std.ArrayList(std.ArrayList(Tile)).init(allocator);
|
||||
defer {
|
||||
for (seen.items) |tiles| {
|
||||
tiles.deinit();
|
||||
}
|
||||
seen.deinit();
|
||||
}
|
||||
|
||||
var cycle_size: u32 = 0;
|
||||
var cycle_start: u32 = 0;
|
||||
var iteration: u32 = 0;
|
||||
outer: while (true) {
|
||||
cycle_slide(parsed);
|
||||
|
||||
for (0.., seen.items) |i, tiles| {
|
||||
if (std.mem.eql(Tile, tiles.items, parsed.tiles.items)) {
|
||||
cycle_start = @intCast(i);
|
||||
cycle_size = @intCast(iteration - i);
|
||||
break :outer;
|
||||
}
|
||||
}
|
||||
try seen.append(try parsed.tiles.clone());
|
||||
|
||||
iteration += 1;
|
||||
}
|
||||
|
||||
const skipped_map = Input{
|
||||
.tiles = seen.items[@mod((target_cycle_count-1) - cycle_start, cycle_size) + cycle_start],
|
||||
.width = parsed.width,
|
||||
.height = parsed.height
|
||||
};
|
||||
|
||||
return .{ .uint = get_total_load(skipped_map) };
|
||||
}
|
||||
|
||||
const example_input = [_][]const u8{
|
||||
"O....#....",
|
||||
"O.OO#....#",
|
||||
".....##...",
|
||||
"OO.#O....O",
|
||||
".O.....O#.",
|
||||
"O.#..O.#.#",
|
||||
"..O..#O..O",
|
||||
".......O..",
|
||||
"#....###..",
|
||||
"#OO..#....",
|
||||
};
|
||||
|
||||
test "part 1 example" {
|
||||
try aoc.expectAnswerUInt(part1, 136, &example_input);
|
||||
}
|
||||
|
||||
test "part 2 example" {
|
||||
try aoc.expectAnswerUInt(part2, 64, &example_input);
|
||||
}
|
53
src/main.zig
53
src/main.zig
@ -21,19 +21,20 @@ 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("day3.zig")),
|
||||
create_day(@import("day4.zig")),
|
||||
create_day(@import("day5.zig")),
|
||||
create_day(@import("day6.zig")),
|
||||
create_day(@import("day7.zig")),
|
||||
create_day(@import("day8.zig")),
|
||||
create_day(@import("day9.zig")),
|
||||
create_day(@import("day10.zig")),
|
||||
create_day(@import("day11.zig")),
|
||||
create_day(@import("day12.zig")),
|
||||
create_day(@import("day13.zig")),
|
||||
create_day(@import("./day1.zig")),
|
||||
create_day(@import("./day2.zig")),
|
||||
create_day(@import("./day3.zig")),
|
||||
create_day(@import("./day4.zig")),
|
||||
create_day(@import("./day5.zig")),
|
||||
create_day(@import("./day6.zig")),
|
||||
create_day(@import("./day7.zig")),
|
||||
create_day(@import("./day8.zig")),
|
||||
create_day(@import("./day9.zig")),
|
||||
create_day(@import("./day10.zig")),
|
||||
create_day(@import("./day11.zig")),
|
||||
create_day(@import("./day12.zig")),
|
||||
create_day(@import("./day13.zig")),
|
||||
create_day(@import("./day14.zig")),
|
||||
};
|
||||
|
||||
fn kilobytes(count: u32) u32 {
|
||||
@ -178,16 +179,18 @@ pub fn main() !u8 {
|
||||
}
|
||||
|
||||
test {
|
||||
_ = @import("day1.zig");
|
||||
_ = @import("day2.zig");
|
||||
_ = @import("day3.zig");
|
||||
_ = @import("day4.zig");
|
||||
_ = @import("day5.zig");
|
||||
_ = @import("day6.zig");
|
||||
_ = @import("day7.zig");
|
||||
_ = @import("day8.zig");
|
||||
_ = @import("day9.zig");
|
||||
_ = @import("day10.zig");
|
||||
_ = @import("day11.zig");
|
||||
_ = @import("day12.zig");
|
||||
_ = @import("./day1.zig");
|
||||
_ = @import("./day2.zig");
|
||||
_ = @import("./day3.zig");
|
||||
_ = @import("./day4.zig");
|
||||
_ = @import("./day5.zig");
|
||||
_ = @import("./day6.zig");
|
||||
_ = @import("./day7.zig");
|
||||
_ = @import("./day8.zig");
|
||||
_ = @import("./day9.zig");
|
||||
_ = @import("./day10.zig");
|
||||
_ = @import("./day11.zig");
|
||||
_ = @import("./day12.zig");
|
||||
_ = @import("./day13.zig");
|
||||
_ = @import("./day14.zig");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user