|
1 | 1 | from aoc import *
|
2 |
| -from statistics import median, mode |
3 |
| -from more_itertools import windowed, take, peekable, chunked, first_true, split_when, first_true |
4 |
| -from heapq import * |
5 |
| -# from functools import reduce, cache, cmp_to_key |
6 |
| -from functools import cache |
7 |
| -from math import ceil |
8 |
| -import re |
9 |
| -from blessed import BlessedList |
10 |
| -from copy import deepcopy |
11 |
| -import operator |
12 |
| -from string import ascii_letters, ascii_lowercase, ascii_uppercase, digits, hexdigits, whitespace |
13 |
| -from pprint import pprint as pp |
14 |
| -import bisect |
15 |
| -import math |
16 |
| -from itertools import pairwise, combinations |
17 |
| -import sys |
18 |
| -from collections import defaultdict, OrderedDict, deque, Counter |
19 |
| -# from ordered_set import OrderedSet |
20 |
| -from sympy import * |
21 |
| -from sympy.geometry import * |
| 2 | +from sympy import symbols |
| 3 | +from sympy.solvers.polysys import solve_poly_system |
22 | 4 |
|
23 | 5 |
|
| 6 | +# Geometrical representation: H is a set of lines (more precisely rays, but this |
| 7 | +# doesn't matter in this task) that represent the trajectories of hailstones. We |
| 8 | +# have to find line l (trajectory of our stone) that intersects all lines in H. |
| 9 | +# |
| 10 | +# This can be represented analytically as a system of equations (they aren't |
| 11 | +# linear as there is a multiplication of two unknowns). |
| 12 | +# |
| 13 | +# As line is defined by two points, if we find a unique line that intersects |
| 14 | +# three lines from H, it should also intersect all other lines (considering the |
| 15 | +# input is correct). |
| 16 | +# |
| 17 | +# Many people on r/adventofcode used Z3. I wanted to use a Python solution and |
| 18 | +# since I used sympy for part one, this post was a good inspiration for me: |
| 19 | +# https://www.reddit.com/r/adventofcode/comments/18pnycy/comment/kepmry2/?utm_source=share&utm_medium=web2x&context=3 |
24 | 20 | def main(input_file: str):
|
25 | 21 | inp = lines(input_file)
|
26 | 22 | points = []
|
27 |
| - for l in inp: |
| 23 | + system = [] |
| 24 | + x, y, z, vx, vy, vz = symbols('x y z vx vy vz') |
| 25 | + ts = [] |
| 26 | + # Three lines (points) is enough. It will define the throw line for all |
| 27 | + # other hailstones. |
| 28 | + for i, l in enumerate(inp[:3]): |
28 | 29 | left, right = l.split(' @ ')
|
29 |
| - left = tuple(int(x) for x in left.split(', ')) |
30 |
| - right = tuple(int(x) for x in right.split(', ')) |
| 30 | + left = tuple(int(j) for j in left.split(', ')) |
| 31 | + right = tuple(int(j) for j in right.split(', ')) |
31 | 32 | points.append((left, right))
|
| 33 | + t = symbols(f't{i}') |
| 34 | + ts.append(t) |
| 35 | + system.append(x + vx * t - left[0] - right[0] * t) |
| 36 | + system.append(y + vy * t - left[1] - right[1] * t) |
| 37 | + system.append(z + vz * t - left[2] - right[2] * t) |
32 | 38 |
|
33 |
| - x_min = 200000000000000 |
34 |
| - x_max = 400000000000000 |
35 |
| - # x_min = 7 |
36 |
| - # x_max = 27 |
37 |
| - suma = 0 |
38 |
| - time = [] |
39 |
| - for i in range(1, 4): |
40 |
| - new_points = [] |
41 |
| - for (x, y, z), (a, b, c) in points: |
42 |
| - new_points.append((x+a*i, y+b*i, z+c*i)) |
43 |
| - time.append(new_points) |
44 |
| - for i1, p1 in enumerate(time[0]): |
45 |
| - for i2, p2 in enumerate(time[1]): |
46 |
| - if i2 == i1: |
47 |
| - continue |
48 |
| - for i3, p3 in enumerate(time[2]): |
49 |
| - if i3 in [i1, i2]: |
50 |
| - continue |
51 |
| - q = Point(p1) |
52 |
| - w = Point(p2) |
53 |
| - line = Line(q, w) |
54 |
| - if line.intersection(Point(p3)): |
55 |
| - print(p1, p2, p3) |
| 39 | + return sum(solve_poly_system(system, x, y, z, vx, vy, vz, *ts)[0][:3]) |
56 | 40 |
|
57 |
| - # for ((x, y, z), (a, b, c)), ((i, j, k), (d, e, f)) in combinations(points, 2): |
58 |
| - # q = Point(x, y) |
59 |
| - # w = Point(x + a, y + b) |
60 |
| - # # w = Point(a, b) |
61 |
| - # l1 = Line(q, w) |
62 |
| - # l1 = Ray(q, w) |
63 |
| - # r = Point(i, j) |
64 |
| - # t = Point(i + d, j + e) |
65 |
| - # # t = Point(d, e) |
66 |
| - # l2 = Line(r, t) |
67 |
| - # l2 = Ray(r, t) |
68 |
| - # inter = intersection(l1, l2) |
69 |
| - # if inter: |
70 |
| - # if x_min <= inter[0][0] <= x_max and x_min <= inter[0][1] <= x_max: |
71 |
| - # suma += 1 |
72 |
| - # # print(f'{((x, y, z), (a, b, c)), ((i, j, k), (d, e, f))}: will cross at {inter}') |
73 |
| - return |
74 | 41 |
|
75 | 42 | DAY = 24
|
76 | 43 | FILE_TEST = f"{DAY}_test.txt"
|
77 | 44 | FILE_EXP = f"{DAY}_expa.txt"
|
78 | 45 | FILE = f"{DAY}.txt"
|
79 | 46 | # test_and_submit(main, FILE_TEST, FILE_EXP, FILE, DAY)
|
80 |
| -# print(main(FILE_TEST)) |
| 47 | +print(main(FILE_TEST)) |
81 | 48 | print(main(FILE))
|
0 commit comments