Module:User:Cscott/Advent Of Code 2023/Day 4
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('day4', function(myrequire)
--[[ DAY 4 ]]--
local lpegrex = myrequire('llpeg.lpegrex')
--[[ PARSING ]]--
local patt = lpegrex.compile([[
Lines <-- {| nl* Card (nl+ Card)* nl* |}
Card <== `Card` {:id: Number :} `:` {:winning: NumberList :} SKIP `|` {:have: NumberList :} SKIP
NumberList <-- {| (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))
return ast
end
--[[ PART 1 ]]--
function winning_numbers(card)
-- in place sort
table.sort(card.have)
table.sort(card.winning)
local my_winning = {}
local i,j = 1,1
while i <= #card.have and j <= #card.winning do
if card.have[i] == card.winning[j] then
table.insert(my_winning, card.have[i])
i = i + 1
elseif card.have[i] < card.winning[j] then
i = i + 1
else
j = j + 1
end
end
--print(card.id, inspect(my_winning))
return my_winning
end
function score_card(card)
local w = winning_numbers(card)
if #w == 0 then return 0 end
local score = 1
for i=2,#w do
score = score * 2
end
return score
end
function sum_points(source)
local cards = parse(source)
local sum = 0
for _,v in pairs(cards) do
sum = sum + score_card(v)
end
return sum
end
--[[ PART 2 ]]--
function naive(source)
local cards = parse(source)
-- preprocess the winning numbers & create initial to-do list
local winning = {}
local todo = {}
for _,v in pairs(cards) do
local id = v.id
table.insert(todo, id)
winning[id] = {}
local next_id = id + 1
for _,_ in pairs(winning_numbers(v)) do
table.insert(winning[id], next_id)
next_id = next_id + 1
end
end
-- okay, naively take stuff off the to-do list and process it.
local i = 1
while i <= #todo do
local id = todo[i]
print("Looking at", id)
for _,v in pairs(winning[id]) do
table.insert(todo, v)
end
i = i + 1
end
--print(inspect(todo))
return #todo
end
function smarter(source)
local cards = parse(source)
-- preprocess the winning numbers & create initial to-do list
local winning = {}
local copies = {}
for _,v in pairs(cards) do
copies[v.id] = 1
end
-- process in order
for _,v in pairs(cards) do
local id = v.id
local next_id = id + 1
for _,_ in pairs(winning_numbers(v)) do -- ignore the actual values
copies[next_id] = copies[next_id] + copies[id]
next_id = next_id + 1
end
end
-- okay, sum up all the copies
--print(inspect(copies))
local sum = 0
for _,v in pairs(copies) do
sum = sum + v
end
return sum
end
--[[ CLI start ] ]--
local source = io.input("day4.input"):read("a")
print("Sum:", sum_points(source))
print("Total:", smarter(source))
--[ [ CLI end ]]--
return {
part1 = function(frame)
local s = mw.title.new(frame.args[1]):getContent()
return sum_points(s)
end,
part2 = function(frame)
local s = mw.title.new(frame.args[1]):getContent()
return smarter(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('day4')
end)()
Content Disclaimer
Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.
- The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
- There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
- It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
- Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
- Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.