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

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

register('day6', function(myrequire) -- DAY 6 -- local lpegrex = myrequire('llpeg.lpegrex')

-- PARSING -- local patt = lpegrex.compile( (Number SKIP)* |} Number <-- %d+ -> tonumber nl <-- %nl SKIP <-- [ ]* NAME_SUFFIX <-- [_%w]+ )

function parse(source) --print(inspect(source)) local ast, errlabel, pos = patt:match(source) if not ast then local lineno, colno, line = lpegrex.calcline(source, pos) local colhelp = string.rep(' ', colno-1)..'^' error('syntax error: '..lineno..':'..colno..': '..errlabel..           '\n'..line..'\n'..colhelp) end --print('Parsed with success!') --print(inspect(ast)) -- post process local games = {} for i,time in ipairs(ast.times) do     local dist = ast.distances[i] table.insert(games, { time = time, dist = dist }) end return games end

function one_game(race) local t,d = race.time,race.dist -- solve quadratic formula local discrim = (t*t) - 4*d if d < 0 then return 0 end -- no way to win the race discrim = math.sqrt(discrim) local min = math.ceil((t - discrim) / 2) local max = math.floor((t + discrim) / 2) -- tricky corner case: we can't tie the record we must win it  if ((race.time - min) * min) <= race.dist then min = min + 1 -- bump it up  end if ((race.time - max) * max) <= race.dist then max = max - 1 -- bump it down end -- print("min", min, "max", max) assert(min > 0 and max < race.time) if min <= max then return (max - min) + 1 end return 0 end

function all_ways(source) local races = parse(source) local prod = 1 for i,r in ipairs(races) do     local ways = one_game(r) --print("Race", i, "Time", r.time, "Dist", r.dist, "Ways", ways) prod = prod * ways end return prod end

function part1(source) return all_ways(source) end

function part2(source) -- remove all spaces! source = string.gsub(source, ' ', '') source = string.gsub(source, ':', ': ') return all_ways(source) end

-- CLI start ] ]-- local source = io.input("day6.input"):read("a") print(part1(source)) print(part2(source)) --[ [ CLI end --

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('day6') end)