Module:User:Cscott/Advent Of Code 2023/Day 13

return (function local builders = {} local function register(name, f) builders[name] = f end register('llpeg', function return require Module:User:Cscott/llpeg end)

register('day13', function(myrequire) -- DAY 13 -- local l = myrequire('llpeg')

-- PARSING -- local Node = {} Node.__index = Node function Node:new(args) return setmetatable(args, self) end function Node:__tostring if self.rock then return "#" end return "." end

local nl = l.P"\n"

function make_node(s) if s == "#" then return Node:new{rock=true} end return Node:new{ash=true} end

local Map = {} Map.__index = Map

function Map:nRows return #(self.data) end

function Map:nCols return #(self.data[1]) end

function Map:__tostring local result = {} for r,row in ipairs(self.data) do     for c,node in ipairs(row) do         table.insert(result, tostring(node)) end table.insert(result, "\n") end return table.concat(result) end

function Map:try_vertical_mirror(col, smudges) -- # of columns to its left local s = 0 for r,row in ipairs(self.data) do     local i = 0 repeat local col1,col2 = col-i,col+1+i if row[col1].ash ~= row[col2].ash then s = s + 1 if s > smudges then return false end -- early return end i = i + 1 until col1 == 1 or col2 == #row end return (s == smudges) end

function Map:try_horizontal_mirror(row, smudges) -- # of columns to its left local s = 0 for c = 1,self:nCols do     local i = 0 repeat local row1,row2 = row-i,row+1+i if self.data[row1][c].ash ~= self.data[row2][c].ash then s = s + 1 if s > smudges then return false end -- early return end i = i + 1 until row1 == 1 or row2 == #(self.data) end return (s == smudges) end

function Map:score(smudges) for i=1,self:nRows-1 do     if self:try_horizontal_mirror(i, smudges) then return 100*i end end for i=1,self:nCols-1 do     if self:try_vertical_mirror(i, smudges) then return i     end end error("no axis of reflection found") end

function make_map(g) return setmetatable({ data=g }, Map) end

local patt = l.P{  "MapList", MapList = l.Ct( l.V"Map" * (nl * nl * l.V"Map")^0 * nl^0) * -1, Map = l.Ct( l.V"Row" * (nl * l.V"Row")^0 ) / make_map, Row = l.Ct( l.V"Node"^1 ), Node = l.S"#." / make_node, }

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) return ast end

-- part 1 --

function part1(source) local maps = parse(source) local sum = 0 for i=1,#maps do     local score = maps[i]:score(0) --print(maps[i]) --print(score) --print sum = sum + score end return sum end

-- part 2 --

function part2(source) local maps = parse(source) local sum = 0 for i=1,#maps do     local score = maps[i]:score(1) --print(maps[i]) --print(score) --print sum = sum + score end return sum end

-- CLI local source = io.input("day13.input"):read("a") --print(inspect(parse(source))) print('Part 1 Sum:', part1(source)) print('Part 2 Sum:', part2(source)) --

return { part1 = function(frame) local s = mw.title.new(frame.args[1]):getContent return part1(s) end, part2 = function(frame) local s = mw.title.new(frame.args[1]):getContent return part2(s, tonumber(frame.args[2])) end, }

end)

local modules = {} modules['table'] = require('table') modules['string'] = require('string') modules['strict'] = {} local function myrequire(name) if modules[name] == nil then modules[name] = true modules[name] = (builders[name])(myrequire) end return modules[name] end return myrequire('day13') end)