4s to run part 2. But still happy with it.
parent
9ffad3b1b4
commit
8ea740f029
@ -0,0 +1,254 @@
|
||||
const std = @import("std");
|
||||
|
||||
const Dir = enum(usize) { up, right, down, left };
|
||||
const Coord = struct { row: usize, col: usize };
|
||||
const Beam = struct { dir: Dir, coord: Coord };
|
||||
|
||||
pub fn main() !void {
|
||||
var content = @embedFile("data.txt");
|
||||
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
var grid = std.ArrayList(std.ArrayList(u8)).init(allocator);
|
||||
defer grid.deinit();
|
||||
|
||||
var lines = std.mem.split(u8, content, "\n");
|
||||
|
||||
while (lines.next()) |line| {
|
||||
if (line.len < 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
var lineArrayList = std.ArrayList(u8).init(allocator);
|
||||
|
||||
for (line) |char| {
|
||||
try lineArrayList.append(char);
|
||||
}
|
||||
|
||||
try grid.append(lineArrayList);
|
||||
}
|
||||
|
||||
const energy = try energize(Beam{ .dir = Dir.right, .coord = Coord{ .row = 0, .col = 0 } }, grid);
|
||||
|
||||
std.debug.print("Part 1: {d}\n", .{energy});
|
||||
|
||||
const height = grid.items.len;
|
||||
const width = grid.items[0].items.len;
|
||||
|
||||
var maxEnergy: usize = 0;
|
||||
|
||||
for (0..height) |row| {
|
||||
for ([_]usize{ 0, width - 1 }) |col| {
|
||||
const dir = if (col == 0) Dir.right else Dir.left;
|
||||
const start = Beam{ .dir = dir, .coord = Coord{ .row = row, .col = col } };
|
||||
const e = try energize(start, grid);
|
||||
if (e > maxEnergy) {
|
||||
maxEnergy = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (0..width) |col| {
|
||||
for ([_]usize{ 0, height - 1 }) |row| {
|
||||
const dir = if (row == 0) Dir.down else Dir.up;
|
||||
const start = Beam{ .dir = dir, .coord = Coord{ .row = row, .col = col } };
|
||||
const e = try energize(start, grid);
|
||||
if (e > maxEnergy) {
|
||||
maxEnergy = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std.debug.print("Part 2: {d}\n", .{maxEnergy});
|
||||
}
|
||||
|
||||
fn energize(start: Beam, grid: std.ArrayList(std.ArrayList(u8))) !usize {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
var beams = std.ArrayList(Beam).init(allocator);
|
||||
defer beams.deinit();
|
||||
|
||||
// add the first beam
|
||||
try beams.append(start);
|
||||
|
||||
var energized = std.AutoHashMap(Coord, void).init(allocator);
|
||||
defer energized.deinit();
|
||||
|
||||
var beamHistory = std.AutoHashMap(Beam, void).init(allocator);
|
||||
defer beamHistory.deinit();
|
||||
|
||||
const height = grid.items.len;
|
||||
const width = grid.items[0].items.len;
|
||||
|
||||
while (true) {
|
||||
// make 2 new lists: beams to add, and beams to remove.
|
||||
// batch these while iterating, and do it all after
|
||||
var beamsToAdd = std.ArrayList(Beam).init(allocator);
|
||||
defer beamsToAdd.deinit();
|
||||
|
||||
var beamsToRemove = std.ArrayList(usize).init(allocator);
|
||||
defer beamsToRemove.deinit();
|
||||
|
||||
if (beams.items.len == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
for ((&beams).items, 0..) |*b, beamNumber| {
|
||||
if (isOutOfGrid(b, grid)) {
|
||||
try beamsToRemove.append(beamNumber);
|
||||
continue;
|
||||
}
|
||||
|
||||
try energized.put(b.coord, {});
|
||||
|
||||
if (beamHistory.contains(b.*)) {
|
||||
try beamsToRemove.append(beamNumber);
|
||||
continue;
|
||||
}
|
||||
|
||||
try beamHistory.put(b.*, {});
|
||||
|
||||
const row = b.coord.row;
|
||||
const col = b.coord.col;
|
||||
|
||||
const value = grid.items[row].items[col];
|
||||
|
||||
const goStraight = value == '.' or (value == '|' and (b.dir == .up or b.dir == .down)) or
|
||||
(value == '-' and (b.dir == .left or b.dir == .right));
|
||||
|
||||
if (goStraight) {
|
||||
switch (b.dir) {
|
||||
.up => if (row == 0) {
|
||||
b.coord.row = height + 10; // put it out of the grid to get cleaned up
|
||||
} else {
|
||||
b.coord.row -= 1;
|
||||
},
|
||||
.right => b.coord.col += 1,
|
||||
.down => b.coord.row += 1,
|
||||
.left => if (col == 0) {
|
||||
b.coord.col = width + 10; // put it out of the grid to get cleaned up
|
||||
} else {
|
||||
b.coord.col -= 1;
|
||||
},
|
||||
}
|
||||
} else if (value == '|') {
|
||||
if (row == 0) {
|
||||
// if we are on the top row, change the beam to go down
|
||||
b.dir = Dir.down;
|
||||
b.coord.row += 1;
|
||||
} else {
|
||||
// otherwise, change beam direction to up and move it up one cell
|
||||
b.dir = Dir.up;
|
||||
b.coord.row -= 1;
|
||||
if (row != height - 1) {
|
||||
// and if we're not on the _bottom_ row,
|
||||
// create a new beam going down, below this cell
|
||||
const newBeam = Beam{ .dir = Dir.down, .coord = Coord{ .row = row + 1, .col = col } };
|
||||
try beamsToAdd.append(newBeam);
|
||||
}
|
||||
}
|
||||
} else if (value == '-') {
|
||||
if (col == 0) {
|
||||
// if we are on the first col, change the beam to go right
|
||||
b.dir = Dir.right;
|
||||
b.coord.col += 1;
|
||||
} else {
|
||||
// otherwise, change beam direction to left and move it left one cell
|
||||
b.dir = Dir.left;
|
||||
b.coord.col -= 1;
|
||||
if (col != width - 1) {
|
||||
// and if we're not on the _last_ column,
|
||||
// create a new beam going right, to the right this cell
|
||||
const newBeam = Beam{ .dir = Dir.right, .coord = Coord{ .row = row, .col = col + 1 } };
|
||||
try beamsToAdd.append(newBeam);
|
||||
}
|
||||
}
|
||||
} else if (value == '/') {
|
||||
switch (b.dir) {
|
||||
.up => {
|
||||
b.dir = Dir.right;
|
||||
b.coord.col += 1;
|
||||
},
|
||||
.right => if (row == 0) {
|
||||
b.coord.row = height + 10; // put it out of the grid to get cleaned up
|
||||
} else {
|
||||
b.dir = Dir.up;
|
||||
b.coord.row -= 1;
|
||||
},
|
||||
.down => if (col == 0) {
|
||||
b.coord.row = height + 10; // put it out of the grid to get cleaned up
|
||||
} else {
|
||||
b.dir = Dir.left;
|
||||
b.coord.col -= 1;
|
||||
},
|
||||
.left => {
|
||||
b.dir = Dir.down;
|
||||
b.coord.row += 1;
|
||||
},
|
||||
}
|
||||
} else if (value == '\\') {
|
||||
switch (b.dir) {
|
||||
.up => if (col == 0) {
|
||||
b.coord.col = width + 10; // put it out of the grid to get cleaned up
|
||||
} else {
|
||||
b.dir = Dir.left;
|
||||
b.coord.col -= 1;
|
||||
},
|
||||
.right => {
|
||||
b.dir = Dir.down;
|
||||
b.coord.row += 1;
|
||||
},
|
||||
.down => {
|
||||
b.dir = Dir.right;
|
||||
b.coord.col += 1;
|
||||
},
|
||||
.left => if (row == 0) {
|
||||
b.coord.row = height + 10; // put it out of the grid to get cleaned up
|
||||
} else {
|
||||
b.dir = Dir.up;
|
||||
b.coord.row -= 1;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove the beams in reverse order
|
||||
const len = beamsToRemove.items.len;
|
||||
for (0..len) |j| {
|
||||
const idx = beamsToRemove.items[len - j - 1];
|
||||
_ = beams.orderedRemove(idx);
|
||||
}
|
||||
beamsToRemove.clearAndFree();
|
||||
|
||||
// add the new beams
|
||||
for (beamsToAdd.items) |beam| {
|
||||
try beams.append(beam);
|
||||
}
|
||||
beamsToAdd.clearAndFree();
|
||||
}
|
||||
|
||||
return energized.count();
|
||||
}
|
||||
|
||||
fn isOutOfGrid(beam: *Beam, grid: std.ArrayList(std.ArrayList(u8))) bool {
|
||||
const row = beam.coord.row;
|
||||
const col = beam.coord.col;
|
||||
const height = grid.items.len;
|
||||
const width = grid.items[0].items.len;
|
||||
return row < 0 or row >= height or col < 0 or col >= width;
|
||||
}
|
||||
|
||||
fn printGrid(grid: std.ArrayList(std.ArrayList(u8)), energized: std.AutoHashMap(Coord, void)) void {
|
||||
for (grid.items, 0..) |line, row| {
|
||||
for (line.items, 0..) |char, col| {
|
||||
if (char == '.' and energized.contains(Coord{ .row = row, .col = col })) {
|
||||
std.debug.print("#", .{});
|
||||
} else {
|
||||
std.debug.print("{c}", .{char});
|
||||
}
|
||||
}
|
||||
std.debug.print("\n", .{});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue