return (functionlocal builders = local function register(name, f) builders[name] = fendregister('llpeg.lpegrex', function return require end)
register('llpeg', function return require end)
register('day7', function(myrequire)--DAY 7 --local lpegrex = myrequire('llpeg.lpegrex')local l = myrequire('llpeg')
--PARSING --local patt = lpegrex.compile(nl* HandBid (nl+ HandBid)* nl* |}HandBid <--
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 astend
--PART 1 --
local JOKER = 1 -- must be lower than the "2"
local card_value = local Kind =
local split_patt = l.Ct((l.P(1) / card_value)^5)function split(hand) -- split hand into cards, map each to value return split_patt:match(hand)end
function kind1(hand) -- count duplicates local count = local max = 0 for _,v in ipairs(hand) do count[v] = (count[v] or 0) + 1 max = math.max(max, count[v]) end if max
4 then return Kind.FourOfAKind end -- count pairs local pairCount = 0 for _,cnt in pairs(count) do if cnt
3 then if pairCount
2 then return Kind.TwoPair end if pairCount
function compare_hands(a, b) if a.kind ~= b.kind then return a.kind < b.kind end -- sort by first card, then second, etc. for i=1,5 do if a.split[i] ~= b.split[i] then return a.split[i] < b.split[i] end end --print(inspect(a), inspect(b)) --error("duplicate hands") return falseend
function winnings(source, compute_kind_func) local hands = parse(source) --print(inspect(hands)) -- compute the kind for every hand for _,h in ipairs(hands) do h.split = split(h.hand) h.kind = compute_kind_func(h.split) end -- sort the hands table.sort(hands, compare_hands) -- sum the winnings! local sum = 0 for rank,h in ipairs(hands) do -- print(rank,h.hand,h.bid,h.kind) sum = sum + rank * h.bid end return sumend
--Part 2 --function kind2(hand) -- count duplicates local count = local max = 0 for _,v in ipairs(hand) do count[v] = (count[v] or 0) + 1 max = math.max(max, count[v]) end local jokers = count[JOKER] or 0 if max
4 then if jokers > 0 then return Kind.FiveOfAKind end return Kind.FourOfAKind end -- count pairs local pairCount = 0 for _,cnt in pairs(count) do if cnt
3 then if jokers
1 then return Kind.FiveOfAKind end -- option 2: three jokers, two non matching cards return Kind.FourOfAKind elseif jokers
1 then -- option 4: three cards, 1 card, 1 joker return Kind.FourOfAKind elseif pairCount
2 then if jokers
1 then -- one joker, two pair return Kind.FullHouse else return Kind.TwoPair end elseif pairCount
function part1(source) return winnings(source, kind1) -- part 1end
function part2(source) source = source:gsub("J","j") -- jokers! return winnings(source, kind2)end
--CLI start ]--local source = io.input("day7.input"):read("a")print(part1(source))print(part2(source))--[[ CLI end ]]--
return
end)
local modules = modules['table'] = require('table')modules['string'] = require('string')modules['strict'] = local function myrequire(name) if modules[name]