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

165 lines
3.4 KiB
Lua

--[[
io.input("test")
local targetRow = 10
local maxx, maxy = 20, 20
--]]
--[
io.input("input")
local targetRow = 2000000
local maxx, maxy = 4000000, 4000000
--]]
function abs(x)
return (x>=0) and x or -x
end
function distance(x1, y1, x2, y2)
return abs(x1-x2) + abs(y1-y2)
end
function inRange( x, y, row, targetD )
local startD = abs(row-y)
local dif = targetD - startD
if dif<0 then return nil
else return x-dif, x+dif
end
end
local count = 0
local positions = {}
local beacons = {} -- beacons in row
local data = {}
for line in io.lines() do
local nums = {}
for match in string.gmatch(line, "(-?%d+)") do
table.insert( nums, tonumber(match) )
end
local sx, sy, bx, by = table.unpack(nums)
local d = distance(sx, sy, bx, by)
local r1, r2 = inRange(sx, sy, targetRow, d)
-- print(sx, sy, bx, by, d)
if r1 then
for c = r1,r2 do
positions[c] = true
end
end
if by == targetRow then
beacons[bx] = true
end
-- for part 2
table.insert(data, {sx, sy, bx, by, d})
end
local result1 = 0
local min, max = math.maxinteger, math.mininteger
for x,v in pairs(positions) do
-- print(x, v)
if not beacons[x] then
result1 = result1 + 1
end
end
print("part 1", result1)
-- part 2
function join( r1, r2 )
local mini = (r1.i < r2.i ) and r1.i or r2.i
local maxf = (r1.f > r2.f ) and r1.f or r2.f
if r2.i <= r1.f+1 and r1.i<=r2.i or r1.i <= r2.f+1 and r2.i <= r1.i then
return { i = mini, f = maxf }
else
return r1, r2
end
end
--[[
function cleanUp( ranges )
local i = 2
repeat
local r1, r2 = join( ranges[i], ranges[i-1] )
if not r2 then
ranges[i-1] = r1 -- joined range
table.remove( ranges, i )
else -- don't intersect, try again
i = i + 1
end
until i > #ranges
end
--]]
local found = false
local minx, miny = 0, 0
local beaconX, beaconY
for y = miny, maxy do
if y%500000==0 then print("#"..tostring(y)) end
-- print("#"..tostring(y))
local ranges = {}
local beacons = {} -- beacons in row
for _, t in ipairs(data) do
local sx, sy, bx, by, d = table.unpack(t)
local ri, rf = inRange(sx, sy, y, d)
if ri then
ri = (ri > minx) and ri or minx
rf = (rf < maxx) and rf or maxx
local range = { i=ri, f=rf }
if #ranges == 0 then
table.insert( ranges, range )
else
local i = 1
repeat
local done
local r1, r2 = join( ranges[i], range )
if not r2 then
ranges[i] = r1 -- joined range
done = true
else -- don't intersect, try again
i = i + 1
-- unless there are no more
if i > #ranges then
ranges[i] = range
done = true
end
end
until done
end
end
end
if #ranges > 1 then
-- clean up
local i = 2
repeat
local r1, r2 = join( ranges[i], ranges[i-1] )
if not r2 then
ranges[i-1] = r1 -- joined range
table.remove( ranges, i )
else -- don't intersect, try again
i = i + 1
end
until i > #ranges
end
-- if there are still two ranges, here's the answer
if #ranges > 1 then
local r1, r2 = ranges[1], ranges[2]
local minf = (r1.f>r2.f) and r2.f or r1.f
beaconX = minf+1
beaconY = y
end
if beaconX then break end
end
local result2 = beaconX*4000000 + beaconY
print("part 2", result2)
print(beaconX, beaconY)
-- part 2 12518502636475
-- 3129625 2636475