2025-12-09 06:38:54 +00:00

100 lines
3.0 KiB
Python

from math import dist
def solve(input):
points = []
for line in open(input):
x,y = map(int, line.strip().split(","))
points.append((x,y))
# Part 1:
# find the largest rectangle created by two points
def areas():
for p in points:
for q in points:
if p != q:
yield area(p,q)
# answer 1
print(max(areas()))
# Part 2:
# find the largest rectangle formed by a pair of points
# which is contained within the polygon defined by the list of points.
lines = list(zip(points, points[1:]+[points[0]]))
# keep only vertical lines, and sort so the uppermost point (lowest y coord) is the first of the pair
lines = [(min(p,q),max(p,q)) for p,q in lines if p[1] != q[1]]
# sort lines by y coord
lines.sort(key=lambda l: (l[0][1],l[1][1],l[0][0],l[1][0]))
#print(lines)
# we want to know if the rectangle formed by a pair of points
# is completely contained within an axis-aligned polygon.
#
# we can do that with a pseudo-scanline algorithm.
#
# we make a couple simplifying assumptions:
# 1. first, that the polygon is not self-intersecting
# 2. second, that the polygon is not "U shaped" --
# that is, it has a definite, single width in every horizontal slice
# and it doesn't curve around at all -- so we don't have to worry
# about voids
#
# for each y position, we first calculate the horizontal bounds of the
# polygon at that line.
#
# then, to test if a rectangle is contained within the polygon,
# we just need to iterate through the y positions which fall inside the rectangle
# and check whether the rectangle would exceed the previously computed bounds
# of the polygon at any of those points.
bounds = {}
ys = sorted(set(p[1] for l in lines for p in l))
for y in ys:
# select lines which intersect with the scanline at y
mylines = []
for p,q in lines:
if p[1] <= y <= q[1]:
mylines.append(p[0]) # only keep the x coord
# since we are assuming no self-intersection and no voids,
# the bounds on this line are just the leftmost and rightmost
# x coordinate of the intersecting lines
bounds[y] = (min(mylines),max(mylines))
#print(ys)
#print(bounds)
def inbounds(p,q):
y0 = min(p[1],q[1])
y1 = max(p[1],q[1])
x0 = min(p[0],q[0])
x1 = max(p[0],q[0])
#print(y0, y1, ys)
start = ys.index(y0)
for i in range(start,len(ys)):
y = ys[i]
if y > y1:
break
if not bounds[y][0] <= x0 <= x1 <= bounds[y][1]:
return False
return True
def inbound_areas():
for p in points:
for q in points:
if p != q and inbounds(p,q):
yield area(p,q)
# answer 2
print(max(inbound_areas()))
def area(p,q):
dx = abs(p[0] - q[0]) + 1
dy = abs(p[1] - q[1]) + 1
return dx*dy
solve("sample")
solve("input")