From cc88617e851687f5f22b7cd9fef54a33eedf1b5a Mon Sep 17 00:00:00 2001 From: Michael Adler Date: Fri, 6 Dec 2024 07:35:15 +0100 Subject: [PATCH] Day 6, Part 1 --- src/day06/day06.lua | 107 +++++++++++++++++++++++++++++++++++++++ src/day06/day06_spec.lua | 20 ++++++++ src/day06/main.lua | 8 +++ 3 files changed, 135 insertions(+) create mode 100644 src/day06/day06.lua create mode 100644 src/day06/day06_spec.lua create mode 100755 src/day06/main.lua diff --git a/src/day06/day06.lua b/src/day06/day06.lua new file mode 100644 index 0000000..b82f736 --- /dev/null +++ b/src/day06/day06.lua @@ -0,0 +1,107 @@ +-- Author: Michael Adler +local M = {} + +local Direction = { + NORTH = 1, + EAST = 2, + SOUTH = 3, + WEST = 4, +} + +local function rotate_right(dir) + if dir == Direction.NORTH then + return Direction.EAST + elseif dir == Direction.EAST then + return Direction.SOUTH + elseif dir == Direction.SOUTH then + return Direction.WEST + elseif dir == Direction.WEST then + return Direction.NORTH + end +end + +local function hash(x, y) + return string.format("%d,%d", x, y) +end + +-- The table keeps track of the number of unique keys added to it. +local function create_smart_table() + local count = 0 + return setmetatable({}, { + __index = function(t, k) + return rawget(t, k) + end, + __newindex = function(t, k, v) + if rawget(t, k) == nil then + count = (count or 0) + 1 + end + rawset(t, k, v) + end, + __len = function(_) + return count + end, + }) +end + +--- @param input string +M.solve = function(input) + local map = {} + + local y, x -- current position + local row_count = 0 + for line in input:gmatch("[^\r\n]+") do + row_count = row_count + 1 + local n = string.len(line) + local row = {} + for i = 1, n do + local c = string.sub(line, i, i) + if c == "^" then + y = row_count + x = i + end + table.insert(row, c) + end + table.insert(map, row) + end + local col_count = #map[1] + + local visited = create_smart_table() + local dir = Direction.NORTH + while true do + -- mark current position as visited + visited[hash(x, y)] = true + -- try advance + local new_x, new_y + if dir == Direction.NORTH then + new_y, new_x = y - 1, x + elseif dir == Direction.EAST then + new_x, new_y = x + 1, y + elseif dir == Direction.SOUTH then + new_y, new_x = y + 1, x + elseif dir == Direction.WEST then + new_x, new_y = x - 1, y + end + + -- is OOB? + if new_y < 1 or new_x < 1 or new_y > row_count or new_x > col_count then + break + end + + -- is obstacle? + local c = map[new_y][new_x] + if c == "#" then + -- go back and rotate + new_y, new_x = y, x + dir = rotate_right(dir) + end + y, x = new_y, new_x + end + + -- in Lua >= 5.2, we could call #visited + local part1 = getmetatable(visited).__len() + local part2 = 0 + + return part1, part2 +end + +return M diff --git a/src/day06/day06_spec.lua b/src/day06/day06_spec.lua new file mode 100644 index 0000000..d81a603 --- /dev/null +++ b/src/day06/day06_spec.lua @@ -0,0 +1,20 @@ +local day06 = require("day06") + +describe("day06", function() + it("solves the example", function() + local input = [[....#..... +.........# +.......... +..#....... +.......#.. +.......... +.#..^..... +........#. +#......... +......#... +]] + local part1, part2 = day06.solve(input) + assert.are.equal(41, part1) + assert.are.equal(0, part2) + end) +end) diff --git a/src/day06/main.lua b/src/day06/main.lua new file mode 100755 index 0000000..307a5b1 --- /dev/null +++ b/src/day06/main.lua @@ -0,0 +1,8 @@ +#!/usr/bin/env luajit +local day06 = require("day06") +local fname = arg[1] or "input.txt" +local f = assert(io.open(fname, "r"), fname .. " missing") +local input = f:read("*a") +f:close() +local part1, part2 = day06.solve(input) +print(string.format("Part 1: %d\nPart 2: %d", part1, part2))