Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <cassert>
- #include <iostream>
- #include <fstream>
- #include <sstream>
- #include <vector>
- #include <iterator>
- #include <algorithm>
- #include <unordered_set>
- #include <set>
- #include <boost/container_hash/hash.hpp>
- #include <boost/fusion/algorithm/auxiliary/copy.hpp>
- #include <boost/fusion/adapted/std_array.hpp>
- #include <boost/fusion/adapted/std_tuple.hpp>
- #include <range/v3/algorithm/count_if.hpp>
- #include <range/v3/algorithm/copy.hpp>
- #include <range/v3/view/transform.hpp>
- #include <range/v3/view/filter.hpp>
- #include <range/v3/view/remove.hpp>
- #include <range/v3/view/iota.hpp>
- #include <range/v3/view/join.hpp>
- #include <range/v3/view/concat.hpp>
- #include <range/v3/view/cartesian_product.hpp>
- #include <range/v3/range/conversion.hpp>
- inline std::string read_file(std::string_view path) {
- std::ifstream is(path.data());
- return static_cast<std::stringstream const&>(std::stringstream() << is.rdbuf()).str();
- }
- namespace day17 {
- template <class point>
- auto get_neighbours_impl(point p) {
- using namespace ranges;
- constexpr auto I = std::tuple_size_v<point>;
- static const auto offsets =
- [] {
- if constexpr (I == 3) {
- return views::cartesian_product(
- views::ints(-1, 2),
- views::ints(-1, 2),
- views::ints(-1, 2))| views::transform([](auto t) { point ret; boost::fusion::copy<std::tuple<int,int,int>, std::array<int,3>>(t, ret); return ret; });
- } else {
- static_assert(I == 4, "I must be 3 or 4");
- return views::cartesian_product(
- views::ints(-1, 2),
- views::ints(-1, 2),
- views::ints(-1, 2),
- views::ints(-1, 2))| views::transform([](auto t) { point ret; boost::fusion::copy<std::tuple<int,int,int,int>, std::array<int,4>>(t, ret); return ret; });
- } }()
- | views::remove(point{})
- | to<std::vector>();
- return offsets | views::transform([&,p](point offset) -> point {
- std::transform(p.begin(), p.end(), offset.begin(), offset.begin(), std::plus<>());
- return offset;
- });
- }
- template <class point_set>
- auto step(const point_set& from) {
- using namespace ranges;
- auto ret = point_set{};
- auto is_active = [&](auto p) { return from.count(p); };
- auto get_neighbours = [](auto p) { return get_neighbours_impl(p); };
- auto cubes_to_check = views::concat(from, from | views::transform(get_neighbours) | views::join) | to<point_set>();
- auto should_be_active = [&](auto p) {
- auto active_neighbours = count_if(get_neighbours(p), is_active);
- if (is_active(p)) {
- return active_neighbours == 2 || active_neighbours == 3;
- } else {
- return active_neighbours == 3;
- }
- };
- return cubes_to_check | views::filter(should_be_active) | to<point_set>();
- }
- template <int dims>
- inline auto execute(std::string s) {
- using point = std::array<int, dims>;
- using point_set = std::unordered_set<point, boost::hash<point>>;
- auto active = point_set{ };
- auto iss = std::istringstream{ s };
- auto line = std::string{ };
- auto y = 0;
- while (std::getline(iss, line)) {
- auto x = 0;
- for (auto c : line) {
- if (c == '#')
- active.insert({x,y});
- ++x;
- }
- ++y;
- }
- for (int i = 0; i < 6; ++i) {
- active = step(std::move(active));
- }
- return active.size();
- }
- namespace a {
- inline void run() {
- auto sample_result = 112;
- assert(execute<3>(read_file("day17.sample")) == sample_result);
- std::cout << "day17a sample: " << execute<3>(read_file("day17.sample")) << ", expected: " << sample_result << std::endl;
- std::cout << "day17a: " << execute<3>(read_file("day17.txt")) << std::endl;
- }
- }
- namespace b {
- inline void run() {
- auto sample_result = 848;
- assert(execute<4>(read_file("day17.sample")) == sample_result);
- std::cout << "day17b sample: " << execute<4>(read_file("day17.sample")) << ", expected: " << sample_result << std::endl;
- std::cout << "day17b: " << execute<4>(read_file("day17.txt")) << std::endl;
- }
- }
- }
- int main() {
- day17::a::run();
- day17::b::run();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement