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

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)