17.py 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. from util import get_input
  2. from itertools import product
  3. from more_itertools import flatten
  4. from math import sqrt, ceil, floor
  5. input = get_input("17.input")
  6. stuff = input[0].split()
  7. tx = [int(a) for a in stuff[2][2:-1].split("..")]
  8. ty = [int(a) for a in stuff[3][2:].split("..")]
  9. def hits(velx, tx, ty):
  10. # High school math comes in handy once again...
  11. #x = velx + velx - 1 + velx - 2 + velx - 3 = velx * steps - steps (steps - 1) / 2 = (velx + 1/2) * steps - steps^2 / 2
  12. # 2 x = (2 velx + 1) steps - steps^2
  13. # 2x - (2 velx + 1) steps + steps^2 = 0
  14. try:
  15. minsteps = ceil((2 * velx + 1) / 2 - sqrt(pow((2 * velx + 1) / 2, 2) - 2 * tx[0]))
  16. except ValueError:
  17. # Equation has no solution;
  18. # projectile never reaches area
  19. return []
  20. try:
  21. maxsteps = floor((2 * velx + 1) / 2 - sqrt(pow((2 * velx + 1) / 2, 2) - 2 * tx[1]))
  22. except ValueError:
  23. # Projectile x-velocity reaches 0
  24. # while above the target area
  25. maxsteps = minsteps + 1000
  26. res = []
  27. for nstep in range(minsteps, maxsteps + 1):
  28. #y = vely * nstep - nstep * (nstep - 1) / 2
  29. #vely * nstep = nstep * (nstep - 1) / 2 + y
  30. #vely = (nstep * (nstep - 1) / 2 + y) / nstep
  31. minvely = ceil((nstep * (nstep - 1) / 2 + ty[0]) / nstep)
  32. maxvely = floor((nstep * (nstep - 1) / 2 + ty[1]) / nstep)
  33. for vely in range(minvely, maxvely + 1):
  34. res.append((velx, vely))
  35. return list(set(res))
  36. # This is slow garbage, leaving it here so you can laugh at me
  37. def naive_hits(vel, tx, ty):
  38. topy = 0
  39. pos = (0, 0)
  40. startvel = vel
  41. while True:
  42. if pos[0] >= tx[0] and pos[0] <= tx[1]:
  43. if pos[1] >= ty[0] and pos[1] <= ty[1]:
  44. return (topy, startvel)
  45. if pos[1] < ty[0]:
  46. return (-1000, startvel)
  47. if pos[0] > tx[1]:
  48. return (-1000, startvel)
  49. if vel[0] == 0:
  50. dx = 0
  51. elif vel[0] < 0:
  52. dx = 1
  53. else:
  54. dx = -1
  55. pos = (pos[0] + vel[0], pos[1] + vel[1])
  56. vel = (vel[0] + dx, vel[1] - 1)
  57. topy = max(pos[1], topy)
  58. hits = list(flatten([hits(x, tx, ty) for x in range(0, 70)]))
  59. # Find highest point on parabola using initial y-velocity
  60. maxvely = max([h[1] for h in hits])
  61. # D(vely * t - (t ^ 2) / 2) == 0
  62. # vely - t == 0
  63. t = maxvely
  64. maxy = int(t * t - t * (t - 1) / 2)
  65. print("Part 1:", maxy)
  66. # This is easy now lol
  67. print("Part 2:", len(hits))