Module:User:Cscott/Advent Of Code 2023/Day 9
Appearance
return (function()
local builders = {}
local function register(name, f)
builders[name] = f
end
register('llpeg', function() return require [[Module:User:Cscott/llpeg]] end)
register('day9', function(myrequire)
--[[ DAY 9 ]]--
local l = myrequire('llpeg')
-- local inspect = require 'inspect'
--[[ PARSING ]]--
local SKIP = l.P" " ^ 0
local nl = l.P"\n"
function tok(s) return l.P(s) * SKIP end
local patt = l.P{
l.Ct( l.V"NumberLine" * (nl^1 * l.V"NumberLine")^0 * nl^0) * -1,
NumberLine = l.Ct( (l.V"Number" * SKIP) ^ 1 ),
Number = ((l.P"-" ^ -1) * (l.R"09"^1)) / tonumber,
}
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 ast
end
--[[ Part 1 ]]--
function predict_next(seq)
local diffs = {}
local saw_nonzero = false
for i=2,#seq do
local d = (seq[i] - seq[i-1])
table.insert(diffs, d)
if seq[i] ~= 0 then saw_nonzero = true end
end
if saw_nonzero then
table.insert(diffs, predict_next(diffs))
-- now compute the next value
return seq[#seq] + diffs[#diffs]
else
-- easy: the sequence was all zeros so predict a zero!
return 0
end
end
function part1(source)
local lines = parse(source)
local sum = 0
for i=1,#lines do
local seq = lines[i]
local prediction = predict_next(seq)
-- print(inspect(seq), prediction)
sum = sum + prediction
end
return sum
end
--[[ Part 2 ]]--
function predict_prev_and_next(seq)
local diffs = {}
local saw_nonzero = false
for i=2,#seq do
local d = (seq[i] - seq[i-1])
table.insert(diffs, d)
if seq[i] ~= 0 then saw_nonzero = true end
end
if saw_nonzero then
local p, n = predict_prev_and_next(diffs)
-- compute the previous value
local prev = seq[1] - p
-- now compute the next value
local nxt = seq[#seq] + n
return prev,nxt
else
-- easy: the sequence was all zeros so predict a zero (on both sides)!
return 0,0
end
end
function part2(source)
local lines = parse(source)
local sum = 0
for i=1,#lines do
local seq = lines[i]
local p,n = predict_prev_and_next(seq)
-- print(p, inspect(seq), n)
sum = sum + p
end
return sum
end
--[[ CLI:
local source = io.input("day9.input"):read("a")
print("Sum", part1(source))
print("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)
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('day9')
end)()