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.

  1. 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:
  2. 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.
  3. 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.
  4. 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.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.