rocks = {} pos_y = 0 for line in io.lines(arg[1]) do pos_x = 0 for char in line:gmatch(".") do if char == "#" then table.insert(rocks, {y=pos_y, x=pos_x}) end pos_x = pos_x + 1 end pos_y = pos_y + 1 end pos_y = nil pos_x = nil max = nil for _, rock in ipairs(rocks) do count = 0 angles_array = {} angles = {} for _, in_rock in ipairs(rocks) do if rock ~= in_rock then angle = math.atan(in_rock.y - rock.y, in_rock.x - rock.x) + math.pi / 2 if angle < 0 then angle = angle + math.pi * 2 end if angles[angle] == nil then angles[angle] = {in_rock} table.insert(angles_array, angle) count = count + 1 else table.insert(angles[angle], in_rock) end end end if not max or max.count < count then max = {count=count, rock=rock, angles=angles, angles_array=angles_array} end end print(string.format("Part 1: %d (%d,%d)", max.count, max.rock.x, max.rock.y)) table.sort(max.angles_array) for _, angle in ipairs(max.angles_array) do table.sort(max.angles[angle], function(x, y) local dist_x = math.sqrt((x.x - max.rock.x) ^ 2 + (x.y - max.rock.y) ^ 2) local dist_y = math.sqrt((y.x - max.rock.x) ^ 2 + (y.y - max.rock.y) ^ 2) return dist_x < dist_y end) end shot = 0 while true do for _, angle in ipairs(max.angles_array) do if #max.angles[angle] > 0 then shot = shot + 1 if shot >= 200 then rock = max.angles[angle][#max.angles[angle]] print(string.format("Part 2: %d", rock.x * 100 + rock.y)) os.exit(true) end max.angles[angle][#max.angles[angle]] = nil end end end