diff --git a/2021/puzzle-17-01.cc b/2021/puzzle-17-01.cc new file mode 100644 index 0000000..872fc75 --- /dev/null +++ b/2021/puzzle-17-01.cc @@ -0,0 +1,75 @@ +#include +#include +#include + +template +constexpr auto triangle_sum(T t) noexcept -> T +{ + return t * (t + 1) / 2; +} + +auto main() -> int +{ + static std::regex re{R"(target area: x=(-?\d+)\.\.(-?\d+), y=(-?\d+)\.\.(-?\d+))"}; + std::smatch m; + std::string line; + + if (!std::getline(std::cin, line)) { + std::cerr << "Unable to read line"; + return 1; + } + if (!std::regex_search(line, m, re)) { + std::cerr << "Unable to interpret: " << line << '\n'; + return 1; + } + + auto x0{std::stol(m.str(1))}; + auto x1{std::stol(m.str(2))}; + auto y0{std::stol(m.str(3))}; + auto y1{std::stol(m.str(4))}; + + auto x_max{std::max(std::abs(x0), std::abs(x1))}; + auto [y_min, y_max] = std::minmax(std::abs(y0), std::abs(y1)); + /* We want to go at most x_max away. To do this in the most steps we want to be going vertical + * at or before the last step. So vx0 must be such that: + * vx0 + (vx0 - 1) + ... + 1 + 0 ... 0 <= x_max. (Look triangular number we know a formula...) + * => vx0 * (vx0 + 1) / 2 <= x_max + * + * I'm lazy - the input is small enough that I can find this by iteration... + */ + long vx0{1}; + while (triangle_sum(vx0) < x_max) { + ++vx0; + } + /* And correct vx0 here. */ + --vx0; + + std::cout << "vx0: " << vx0 << '\n'; + + /* Going the vertically is harder. Let's do it by iteration. We know the total number of steps + * we want to take is at least vx0. + * + * Actually - we pass y=0 on the way down, with velocity -vy0. So we want: + * triangle_sum(vy_end) - triangle_sum(vy0) <= y_max; + */ + long candidate_vy0{1}; + long vy0{1}; + while (candidate_vy0 <= y_max) { + long ypos{0}; + long vy{candidate_vy0}; + while (ypos < y_max) { + ypos += (vy++); + } + ypos -= (--vy); + if (ypos >= y_min) { + /* This speed works - let's use update the candidate. */ + vy0 = candidate_vy0; + } + ++candidate_vy0; + } + + std::cout << "vy0: " << vy0 << '\n'; + std::cout << "Max height:" << triangle_sum(vy0) << '\n'; + + return 0; +} diff --git a/2021/puzzle-17-02.cc b/2021/puzzle-17-02.cc new file mode 100644 index 0000000..ea22a66 --- /dev/null +++ b/2021/puzzle-17-02.cc @@ -0,0 +1,77 @@ +#include +#include +#include + +template +constexpr auto triangle_sum(T t) noexcept -> T +{ + return t * (t + 1) / 2; +} + +auto main() -> int +{ + static std::regex re{R"(target area: x=(-?\d+)\.\.(-?\d+), y=(-?\d+)\.\.(-?\d+))"}; + std::smatch m; + std::string line; + + if (!std::getline(std::cin, line)) { + std::cerr << "Unable to read line"; + return 1; + } + if (!std::regex_search(line, m, re)) { + std::cerr << "Unable to interpret: " << line << '\n'; + return 1; + } + + auto x0{std::stol(m.str(1))}; + auto x1{std::stol(m.str(2))}; + auto y0{std::stol(m.str(3))}; + auto y1{std::stol(m.str(4))}; + + auto [x_min, x_max] = std::minmax(std::abs(x0), std::abs(x1)); + auto [y_min, y_max] = std::minmax(std::abs(y0), std::abs(y1)); + + /* Find a minimum vx0. */ + long vx0_min{1}; + while (triangle_sum(vx0_min) < x_min) { + ++vx0_min; + } + + unsigned count_success{0}; + + /* For each of the possible starting velocities. */ + for (long vy0_start{-y_max}; vy0_start <= y_max; ++vy0_start) { + for (long vx0_start{vx0_min}; vx0_start <= x_max; ++vx0_start) { + auto vx0{vx0_start}; + auto vy0{vy0_start}; + long x{0}; + long y{0}; + + /* Iterate until we're in the target range in the x direction. We know this will happen as + * vx0_start is at least vx0_min. + */ + while (x < x_min) { + x += vx0; + vx0 = std::max(vx0 - 1, long{0}); + y += (vy0--); + } + + /* Now check to see where whether the y co-ordinate will end up in the target zone whilst + * we're still in the zone horizontally. + */ + while (x <= x_max && -y <= y_max) { + if (y_min <= -y && -y <= y_max) { + ++count_success; + break; + } + x += vx0; + vx0 = std::max(vx0 - 1, long{0}); + y += (vy0--); + } + } + } + + std::cout << "Count of successful trajectories:" << count_success << '\n'; + + return 0; +}