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

158 lines
3.2 KiB
Lua

io.input("test")
--io.input("input")
function p2s( x, y )
return string.format("%d,%d", x, y)
end
function s2p( s )
local x, y = string.match(s,"(-?%d+),(-?%d+)")
x = tonumber(x)
y = tonumber(y)
return x, y
end
function neighbors(x, y)
local n = {}
n.NW = p2s( x-1, y-1)
n.N = p2s( x, y-1)
n.NE = p2s( x+1, y-1)
n.E = p2s( x+1, y )
n.SE = p2s(x+1, y+1)
n.S = p2s(x, y+1)
n.SW = p2s(x-1, y+1)
n.W = p2s(x-1, y)
return n
end
local max = {y=0, x=0}
local min = {y=10000, x=10000}
function updateMaxMin( j, i )
if j>max.x then max.x = j
elseif j<min.x then min.x = j end
if i>max.y then max.y = i
elseif i<min.y then min.y = i end
end
local nelves = 0
local elves = {}
-- parse map
local i = 1
for line in io.lines() do
local j = 1
for c in string.gmatch(line, "%g") do
if c=="#" then
elves[ p2s(j,i) ] = true
updateMaxMin(j, i)
nelves = nelves + 1
end
j = j + 1
end
i = i + 1
end
local dirs = {"N", "S", "W", "E"}
local offdirs = 0
local round = 1
local result1
repeat
-- first half
local attempts = {}
for s, e in pairs(elves) do
local x, y = s2p(s)
local alone = true
local n = neighbors(x,y)
for k, ns in pairs(n) do
if elves[ns] then alone = false break end
end
if alone then goto continue end
for i=0,3 do
local idirs = (i+offdirs)%4 + 1
local dir = dirs[idirs]
if dir=="N" and not (elves[n.NW] or elves[n.N] or elves[n.NE]) then
--print("propose north")
if attempts[n.N] == nil then
attempts[n.N] = s
elseif attempts[n.N] then -- attempt
attempts[n.N] = false
end
break
elseif dir=="S" and not (elves[n.SW] or elves[n.S] or elves[n.SE]) then
--print("propose south")
if attempts[n.S] == nil then
attempts[n.S] = s
elseif attempts[n.S] then -- attempt
attempts[n.S] = false
end
break
elseif dir=="W" and not (elves[n.SW] or elves[n.W] or elves[n.NW]) then
--print("propose west")
if attempts[n.W] == nil then
attempts[n.W] = s
elseif attempts[n.W] then -- attempt
attempts[n.W] = false
end
break
elseif dir=="E" and not (elves[n.SE] or elves[n.E] or elves[n.NE]) then
-- print("propose east")
if attempts[n.E] == nil then
attempts[n.E] = s
elseif attempts[n.E] then -- attempt
attempts[n.E] = false
end
break
end
end
::continue::
end
--second half
local count = 0
for k, s in pairs(attempts) do
if s then
elves[s] = nil
elves[k] = true
local nx, ny = s2p(k)
updateMaxMin(nx, ny)
count = count + 1
end
end
--[[
print("moved:",count)
print(min.x, min.y, max.x, max.y)
--]]
offdirs = (offdirs==3) and 0 or (offdirs+1)
if round%100==0 then
print("round", round)
end
if round == 10 then
result1 = (max.y-min.y+1)*(max.x-min.x+1)-nelves
end
if count > 0 then
round = round + 1
end
until count == 0
print("part 1", result1)
print("part 2", round)
-- print map:
for y=min.y,max.y do
local m = ""
for x=min.x,max.x do
local s = p2s(x,y)
m = m .. (elves[s] and "#" or ".")
end
-- print(m)
end