advent-of-code/12022/17/17.lua

190 lines
4.0 KiB
Lua

--io.input("test")
io.input("input")
--
--local target = 2022 -- part 1
local target = 1000000000000 -- part 2
local shapes = {
{ w = 4, h = 1, map = { {1, 1, 1, 1} } },
{ w = 3, h = 3, map = { {0, 1, 0}, {1, 1, 1}, {0, 1, 0} } },
{ w = 3, h = 3, map = { {1, 1, 1}, {0, 0, 1}, {0, 0, 1} } },
{ w = 1, h = 4, map = { {1}, {1}, {1}, {1} } },
{ w = 2, h = 2, map = { {1, 1}, {1, 1} } },
}
local f = io.read("a")
local jets = {}
for j in string.gmatch(f,"[<>]") do
table.insert( jets, j)
end
function emptiness()
return {0, 0, 0, 0, 0, 0, 0}
end
local tunnel = {}
function tunnel:print()
for i = #self, 1, -1 do
local s = ""
local row = self[i]
for _, c in ipairs(row) do
s = s .. (c == 1 and "@" or ( c==2 and "#" or "."))
end
print(s)
end
end
function tunnel:drawShape( shape, shX, shY, color)
local tunnel = self
local color = color or 1
for ly = 1, shape.h do
local y = ly + shY - 1
tunnel[y] = tunnel[y] or emptiness()
for lx = 1, shape.w do
local x = lx + shX - 1
tunnel[y][x] = shape.map[ly][lx]==1 and color or tunnel[y][x]
end
end
end
function tunnel:clearShape( shape, shX, shY )
self:drawShape( shape, shX, shY, 0 )
end
function equals( t1, t2 )
for i = 1, #t1 do
if t1[i] ~= t2[i] then return false end
end
return true
end
local shI = 1
local jeI = 1
local erasedRows = 0
local iFound, iPeriod
local i = 1
while i <= target do
local shape = shapes[shI]
local x = 3 -- left
local y = #tunnel + 4 -- bottom
for i = 1, 3 do
table.insert( tunnel, emptiness() )
end
repeat -- moving loop
tunnel:drawShape( shape, x, y )
-- jet
local jet = jets[jeI]
local inc = jet=="<" and -1 or 1
local canMove = false
if (inc == -1 and x > 1 ) or ( inc == 1 and x + shape.w - 1 < 7) then
canMove = true
for lx = 1, shape.w do
local shX = lx + x - 1
for ly = 1, shape.h do
local shY = ly + y - 1
if tunnel[shY][shX+inc] == 2 and shape.map[ly][lx]==1 then
canMove = false
end
end
end
end
if canMove then
tunnel:clearShape( shape, x, y )
x = x + inc
tunnel:drawShape( shape, x, y )
end
jeI = (jeI == #jets) and 1 or (jeI + 1)
-- down
canMove = (y > 1)
if canMove then
for lx = 1, shape.w do
local shX = lx + x - 1
for ly = 1, shape.h do
local shY = ly + y - 1
if tunnel[shY-1][shX] == 2 and shape.map[ly][lx]==1 then
canMove = false
break
end
end
if not canMove then break end
end
end
if canMove then
tunnel:clearShape( shape, x, y )
y = y - 1
tunnel:drawShape( shape, x, y )
end
until not canMove
-- stopped shape
tunnel:drawShape( shape, x, y, 2)
-- clean tunnel
repeat
local emptyRow = true
local ind = #tunnel
for _, c in ipairs( tunnel[ind] ) do
if c > 0 then
emptyRow = false
break
end
end
if emptyRow then
table.remove( tunnel )
end
until not emptyRow or #tunnel == 0
-- check for repetition
local period
for size = 10, #tunnel/2 do
local equal = true
for j = 1, size do
local tail = tunnel[ #tunnel - j + 1 ]
local tail2 = tunnel[ #tunnel - size - j + 1 ]
if not equals(tail, tail2) then
equal = false
break
end
end
if equal then
period = size
for i = 1,period do
table.remove(tunnel)
end
erasedRows = erasedRows + period
if not iFound then
iFound = i
elseif not iPeriod then
iPeriod = i - iFound
-- jump ahead!
local remaining = target - i
local advance = remaining // iPeriod
local outOfIPeriod = remaining % iPeriod
erasedRows = erasedRows + advance*period
i = target - outOfIPeriod
end
-- print(i, iFound, period, iPeriod, #tunnel )
break
end
end
shI = (shI == #shapes) and 1 or (shI + 1)
i = i + 1
end
print("result ", #tunnel + erasedRows)