--[[ 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