diff options
| -rw-r--r-- | makefile | 3 | ||||
| -rw-r--r-- | src/day24.cpp | 131 | ||||
| -rw-r--r-- | src/day24.py | 33 |
3 files changed, 166 insertions, 1 deletions
| @@ -22,7 +22,8 @@ all: bin/day01 \ | |||
| 22 | bin/day20 \ | 22 | bin/day20 \ |
| 23 | bin/day21 \ | 23 | bin/day21 \ |
| 24 | bin/day22 \ | 24 | bin/day22 \ |
| 25 | bin/day23 | 25 | bin/day23 \ |
| 26 | bin/day24 | ||
| 26 | 27 | ||
| 27 | bin: | 28 | bin: |
| 28 | mkdir $@ | 29 | mkdir $@ |
diff --git a/src/day24.cpp b/src/day24.cpp new file mode 100644 index 0000000..296d38a --- /dev/null +++ b/src/day24.cpp | |||
| @@ -0,0 +1,131 @@ | |||
| 1 | #include <cstdlib> | ||
| 2 | #include <fstream> | ||
| 3 | #include <iostream> | ||
| 4 | #include <limits> | ||
| 5 | #include <string> | ||
| 6 | #include <tuple> | ||
| 7 | #include <vector> | ||
| 8 | using namespace std; | ||
| 9 | |||
| 10 | using line_type = tuple<double, double, double, double, double, double>; | ||
| 11 | using point_type = tuple<double, double>; | ||
| 12 | using puzzle_type = vector<line_type>; | ||
| 13 | |||
| 14 | template<typename T> | ||
| 15 | int | ||
| 16 | sgn(T val) | ||
| 17 | { | ||
| 18 | return (T(0) < val) - (val < T(0)); | ||
| 19 | } | ||
| 20 | |||
| 21 | puzzle_type | ||
| 22 | read_file(string_view filename) | ||
| 23 | { | ||
| 24 | fstream input{ filename }; | ||
| 25 | puzzle_type result; | ||
| 26 | |||
| 27 | for ( string line; getline(input, line); ) { | ||
| 28 | const auto NFIELDS = 6; | ||
| 29 | |||
| 30 | double x, y, z, dx, dy, dz; // NOLINT | ||
| 31 | |||
| 32 | if ( sscanf(line.data(), "%lf, %lf, %lf @ %lf, %lf, %lf", &x, &y, &z, &dx, &dy, &dz) != NFIELDS ) { | ||
| 33 | continue; | ||
| 34 | } | ||
| 35 | |||
| 36 | result.emplace_back(make_tuple(x, y, z, dx, dy, dz)); | ||
| 37 | } | ||
| 38 | |||
| 39 | return result; | ||
| 40 | } | ||
| 41 | |||
| 42 | point_type | ||
| 43 | get_direction(line_type line) | ||
| 44 | { | ||
| 45 | const auto [x, y, z, dx, dy, dz] = line; | ||
| 46 | |||
| 47 | return make_tuple(sgn(dx), sgn(dy)); | ||
| 48 | } | ||
| 49 | |||
| 50 | point_type | ||
| 51 | get_direction(line_type from, point_type to) | ||
| 52 | { | ||
| 53 | const auto [x, y, z, dx, dy, dz] = from; | ||
| 54 | const auto [to_x, to_y] = to; | ||
| 55 | |||
| 56 | return make_tuple(sgn(to_x - x), sgn(to_y - y)); | ||
| 57 | } | ||
| 58 | |||
| 59 | bool | ||
| 60 | lint(line_type stone_a, line_type stone_b, point_type& cross_point) | ||
| 61 | { | ||
| 62 | const auto p_1 = make_tuple(get<0>(stone_a), get<1>(stone_a)); | ||
| 63 | const auto p_2 = make_tuple(get<0>(stone_a) + get<3>(stone_a), get<1>(stone_a) + get<4>(stone_a)); | ||
| 64 | |||
| 65 | const auto p_3 = make_tuple(get<0>(stone_b), get<1>(stone_b)); | ||
| 66 | const auto p_4 = make_tuple(get<0>(stone_b) + get<3>(stone_b), get<1>(stone_b) + get<4>(stone_b)); | ||
| 67 | |||
| 68 | const auto a_1 = get<1>(p_2) - get<1>(p_1); | ||
| 69 | const auto b_1 = get<0>(p_1) - get<0>(p_2); | ||
| 70 | const auto c_1 = a_1 * (get<0>(p_1)) + b_1 * (get<1>(p_1)); | ||
| 71 | |||
| 72 | const auto a_2 = get<1>(p_4) - get<1>(p_3); | ||
| 73 | const auto b_2 = get<0>(p_3) - get<0>(p_4); | ||
| 74 | const auto c_2 = a_2 * (get<0>(p_3)) + b_2 * (get<1>(p_3)); | ||
| 75 | |||
| 76 | const auto determinant = a_1 * b_2 - a_2 * b_1; | ||
| 77 | |||
| 78 | if ( determinant == 0 ) { | ||
| 79 | return false; | ||
| 80 | } | ||
| 81 | |||
| 82 | auto p_x = (b_2 * c_1 - b_1 * c_2) / determinant; | ||
| 83 | auto p_y = (a_1 * c_2 - a_2 * c_1) / determinant; | ||
| 84 | |||
| 85 | cross_point = make_tuple(p_x, p_y); | ||
| 86 | |||
| 87 | return true; | ||
| 88 | } | ||
| 89 | |||
| 90 | void | ||
| 91 | part1(const puzzle_type& input) | ||
| 92 | { | ||
| 93 | const auto in_range = [](point_type point) -> bool { | ||
| 94 | static const auto lower_limit = 200000000000000.0; | ||
| 95 | static const auto upper_limit = 400000000000000.0; | ||
| 96 | |||
| 97 | const auto [x, y] = point; | ||
| 98 | |||
| 99 | return x > lower_limit && x < upper_limit && y > lower_limit && y < upper_limit; | ||
| 100 | }; | ||
| 101 | |||
| 102 | const auto in_future = [](line_type stone, point_type point) -> bool { | ||
| 103 | const auto sgn_stone = get_direction(stone); | ||
| 104 | const auto sgn_point = get_direction(stone, point); | ||
| 105 | |||
| 106 | return sgn_stone == sgn_point; | ||
| 107 | }; | ||
| 108 | |||
| 109 | long sum = 0; | ||
| 110 | for ( size_t idx = 0; idx != input.size(); ++idx ) { | ||
| 111 | const auto& stone_a = input[idx]; | ||
| 112 | |||
| 113 | for ( size_t idx2 = idx + 1; idx2 < input.size(); ++idx2 ) { | ||
| 114 | const auto& stone_b = input[idx2]; | ||
| 115 | |||
| 116 | point_type cross_point; | ||
| 117 | if ( lint(stone_a, stone_b, cross_point) && in_range(cross_point) && in_future(stone_a, cross_point) && in_future(stone_b, cross_point) ) { | ||
| 118 | ++sum; | ||
| 119 | } | ||
| 120 | } | ||
| 121 | } | ||
| 122 | cout << sum << endl; | ||
| 123 | } | ||
| 124 | |||
| 125 | int | ||
| 126 | main() | ||
| 127 | { | ||
| 128 | const auto input = read_file("data/day24.txt"); | ||
| 129 | |||
| 130 | part1(input); | ||
| 131 | } | ||
diff --git a/src/day24.py b/src/day24.py new file mode 100644 index 0000000..809f2d0 --- /dev/null +++ b/src/day24.py | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | class Hailstone: | ||
| 2 | def __init__(self, sx, sy, sz, vx, vy, vz): | ||
| 3 | self.sx = sx | ||
| 4 | self.sy = sy | ||
| 5 | self.sz = sz | ||
| 6 | self.vx = vx | ||
| 7 | self.vy = vy | ||
| 8 | self.vz = vz | ||
| 9 | |||
| 10 | self.a = vy | ||
| 11 | self.b = -vx | ||
| 12 | self.c = vy * sx - vx * sy | ||
| 13 | |||
| 14 | def __repr__(self): | ||
| 15 | return "Hailstone{" + f"a={self.a}, b={self.b}, c={self.c}" + "}" | ||
| 16 | |||
| 17 | hailstones = [Hailstone(*map(int, line.replace("@", ",").split(","))) for line in open("data/day24.txt")] | ||
| 18 | |||
| 19 | total = 0 | ||
| 20 | |||
| 21 | for i, hs1 in enumerate(hailstones): | ||
| 22 | for hs2 in hailstones[:i]: | ||
| 23 | a1, b1, c1 = hs1.a, hs1.b, hs1.c | ||
| 24 | a2, b2, c2 = hs2.a, hs2.b, hs2.c | ||
| 25 | if a1 * b2 == b1 * a2: | ||
| 26 | continue | ||
| 27 | x = (c1 * b2 - c2 * b1) / (a1 * b2 - a2 * b1) | ||
| 28 | y = (c2 * a1 - c1 * a2) / (a1 * b2 - a2 * b1) | ||
| 29 | if 200000000000000 <= x <= 400000000000000 and 200000000000000 <= y <= 400000000000000: | ||
| 30 | if all((x - hs.sx) * hs.vx >= 0 and (y - hs.sy) * hs.vy >= 0 for hs in (hs1, hs2)): | ||
| 31 | total += 1 | ||
| 32 | |||
| 33 | print(total) | ||
