Add 2021 day 17 puzzles
This commit is contained in:
75
2021/puzzle-17-01.cc
Normal file
75
2021/puzzle-17-01.cc
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <regex>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
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;
|
||||||
|
}
|
77
2021/puzzle-17-02.cc
Normal file
77
2021/puzzle-17-02.cc
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <regex>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
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;
|
||||||
|
}
|
Reference in New Issue
Block a user