Module:User:Cscott/Advent Of Code 2023/Day 16 Explained

return (functionlocal builders = local function register(name, f) builders[name] = fendregister('llpeg', function return require end)

register('day16', function(myrequire)--DAY 16 --local l = myrequire('llpeg')

--PARSING --local Spot = Spot.__index = Spotfunction Spot:new(args) return setmetatable(args, self)endfunction Spot:is_mirror return self.char

'/' or self.char

'\\' endfunction Spot:is_splitter return self.char

'-' or self.char

'|' endfunction Spot:is_empty return self.char

'.' endfunction Spot:__tostring return self.charend

local nl = l.P"\n"

function make_spot(s) return Spot:newend

local patt = l.P

local Graph = Graph.__index = Graph

function parse(source) --print(inspect(source)) local ast, errlabel, pos = patt:match(source) if not ast then error(string.format("Error at pos %s label '%s'", pos, errlabel)) end --print('Parsed with success!') --print(inspect(ast)) return Graph:new(ast)end

--Part 1 --

function Graph:new(data) return setmetatable(self)end

function Graph:at(row,col,default) return (self.data[row] or)[col] or defaultend

function Graph:rowN return #(self.data)end

function Graph:colN return #(self.data[1])end

function Graph:print for r,row in ipairs(self.data) do for c,val in ipairs(row) do if val

nil then val = " " elseif val.energized then val = "#" end io.write(tostring(val)) end io.write("\n") endend

function Graph:link for r=1,self:rowN do for c=1,self:colN do local sp = self:at(r,c) sp.r, sp.c = r,c if r > 1 then sp.n = self:at(r-1,c) end if c > 1 then sp.w = self:at(r,c-1) end if r < self:rowN then sp.s = self:at(r+1,c) end if c < self:colN then sp.e = self:at(r,c+1) end end endend

function Graph:clearAndScore local sum = 0 for r=1,self:rowN do for c=1,self:colN do local sp = self:at(r,c) if sp.energized then sum = sum + 1 sp.energized = nil sp.seen_n = nil sp.seen_e = nil sp.seen_w = nil sp.seen_s = nil end end end return sumend

local mirror_effect =

function ray_cast(sp, dir) if sp['seen_'..dir] ~= nil then return end sp.energized = true sp['seen_'..dir] = true local ndir = mirror_effect[sp.char][dir] if #ndir

1 then local nsp = sp[ndir] if nsp ~= nil then return ray_cast(nsp, ndir) -- tail call end else for i=1,#ndir do local nsp = sp[ndir:sub(i,i)] if nsp ~= nil then ray_cast(nsp, ndir:sub(i,i)) end end endend

function part1(source) local graph = parse(source) graph:link --graph:print --print ray_cast(graph:at(1,1),"e") --graph:print return graph:clearAndScoreend

function part2(source) local graph = parse(source) graph:link local max = 0 local function check(r,c,dir) ray_cast(graph:at(r,c),dir) local score = graph:clearAndScore if score > max then max = score end end for r=1,graph:rowN do check(r,1,"e") check(r,graph:colN,"w") end for c=1,graph:colN do check(1,c,"s") check(graph:rowN,c,"n") end return maxend

--CLI ]--local source = io.input("day16.input"):read("a")print('Sum:', part1(source))print('Sum:', part2(source))--[[ END CLI ]]--

return

end)

local modules = modules['table'] = require('table')modules['string'] = require('string')modules['strict'] = local function myrequire(name) if modules[name]