From 04b4afc87e9a08ff8cd54cdcbbc968339fbc33a0 Mon Sep 17 00:00:00 2001 From: John Costa Date: Mon, 18 Dec 2023 23:20:12 +0000 Subject: [PATCH] Day 18, lets go! --- AdventOfCode2023/src/day16/day16.zig | 239 +++++++++++++++++++++++++++ AdventOfCode2023/src/day18/day18.zig | 159 ++++++++++++++++++ AdventOfCode2023/src/main.zig | 8 +- 3 files changed, 403 insertions(+), 3 deletions(-) create mode 100644 AdventOfCode2023/src/day16/day16.zig create mode 100644 AdventOfCode2023/src/day18/day18.zig diff --git a/AdventOfCode2023/src/day16/day16.zig b/AdventOfCode2023/src/day16/day16.zig new file mode 100644 index 0000000..c77603e --- /dev/null +++ b/AdventOfCode2023/src/day16/day16.zig @@ -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 = ∈ + 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 diff --git a/AdventOfCode2023/src/day18/day18.zig b/AdventOfCode2023/src/day18/day18.zig new file mode 100644 index 0000000..4d7d06b --- /dev/null +++ b/AdventOfCode2023/src/day18/day18.zig @@ -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}); +} diff --git a/AdventOfCode2023/src/main.zig b/AdventOfCode2023/src/main.zig index 6ed165b..44429f8 100644 --- a/AdventOfCode2023/src/main.zig +++ b/AdventOfCode2023/src/main.zig @@ -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); }