24_hail.py 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. #!/usr/bin/env python3
  2. import sys
  3. import re
  4. from itertools import combinations
  5. def intersect2d(path1, path2, low, high):
  6. # https://stackoverflow.com/questions/563198
  7. x1, y1, _, dx1, dy1, _ = path1
  8. x2, y2, _, dx2, dy2, _ = path2
  9. rs = dx1 * dy2 - dy1 * dx2
  10. if rs:
  11. t = ((x2 - x1) * dy2 - (y2 - y1) * dx2) / rs
  12. u = ((x2 - x1) * dy1 - (y2 - y1) * dx1) / rs
  13. if t >= 0 and u >= 0:
  14. x = x1 + t * dx1
  15. y = y1 + t * dy1
  16. return low <= x <= high and low <= y <= high
  17. return False
  18. def cross(u, v):
  19. a, b, c = u
  20. d, e, f = v
  21. return (b * f - c * e), (c * d - a * f), (a * e - b * d)
  22. def dot(u, v):
  23. return sum(a * b for a, b in zip(u, v))
  24. def add(u, v):
  25. return tuple(a + b for a, b in zip(u, v))
  26. def sub(u, v):
  27. return add(u, mul(-1, v))
  28. def mul(scalar, v):
  29. return tuple(scalar * x for x in v)
  30. def intersect_all(paths):
  31. # take 3 hailstones and use one as the origin for the other two:
  32. (q0, u0), (q1, u1), (q2, u2) = ((x[:3], x[3:]) for x in paths[:3])
  33. p1 = sub(q1, q0)
  34. p2 = sub(q2, q0)
  35. v1 = sub(u1, u0)
  36. v2 = sub(u2, u0)
  37. # now there exist some t1 and t2 such that p1+t1v1 and p2+t2v2 are
  38. # collinear, meaning their cross-product is zero:
  39. # 0 = p1+t1v1 x p2+t2v2
  40. # = p1 x p2 + p1 x t2v2 + t1v1 x p2 + t1v1 x t2v2
  41. # = p1 x p2 + t2(p1 x v2) + t1(v1 x p2) + t1t2(v1 x v2)
  42. # given that (a x b)*a = (a x b)*b = 0, take dot product with v2 to get t1:
  43. # 0 = v2*(p1 x p2) + t1v2*(v1 x p2)
  44. # t1 = v2*(p2 x p1) / v2*(v1 x p2)
  45. # take dot product with v1 to get t2:
  46. # 0 = v1*(p1 x p2) + t2v1*(p1 x v2)
  47. # t2 = v1*(p2 x p1) / v1*(p1 x v2)
  48. t1 = dot(v2, cross(p2, p1)) / dot(v2, cross(v1, p2))
  49. t2 = dot(v1, cross(p2, p1)) / dot(v1, cross(p1, v2))
  50. # use intersection times to compute intersection coordinates:
  51. intersect1 = add(q1, mul(t1, u1))
  52. intersect2 = add(q2, mul(t2, u2))
  53. # draw a line back through the intersection coordinates to get the origin:
  54. velocity = mul(1 / (t2 - t1), sub(intersect2, intersect1))
  55. origin = sub(intersect1, mul(t1, velocity))
  56. return int(sum(origin))
  57. paths = [tuple(map(int, re.findall(r'-?\d+', line))) for line in sys.stdin]
  58. print(sum(intersect2d(a, b, 2e14, 4e14) for a, b in combinations(paths, 2)))
  59. print(intersect_all(paths))