Day 18, lets go!
This commit is contained in:
239
AdventOfCode2023/src/day16/day16.zig
Normal file
239
AdventOfCode2023/src/day16/day16.zig
Normal file
@ -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
|
159
AdventOfCode2023/src/day18/day18.zig
Normal file
159
AdventOfCode2023/src/day18/day18.zig
Normal file
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user