Day 18, lets go!

This commit is contained in:
2023-12-18 23:20:12 +00:00
parent a25b982dab
commit 04b4afc87e
3 changed files with 403 additions and 3 deletions
AdventOfCode2023/src

@ -0,0 +1,239 @@
const std = @import("std");
const print = std.debug.print;
const EMPTY = '.';
const VERTICAL_SPLIT = '|';
const HORIZONTAL_SPLIT = '-';
const CLOCKWISE_TURN = '/';
const ANTI_CLOCKWISE_TURN = '\\';
const Directions = enum { UP, DOWN, LEFT, RIGHT };
const BeamsController = struct {
beams: std.AutoHashMap(usize, *Beam),
allocator: std.mem.Allocator,
counter: usize,
heatmap: std.AutoHashMap(u128, bool),
splitsMade: std.AutoHashMap(u128, bool),
pub fn walk(self: *BeamsController) !void {
var iter = self.*.beams.iterator();
var deleteList = std.ArrayList(usize).init(self.allocator);
defer deleteList.deinit();
while (iter.next()) |entry| {
var delete = try entry.value_ptr.*.step();
if (delete) {
// print("Beam {} removing\n", .{entry.value_ptr.*.index});
try deleteList.append(entry.key_ptr.*);
// self.allocator.destroy(entry.value_ptr.*);
} else {
// var beams = entry.value_ptr.*;
// print("Beam {} ({},{}) {}\n", .{ beams.index, beams.x, beams.y, beams.direction });
}
}
for (deleteList.items) |i| {
_ = self.*.beams.remove(i);
}
}
pub fn horizontalSplit(self: *BeamsController, beam: *Beam) !bool {
// Assume direction is up or down.
// Assume "parent" beam always goes right.
var coord = @as(u128, beam.x) << 64 | @as(u128, beam.y);
if (self.*.splitsMade.get(coord)) |_| {
// dont split again
return true;
}
var splitBeam = try self.allocator.create(Beam);
splitBeam.*.grid = beam.*.grid;
splitBeam.*.x = beam.*.x;
splitBeam.*.y = beam.*.y;
splitBeam.*.direction = Directions.LEFT;
splitBeam.*.controller = beam.*.controller;
self.*.counter += 1;
splitBeam.*.index = self.*.counter;
try self.*.beams.put(splitBeam.index, splitBeam);
try self.*.splitsMade.put(coord, true);
return false;
}
pub fn verticalSplit(self: *BeamsController, beam: *Beam) !bool {
// Assume direction is left or right
// Assume "parent" beam always goes down.
var coord = @as(u128, beam.x) << 64 | @as(u128, beam.y);
if (self.*.splitsMade.get(coord)) |_| {
// dont split again
return true;
}
var splitBeam = try self.allocator.create(Beam);
splitBeam.*.grid = beam.*.grid;
splitBeam.*.x = beam.*.x;
splitBeam.*.y = beam.*.y;
splitBeam.*.direction = Directions.UP;
splitBeam.*.controller = beam.*.controller;
self.*.counter += 1;
splitBeam.*.index = self.*.counter;
try self.*.beams.put(splitBeam.index, splitBeam);
try self.*.splitsMade.put(coord, true);
return false;
}
};
const Beam = struct {
grid: *[][]const u8,
x: usize,
y: usize,
direction: Directions,
controller: *BeamsController,
index: usize,
pub fn step(self: *Beam) !bool {
var coord = @as(u128, self.x) << 64 | @as(u128, self.y);
try self.*.controller.heatmap.put(coord, true);
switch (self.direction) {
Directions.RIGHT => {
if (self.*.x == self.*.grid.*[0].len - 1) {
return true;
}
var tile = self.*.grid.*[self.*.y][self.*.x];
if (tile == VERTICAL_SPLIT) {
// call beams controller vertical split.
var alreadyDone = try self.controller.verticalSplit(self);
if (alreadyDone) {
return true;
}
self.*.direction = Directions.DOWN;
} else if (tile == CLOCKWISE_TURN) {
// moving right. turn upwards.
self.*.direction = Directions.UP;
} else if (tile == ANTI_CLOCKWISE_TURN) {
self.*.direction = Directions.DOWN;
}
},
Directions.LEFT => {
if (self.*.x == 0) {
return true;
}
var tile = self.*.grid.*[self.*.y][self.*.x];
if (tile == VERTICAL_SPLIT) {
// call beams controller vertical split.
var alreadyDone = try self.controller.verticalSplit(self);
if (alreadyDone) {
return true;
}
self.*.direction = Directions.DOWN;
} else if (tile == CLOCKWISE_TURN) {
// moving right. turn upwards.
self.*.direction = Directions.DOWN;
} else if (tile == ANTI_CLOCKWISE_TURN) {
self.*.direction = Directions.UP;
}
},
Directions.UP => {
if (self.*.y == 0) {
return true;
}
var tile = self.*.grid.*[self.*.y][self.*.x];
if (tile == HORIZONTAL_SPLIT) {
// call beams controller vertical split.
var alreadyDone = try self.controller.horizontalSplit(self);
if (alreadyDone) {
return true;
}
self.*.direction = Directions.RIGHT;
} else if (tile == CLOCKWISE_TURN) {
// moving right. turn upwards.
self.*.direction = Directions.RIGHT;
} else if (tile == ANTI_CLOCKWISE_TURN) {
self.*.direction = Directions.LEFT;
}
},
Directions.DOWN => {
if (self.*.y == self.*.grid.*.len - 1) {
return true;
}
var tile = self.*.grid.*[self.*.y][self.*.x];
if (tile == HORIZONTAL_SPLIT) {
// call beams controller vertical split.
var alreadyDone = try self.controller.horizontalSplit(self);
if (alreadyDone) {
return true;
}
self.*.direction = Directions.RIGHT;
} else if (tile == CLOCKWISE_TURN) {
// moving right. turn upwards.
self.*.direction = Directions.LEFT;
} else if (tile == ANTI_CLOCKWISE_TURN) {
self.*.direction = Directions.RIGHT;
}
},
}
switch (self.direction) {
Directions.UP => {
self.*.y -= 1;
},
Directions.DOWN => {
self.*.y += 1;
},
Directions.LEFT => {
self.*.x -= 1;
},
Directions.RIGHT => {
self.*.x += 1;
},
}
coord = @as(u128, self.x) << 64 | @as(u128, self.y);
try self.*.controller.heatmap.put(coord, true);
return false;
}
};
pub fn solve(input: [][]const u8) !void {
var allocator = std.heap.page_allocator;
var controller = BeamsController{ .allocator = allocator, .beams = std.AutoHashMap(usize, *Beam).init(allocator), .counter = 0, .heatmap = std.AutoHashMap(u128, bool).init(allocator), .splitsMade = std.AutoHashMap(u128, bool).init(allocator) };
var in = input;
var firstBeam = try allocator.create(Beam);
firstBeam.*.x = 0;
firstBeam.*.y = 0;
firstBeam.*.direction = Directions.RIGHT;
firstBeam.*.grid = &in;
firstBeam.*.controller = &controller;
firstBeam.*.index = 0;
try controller.beams.put(0, firstBeam);
while (controller.beams.count() > 0) {
try controller.walk();
}
var iter = controller.heatmap.iterator();
while (iter.next()) |entry| {
var x = entry.key_ptr.* >> 64;
var y = entry.key_ptr.* & 0xFFFFFFFFFFFFFFFF;
print("{},{}\n", .{ x, y });
}
print("Part 1: {}\n", .{controller.heatmap.count()});
}
// 6858

@ -0,0 +1,159 @@
const std = @import("std");
const print = std.debug.print;
const GRID_SIZE = 10000;
fn countInside(grid: *[][]u32, x: usize, y: usize) void {
if (grid.*[y][x] == 1) {
return;
}
if (grid.*[y][x] > 2) {
return;
}
grid.*[y][x] = 1;
countInside(grid, x - 1, y);
countInside(grid, x + 1, y);
countInside(grid, x, y - 1);
countInside(grid, x, y + 1);
countInside(grid, x - 1, y - 1);
countInside(grid, x + 1, y - 1);
countInside(grid, x + 1, y + 1);
countInside(grid, x - 1, y + 1);
}
pub fn solve(input: [][]const u8) !void {
const allocator = std.heap.page_allocator;
var grid = try allocator.alloc([]u32, GRID_SIZE);
for (0..grid.len) |i| {
grid[i] = try allocator.alloc(u32, GRID_SIZE);
@memset(grid[i], 2);
}
var coords = std.ArrayList(u128).init(allocator);
var x: usize = GRID_SIZE / 2;
var y: usize = GRID_SIZE / 2;
var part2x: usize = 20_000_000_000;
var part2y: usize = 20_000_000_000;
var part2edges: usize = 0;
for (input) |line| {
var tokenizer = std.mem.tokenizeSequence(u8, line, " ");
var stringDirection = tokenizer.next().?;
var times = try std.fmt.parseInt(u32, tokenizer.next().?, 10);
var stringColour = tokenizer.next().?;
var colour = try std.fmt.parseInt(u32, stringColour[2 .. stringColour.len - 2], 16);
for (0..times) |_| {
switch (stringDirection[0]) {
'U' => {
y -= 1;
},
'D' => {
y += 1;
},
'R' => {
x += 1;
},
'L' => {
x -= 1;
},
else => unreachable,
}
grid[y][x] = colour;
}
var part2Direction = stringColour[stringColour.len - 2 .. stringColour.len - 1][0] - '0';
part2edges += colour;
if (part2Direction == 0) {
// Right
var c2 = @as(u128, part2x + colour) << 64 | @as(u128, part2y);
part2x = part2x + colour;
// try coords.put(c1, true);
try coords.append(c2);
} else if (part2Direction == 1) {
// Down
var c2 = @as(u128, part2x) << 64 | @as(u128, part2y + colour);
part2y = part2y + colour;
// try coords.put(c1, true);
try coords.append(c2);
} else if (part2Direction == 2) {
// Left
var c2 = @as(u128, part2x - colour) << 64 | @as(u128, part2y);
part2x = part2x - colour;
// try coords.put(c1, true);
try coords.append(c2);
} else if (part2Direction == 3) {
// Up
var c2 = @as(u128, part2x) << 64 | @as(u128, part2y - colour);
part2y = part2y - colour;
// try coords.put(c1, true);
try coords.append(c2);
}
}
countInside(&grid, GRID_SIZE / 2 + 1, GRID_SIZE / 2 + 1);
var part1: usize = 0;
var part2: i256 = 0;
for (4800..5300) |i| {
for (4800..5300) |j| {
if (grid[i][j] == 2) {
// print(".", .{});
} else {
// print("#", .{});
part1 += 1;
}
}
// print("\n", .{});
}
var first = coords.items[0];
var prev = first;
var items = try coords.toOwnedSlice();
for (items) |key| {
var x2 = @as(i256, key >> 64);
var y2 = @as(i256, key & 0xFFFFFFFFFFFFFFFF);
var x1 = @as(i256, prev >> 64);
var y1 = @as(i256, prev & 0xFFFFFFFFFFFFFFFF);
prev = key;
part2 += x1 * y2 - x2 * y1;
}
var x2 = @as(i256, first >> 64);
var y2 = @as(i256, first & 0xFFFFFFFFFFFFFFFF);
var x1 = @as(i256, prev >> 64);
var y1 = @as(i256, prev & 0xFFFFFFFFFFFFFFFF);
part2 += x1 * y2 - x2 * y1;
part2 = @divTrunc(part2, 2);
part2 += part2edges / 2 + 1;
print("Part 1: {}\n", .{part1});
print("Part 2: {}\n", .{part2});
}

@ -10,13 +10,15 @@ const std = @import("std");
// const day10 = @import("./day10/day10.zig");
// const day11 = @import("./day11/day11.zig");
// const day12 = @import("./day12/day12.zig");
const day15 = @import("./day15/day15.zig");
// const day15 = @import("./day15/day15.zig");
// const day16 = @import("./day16/day16.zig");
const day18 = @import("./day18/day18.zig");
const utils = @import("utils.zig");
pub fn main() !void {
const allocator = std.heap.page_allocator;
var input = try utils.getInput("./src/day15/input.txt", allocator);
var input = try utils.getInput("./src/day18/input.txt", allocator);
defer allocator.free(input);
try day15.solve(input);
try day18.solve(input);
}