165 lines
3.4 KiB
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
|