Jump to content

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

From Wikipedia, the free encyclopedia
return (function()
local builders = {}
local function register(name, f)
  builders[name] = f
end
register('advent.compat', function() return require [[Module:User:Cscott/compat]] end)

register('day1', function(myrequire)
--[[
   Day 1, first part; advent of code 2023
]]--

local compat = myrequire('advent.compat')

--[[
   Infrastructure
]]--

function split(str)
   lines = {}
   for s in string.gmatch(str, "[^\r\n]+") do
      table.insert(lines, s)
   end
   return lines
end

function part1(frame)
   local s = mw.title.new(frame.args[1]):getContent()
   return day1a(split(s))
end

function part2(frame)
   local s = mw.title.new(frame.args[1]):getContent()
   return day1b(split(s))
end

--[[
   Part 1
]]--

function day1a(lines)
   local sum = 0
   for _,line in pairs(lines) do
      -- ignore everything but numbers
      local nums = string.gsub(line, "[^0-9]", "")
      -- ignore everything but the first and the last
      nums = string.sub(nums, 1, 1) .. string.sub(nums, -1, -1)
      -- coerce to integer
      n = 0 + nums
      sum = sum + n
      -- io.write(n, "\n")
   end
   -- io.write("Sum: ", sum, "\n")
   return sum
end

--[[
Part 2!
]]--

local digits = { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }

function findDigit(str)
   for d = 1, #digits do
      local word = digits[d]
      -- io.write("checking ",word,"\n")
      if string.sub(str, 1, #word) == word then
         return d, #word
      end
   end
   -- is the first character a digit?
   if string.match(str, "^[0-9]") then
      return (0 + string.sub(str, 1, 1)), 1
   else
      return 0, 0
   end
end

function day1b(lines)
   local sum = 0
   for _,line in pairs(lines) do
      local first
      local last
      -- find first digit
      i = 1
      while i <= #line do
         local piece = string.sub(line, i)
         d, len = findDigit(piece)
         if len > 0 then
            first = d
            break
         else
            -- ignore this character
            i = i + 1
         end
      end
      -- find last digit
      i = #line
      while i >= 1 do
         local piece = string.sub(line, i)
         d, len = findDigit(piece)
         if len > 0 then
            last = d
            break
         else
            -- ignore this character
            i = i - 1
         end
      end
      -- ignore everything but the first and the last digit
      local n = (10*first) + last
      -- io.write(line, " -> ", n, "\n")
      sum = sum + n
   end
   return sum
end

--[[
   Testing
]]--

-- io.write("Sum: ", day1a(io.lines(compat.unpack(arg))), "\n")
-- io.write("Sum: ", day1a(split(io.input("day1.example"):read("a"))), "\n")

-- io.write("Sum: ", day1b(split(io.input("day1b.example"):read("a"))), "\n")

return {
   part1 = part1,
   part2 = part2,
}

end)

local modules = {}
modules['bit32'] = require('bit32')
modules['string'] = require('string')
modules['strict'] = {}
modules['table'] = require('table')
local function myrequire(name)
  if modules[name] == nil then
    modules[name] = true
    modules[name] = (builders[name])(myrequire)
  end
  return modules[name]
end
return myrequire('day1')
end)()