return (functionlocal builders = local function register(name, f) builders[name] = fendregister('llpeg', function return require end)
register('advent.compat', function return require end)
register('day10', function(myrequire)--DAY 10 --local l = myrequire('llpeg')local compat = myrequire('advent.compat')
--PARSING --local Tile = Tile.__index = Tilefunction Tile:new(args) return setmetatable(args, self)endfunction Tile:p return l.P(self.c) * l.Cc(self)endfunction Tile:__tostring return self.cend
local NS = Tile:newlocal EW = Tile:newlocal NE = Tile:newlocal NW = Tile:newlocal SW = Tile:newlocal SE = Tile:newlocal GND = Tile:newlocal START = Tile:new
local nl = l.P"\n"
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:set(row,col,val) if self.data
nil then self.data[row] = end self.data[row][col] = valend
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
function Graph:find_start for r,row in ipairs(self.data) do for c,val in ipairs(row) do if val.start then return r,c end end end error("start not found")end
function Graph:fix_start local row,col = self:find_start local start = self:at(row,col) if self:at(row-1, col,).s then start.n = true end if self:at(row+1, col,).n then start.s = true end if self:at(row, col-1,).e then start.w = true end if self:at(row, col+1,).w then start.e = true end return row,colend
function flood_fill(graph) local r,c = graph:fix_start local fill = Graph:new fill:set(r,c,0) local todo = table.insert(todo,) table.insert(todo,) local i=0 local maxfill = 0 while i < #todo do i = i + 1 local r,c = compat.unpack(todo[i]) local tile = graph:at(r,c) local fillval = fill:at(r,c) local nr,nc --print("fillval",fillval,"at",r,c) --print(inspect(tile)) if tile.n and fill:at(r-1, c)
nil then nr,nc = r+1,c elseif tile.e and fill:at(r,c+1)
nil then nr,nc = r,c-1 else return maxfill,fill -- no more to fill! end fill:set(nr,nc,fillval+1) table.insert(todo,) maxfill = math.max(maxfill, fillval+1) endend
function part1(source) local graph = parse(source) --graph:print local ans,_ = flood_fill(graph) return ansend
--Part 2 --
function compute_inner(g, fill, nrows, ncols) local inner = false local sum = 0 for r=1,nrows do inner = false for c=1,ncols do local is_loop = (fill:at(r,c) ~= nil) if is_loop then -- we shoot infintesimally south of the midpoint, such that -- these count as crossing: |7F (south is true) -- and these do not: -LJ (south is false) if g:at(r,c).s then inner = not inner end elseif inner then -- print(r,c) sum = sum + 1 end end end return sumend
function part2(source) local graph = parse(source) --graph:print local _,fill = flood_fill(graph) local ans = compute_inner(graph, fill, graph:rowN, graph:colN) return ansend
----
return
end)
local modules = modules['table'] = require('table')modules['string'] = require('string')modules['strict'] = local function myrequire(name) if modules[name]