Skip to content

Commit

Permalink
Day 6, Part 1
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeladler committed Dec 6, 2024
1 parent a56ddc3 commit cc88617
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 0 deletions.
107 changes: 107 additions & 0 deletions src/day06/day06.lua
Original file line number Diff line number Diff line change
@@ -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
20 changes: 20 additions & 0 deletions src/day06/day06_spec.lua
Original file line number Diff line number Diff line change
@@ -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)
8 changes: 8 additions & 0 deletions src/day06/main.lua
Original file line number Diff line number Diff line change
@@ -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))

0 comments on commit cc88617

Please sign in to comment.