-
-
Save ndbn/a2eb9d1059147a10722470b24858d9bf to your computer and use it in GitHub Desktop.
AoC 2024 Day 15
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const std = @import("std"); | |
const input_file_name = "inputs/15.txt"; | |
const input_data = blk: { | |
@setEvalBranchQuota(300_000); | |
var result: []const []const u8 = &.{}; | |
const input_file = @embedFile(input_file_name); | |
var token = std.mem.splitSequence(u8, input_file, "\r\n"); | |
while (token.next()) |val| { | |
result = result ++ [1][]const u8{val}; | |
} | |
break :blk result; | |
}; | |
const rows = input_data.len; | |
const cols = input_data[0].len; | |
// | |
const divider = blk: { | |
@setEvalBranchQuota(300_000); | |
for (input_data, 0..) |data, i| { | |
if (data.len == 0) break :blk i; | |
} | |
unreachable; | |
}; | |
const MOVES = input_data[divider + 1 ..]; | |
const MOVES_ROWS = MOVES.len; | |
const MOVES_COLS = MOVES[0].len; | |
const Vec2 = struct { | |
r: isize, | |
c: isize, | |
pub fn add(self: Vec2, drdc: [2]i8) Vec2 { | |
return .{ | |
.r = self.r + drdc[0], | |
.c = self.c + drdc[1], | |
}; | |
} | |
pub fn left(self: Vec2) Vec2 { | |
return .{ | |
.r = self.r, | |
.c = self.c - 1, | |
}; | |
} | |
pub fn right(self: Vec2) Vec2 { | |
return .{ | |
.r = self.r, | |
.c = self.c + 1, | |
}; | |
} | |
}; | |
const Move = [2]i8; | |
fn charToMove(c: u8) Move { | |
return switch (c) { | |
'>' => .{ 0, 1 }, | |
'<' => .{ 0, -1 }, | |
'^' => .{ -1, 0 }, | |
'v' => .{ 1, 0 }, | |
else => unreachable, | |
}; | |
} | |
fn writeMap(map: anytype, pos: Vec2, c: u8) void { | |
map[@intCast(pos.r)][@intCast(pos.c)] = c; | |
} | |
fn readMap(map: anytype, pos: Vec2) u8 { | |
return map[@intCast(pos.r)][@intCast(pos.c)]; | |
} | |
fn ptrMap(map: anytype, pos: Vec2) *u8 { | |
return &map[@intCast(pos.r)][@intCast(pos.c)]; | |
} | |
fn swapByteMap(map: anytype, pos1: Vec2, pos2: Vec2) void { | |
std.mem.swap(u8, ptrMap(map, pos1), ptrMap(map, pos2)); | |
} | |
fn part1() !isize { | |
var result: isize = 0; | |
result = 0; | |
// | |
var MAP: [divider][cols]u8 = undefined; | |
for (input_data[0..divider], 0..) |line, i| { | |
MAP[i] = line[0..cols].*; | |
} | |
const START: Vec2 = blk2: { | |
for (0..MAP.len) |r| { | |
for (0..MAP[r].len) |c| { | |
if (MAP[r][c] == '@') { | |
break :blk2 .{ .r = @intCast(r), .c = @intCast(c) }; | |
} | |
} | |
} | |
unreachable; | |
}; | |
var robot_coord: Vec2 = START; | |
for (0..MOVES_ROWS) |mr| { | |
for (0..MOVES_COLS) |mc| { | |
// read move instruction | |
const dmove: [2]i8 = charToMove(MOVES[mr][mc]); | |
// Calc next coordinates | |
const next_coord = robot_coord.add(dmove); | |
// MAP char at new | |
const b = readMap(MAP, next_coord); | |
if (b == '.') { | |
// move robot | |
swapByteMap(&MAP, robot_coord, next_coord); | |
robot_coord = next_coord; | |
} else if (b == '#') { | |
// nothing to do, it's a wall | |
} else if (b == 'O') { | |
var times: u32 = 0; | |
var slide_coord = next_coord; | |
while (readMap(MAP, slide_coord) == 'O') { | |
times += 1; | |
slide_coord = slide_coord.add(dmove); | |
} | |
const what_after_boxes = readMap(MAP, slide_coord); | |
if (what_after_boxes == '.') { | |
// can move package of boxes | |
const reversed_dmove = .{ dmove[0] * -1, dmove[1] * -1 }; | |
var caret = slide_coord; | |
times += 1; // add 1 for robot moves also | |
while (times > 0) : (times -= 1) { | |
const prev_caret = caret.add(reversed_dmove); | |
swapByteMap(&MAP, caret, prev_caret); | |
caret = prev_caret; //move caret | |
} | |
robot_coord = caret.add(dmove); //new robot coordinates | |
} | |
} | |
} | |
} | |
//print map / calc result | |
for (0..MAP.len) |r| { | |
// std.debug.print("{s}\n", .{MAP[r]}); // print map | |
for (MAP[r], 0..) |b, c| { | |
if (b == 'O') { | |
const r2: u32 = @intCast(r); | |
const c2: u32 = @intCast(c); | |
result += 100 * r2 + c2; | |
} | |
} | |
} | |
return result; | |
} | |
fn part2() !isize { | |
var result: isize = 0; | |
result = 0; | |
// | |
// change map | |
var MAP: [divider][cols * 2]u8 = undefined; | |
for (input_data[0..divider], 0..) |line, i| { | |
for (line[0..cols], 0..) |c, j| { | |
if (c == '#') { | |
MAP[i][2 * j] = '#'; | |
MAP[i][2 * j + 1] = '#'; | |
} else if (c == 'O') { | |
MAP[i][2 * j] = '['; | |
MAP[i][2 * j + 1] = ']'; | |
} else if (c == '.') { | |
MAP[i][2 * j] = '.'; | |
MAP[i][2 * j + 1] = '.'; | |
} else if (c == '@') { | |
MAP[i][2 * j] = '@'; | |
MAP[i][2 * j + 1] = '.'; | |
} | |
} | |
} | |
const START: Vec2 = blk2: { | |
for (0..MAP.len) |r| { | |
for (0..MAP[r].len) |c| { | |
if (MAP[r][c] == '@') { | |
break :blk2 .{ .r = @intCast(r), .c = @intCast(c) }; | |
} | |
} | |
} | |
unreachable; | |
}; | |
var robot_coord: Vec2 = START; | |
for (0..MOVES_ROWS) |mr| { | |
for (0..MOVES_COLS) |mc| { | |
// Debug | |
// for (0..MAP.len) |r| { | |
// std.debug.print("{c}: {s}\n", .{ MOVES[mr][mc], MAP[r] }); // print map | |
// } | |
// while (true) { | |
// const stdin = std.io.getStdIn().reader(); | |
// const b = try stdin.readByte(); | |
// if (b == '\n') break; | |
// } | |
// read move instruction | |
const dmove: [2]i8 = charToMove(MOVES[mr][mc]); | |
// Calc next coordinates | |
const next_coord = robot_coord.add(dmove); | |
// MAP char at new | |
const b = readMap(&MAP, next_coord); | |
if (b == '.') { | |
// move robot | |
swapByteMap(&MAP, robot_coord, next_coord); | |
robot_coord = next_coord; | |
} else if (b == '#') { | |
// nothing to do, it's a wall | |
} else if (b == '[' or b == ']') { | |
if (dmove[0] == 0) { // left or right - stright line, work same as part1 | |
var times: u32 = 0; | |
var slide_coord = next_coord; | |
while (true) { | |
const c = readMap(&MAP, slide_coord); | |
if (!(c == ']' or c == '[')) break; | |
times += 1; | |
slide_coord = slide_coord.add(dmove); | |
} | |
const what_after_boxes = readMap(&MAP, slide_coord); | |
if (what_after_boxes == '.') { | |
// can move package of boxes | |
const reversed_dmove = .{ dmove[0] * -1, dmove[1] * -1 }; | |
var caret = slide_coord; | |
times += 1; // add 1 for robot moves also | |
while (times > 0) : (times -= 1) { | |
const prev_caret = caret.add(reversed_dmove); | |
swapByteMap(&MAP, caret, prev_caret); | |
caret = prev_caret; //move caret | |
} | |
robot_coord = caret.add(dmove); //new robot coordinates | |
} | |
} else { | |
// up and down moves | |
const MapType = @TypeOf(MAP); | |
const check_map = struct { | |
pub fn check_map_fn(map: *MapType, pos: Vec2, dir: [2]i8) bool { | |
const c = readMap(map, pos); | |
if (c == '.') return true; | |
if (c == '#') return false; | |
if (c == '[') return check_map_fn(map, pos.right().add(dir), dir) and check_map_fn(map, pos.add(dir), dir); | |
if (c == ']') return check_map_fn(map, pos.left().add(dir), dir) and check_map_fn(map, pos.add(dir), dir); | |
if (c == '@') return false; | |
// std.debug.print("unreachable {c}\n", .{c}); | |
unreachable; | |
} | |
}.check_map_fn; | |
const move_map = struct { | |
pub fn move_map_fn(map: *MapType, pos: Vec2, dir: [2]i8, second_part: bool) bool { | |
const c = readMap(map, pos); | |
if (c == '.') { | |
const reversed_dir = .{ dir[0] * -1, dir[1] * -1 }; | |
const prev_pos = pos.add(reversed_dir); | |
swapByteMap(map, pos, prev_pos); | |
return true; | |
} | |
if (c == '#') return false; | |
if (c == '[') return move_map_fn(map, pos.add(dir), dir, second_part) and move_map_fn(map, pos.right(), dir, second_part); | |
if (c == ']') return move_map_fn(map, pos.add(dir), dir, second_part) and move_map_fn(map, pos.left(), dir, second_part); | |
unreachable; | |
} | |
}.move_map_fn; | |
const next_map_coord = robot_coord.add(dmove); | |
if (check_map(&MAP, next_map_coord, dmove)) { | |
_ = move_map(&MAP, next_map_coord, dmove, false); | |
robot_coord = robot_coord.add(dmove); | |
} | |
} | |
} | |
} | |
} | |
//print map / calc result | |
for (0..MAP.len) |r| { | |
// std.debug.print("{s}\n", .{MAP[r]}); // print map | |
for (MAP[r], 0..) |b, c| { | |
if (b == '[') { | |
const r2: u32 = @intCast(r); | |
const c2: u32 = @intCast(c); | |
result += 100 * r2 + c2; | |
} | |
} | |
} | |
return result; | |
} | |
pub fn main() !void { | |
var timer = try std.time.Timer.start(); | |
const part1_result = try part1(); | |
std.debug.print("part 1 {d} {d}ms\n", .{ part1_result, timer.lap() / std.time.ns_per_ms }); | |
const part2_result = try part2(); | |
std.debug.print("part 2 {d} {d}ms\n", .{ part2_result, timer.lap() / std.time.ns_per_ms }); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment