From 56e890cec0a28c0a485212ccebfaf774235a79a2 Mon Sep 17 00:00:00 2001 From: Thomas Schmucker Date: Wed, 3 Jan 2024 23:35:54 +0100 Subject: prepare for more puzzles ... :) --- 2023/src/day24.cpp | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 2023/src/day24.cpp (limited to '2023/src/day24.cpp') diff --git a/2023/src/day24.cpp b/2023/src/day24.cpp new file mode 100644 index 0000000..76f459b --- /dev/null +++ b/2023/src/day24.cpp @@ -0,0 +1,173 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +using line_type = tuple; +using point_type = tuple; +using puzzle_type = vector; + +template +int +sgn(T val) +{ + return (T(0) < val) - (val < T(0)); +} + +puzzle_type +read_file(string_view filename) +{ + fstream input{ filename }; + puzzle_type result; + + for ( string line; getline(input, line); ) { + const auto NFIELDS = 6; + + double x, y, z, dx, dy, dz; // NOLINT + + if ( sscanf(line.data(), "%lf, %lf, %lf @ %lf, %lf, %lf", &x, &y, &z, &dx, &dy, &dz) != NFIELDS ) { + continue; + } + + result.emplace_back(make_tuple(x, y, z, dx, dy, dz)); + } + + return result; +} + +point_type +get_direction(line_type line) +{ + const auto [x, y, z, dx, dy, dz] = line; + + return make_tuple(sgn(dx), sgn(dy)); +} + +point_type +get_direction(line_type from, point_type to) +{ + const auto [x, y, z, dx, dy, dz] = from; + const auto [to_x, to_y] = to; + + return make_tuple(sgn(to_x - x), sgn(to_y - y)); +} + +bool +lint(line_type stone_a, line_type stone_b, point_type& cross_point) +{ + const auto p_1 = make_tuple(get<0>(stone_a), get<1>(stone_a)); + const auto p_2 = make_tuple(get<0>(stone_a) + get<3>(stone_a), get<1>(stone_a) + get<4>(stone_a)); + + const auto p_3 = make_tuple(get<0>(stone_b), get<1>(stone_b)); + const auto p_4 = make_tuple(get<0>(stone_b) + get<3>(stone_b), get<1>(stone_b) + get<4>(stone_b)); + + const auto a_1 = get<1>(p_2) - get<1>(p_1); + const auto b_1 = get<0>(p_1) - get<0>(p_2); + const auto c_1 = a_1 * (get<0>(p_1)) + b_1 * (get<1>(p_1)); + + const auto a_2 = get<1>(p_4) - get<1>(p_3); + const auto b_2 = get<0>(p_3) - get<0>(p_4); + const auto c_2 = a_2 * (get<0>(p_3)) + b_2 * (get<1>(p_3)); + + const auto determinant = a_1 * b_2 - a_2 * b_1; + + if ( determinant == 0 ) { + return false; + } + + auto p_x = (b_2 * c_1 - b_1 * c_2) / determinant; + auto p_y = (a_1 * c_2 - a_2 * c_1) / determinant; + + cross_point = make_tuple(p_x, p_y); + + return true; +} + +void +part1(const puzzle_type& input) +{ + const auto in_range = [](point_type point) -> bool { + static const auto lower_limit = 200000000000000.0; + static const auto upper_limit = 400000000000000.0; + + const auto [x, y] = point; + + return x > lower_limit && x < upper_limit && y > lower_limit && y < upper_limit; + }; + + const auto in_future = [](line_type stone, point_type point) -> bool { + const auto sgn_stone = get_direction(stone); + const auto sgn_point = get_direction(stone, point); + + return sgn_stone == sgn_point; + }; + + long sum = 0; + for ( size_t idx = 0; idx != input.size(); ++idx ) { + const auto& stone_a = input[idx]; + + for ( size_t idx2 = idx + 1; idx2 < input.size(); ++idx2 ) { + const auto& stone_b = input[idx2]; + + point_type cross_point; + if ( lint(stone_a, stone_b, cross_point) && in_range(cross_point) && in_future(stone_a, cross_point) && in_future(stone_b, cross_point) ) { + ++sum; + } + } + } + cout << sum << endl; +} + +void +part2(const puzzle_type& input) +{ + auto config = z3::config(); + auto context = z3::context(config); + auto solver = z3::solver(context); + + const auto px = context.int_const("px"); + const auto py = context.int_const("py"); + const auto pz = context.int_const("pz"); + const auto vx = context.int_const("vx"); + const auto vy = context.int_const("vy"); + const auto vz = context.int_const("vz"); + + for ( size_t i = 0; i != input.size(); ++i ) { + const auto& stone = input[i]; + + const auto pxn = context.int_val(int64_t(get<0>(stone))); + const auto pyn = context.int_val(int64_t(get<1>(stone))); + const auto pzn = context.int_val(int64_t(get<2>(stone))); + const auto vxn = context.int_val(int64_t(get<3>(stone))); + const auto vyn = context.int_val(int64_t(get<4>(stone))); + const auto vzn = context.int_val(int64_t(get<5>(stone))); + const auto tn = context.int_const(to_string(i+1).c_str()); + + solver.add(tn >= 0); + solver.add(pxn + vxn * tn == px + vx * tn); + solver.add(pyn + vyn * tn == py + vy * tn); + solver.add(pzn + vzn * tn == pz + vz * tn); + } + + solver.check(); + + auto model = solver.get_model(); + + cout << model.eval(px).as_int64() + model.eval(py).as_int64() + model.eval(pz).as_int64() << endl; +} + +int +main() +{ + const auto input = read_file("data/day24.txt"); + + part1(input); + part2(input); +} -- cgit v1.3