From 17d796ceb0a577b58100580e347abbfe71301b2f Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Fri, 23 Dec 2022 18:13:54 +0000 Subject: [PATCH] Solutions for 2022 day 23 --- 2022/puzzle-23-01.cc | 204 +++++++++++++++++++++++++++++++++++++++++ 2022/puzzle-23-02.cc | 211 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 415 insertions(+) create mode 100644 2022/puzzle-23-01.cc create mode 100644 2022/puzzle-23-02.cc diff --git a/2022/puzzle-23-01.cc b/2022/puzzle-23-01.cc new file mode 100644 index 0000000..c318462 --- /dev/null +++ b/2022/puzzle-23-01.cc @@ -0,0 +1,204 @@ +// +// Created by Matthew Gretton-Dann on 16/12/2022. +// + +#include +#include +#include +#include +#include +#include +#include +#include + +using Int = std::int64_t; +using UInt = std::uint64_t; + +using Point = std::pair; +using Grid = std::vector; +using Dirs = std::list>; + +constexpr Point north{0, -1}; +constexpr Point north_east{1, -1}; +constexpr Point east{1, 0}; +constexpr Point south_east{1, 1}; +constexpr Point south{0, 1}; +constexpr Point south_west{-1, 1}; +constexpr Point west{-1, 0}; +constexpr Point north_west{-1, -1}; + +auto next_state(Grid const& grid, Dirs const& dirs) -> Grid +{ + constexpr std::array all_dirs{north, north_east, east, south_east, + south, south_west, west, north_west}; + + UInt const width{grid.at(0).size()}; + UInt const height{grid.size()}; + Int num_pts{0}; + Grid result(height, std::string(width, '.')); + // We have designed the grid so we shouldn't need to check the edges. + for (unsigned y{1}; y < height - 1; ++y) { + for (unsigned x{1}; x < width - 1; ++x) { + if (grid.at(y).at(x) == '.') { + continue; + } + ++num_pts; + + if (std::all_of(all_dirs.begin(), all_dirs.end(), [&x, &y, &grid](auto const& dir) { + return grid.at(dir.second + y).at(dir.first + x) == '.'; + })) { + result.at(y).at(x) = '#'; + continue; + } + + bool moved{false}; + Point direction{0, 0}; + for (auto const& ds : dirs) { + if (std::all_of(ds.begin(), ds.end(), [&x, &y, &grid](auto const& d) { + return grid.at(y + d.second).at(x + d.first) == '.'; + })) { + moved = true; + direction = ds[1]; + } + if (moved) { + break; + } + } + + char const coord{result.at(y + direction.second).at(x + direction.first)}; + if (result.at(y + direction.second).at(x + direction.first) == '.') { + result.at(y + direction.second).at(x + direction.first) = + static_cast('#' + (direction.second * 4) + direction.first); + } + else { + result.at(y).at(x) = '#'; + int dx{0}; + int dy{0}; + if (coord != 'M') { + switch (coord) { + case '#' - 4 - 1: + dx = 1; + dy = 1; + break; + case '#' - 4: + dx = 0; + dy = 1; + break; + case '#' - 4 + 1: + dx = -1; + dy = 1; + break; + case '#' - 1: + dx = 1; + dy = 0; + break; + case '#' + 1: + dx = -1; + dy = 0; + break; + case '#' + 4 - 1: + dx = 1; + dy = -1; + break; + case '#' + 4: + dx = 0; + dy = -1; + break; + case '#' + 4 + 1: + dx = -1; + dy = -1; + break; + default: + abort(); + } + result.at(y + direction.second).at(x + direction.first) = 'M'; + result.at(y + direction.second + dy).at(x + direction.first + dx) = '#'; + } + } + } + } + + for (unsigned y{0}; y < height; ++y) { + for (unsigned x{0}; x < width; ++x) { + if (result.at(y).at(x) == 'M') { + result.at(y).at(x) = '.'; + } + else if (result.at(y).at(x) != '.') { + result.at(y).at(x) = '#'; + --num_pts; + } + } + } + + assert(num_pts == 0); + return result; +} + +auto calc_score(Grid const& grid) -> UInt +{ + UInt const width{grid.at(0).size()}; + UInt const height{grid.size()}; + UInt num_pts{0}; + UInt min_x{std::numeric_limits::max()}; + UInt min_y{std::numeric_limits::max()}; + UInt max_x{0}; + UInt max_y{0}; + + for (UInt y{0}; y < height; ++y) { + for (UInt x{0}; x < width; ++x) { + if (grid[y][x] == '#') { + min_x = std::min(min_x, x); + min_y = std::min(min_y, y); + max_x = std::max(max_x, x); + max_y = std::max(max_y, y); + ++num_pts; + } + } + } + + return (max_x - min_x + 1) * (max_y - min_y + 1) - num_pts; +} + +using namespace std::string_literals; +auto main() -> int +{ + std::string line; + Grid grid; + + Dirs dirs_to_consider = {{north_west, north, north_east}, + {south_east, south, south_west}, + {south_west, west, north_west}, + {north_east, east, south_east}}; + + constexpr UInt num_rounds{10}; + + // We surround each line of the grid with extra dots so we don't have to resize as we go along. + std::size_t max_row_length{0}; + std::string const padding(num_rounds + 1, '.'); + while (std::getline(std::cin, line)) { + std::string result{padding}; + result += line; + result += padding; + grid.push_back(result); + max_row_length = std::max(max_row_length, result.size()); + } + for (auto& s : grid) { + s.resize(max_row_length, '.'); + } + grid.insert(grid.begin(), num_rounds + 1, std::string(max_row_length, '.')); + grid.insert(grid.end(), num_rounds + 1, std::string(max_row_length, '.')); + + for (UInt i{0}; i < num_rounds; ++i) { + std::cout << "\n\nStep " << i << "\n"; + for (auto const& r : grid) { + std::cout << r << "\n"; + } + grid = next_state(grid, dirs_to_consider); + dirs_to_consider.push_back(dirs_to_consider.front()); + dirs_to_consider.pop_front(); + } + + UInt const score{calc_score(grid)}; + std::cout << "Score: " << score << "\n"; + return EXIT_SUCCESS; +} diff --git a/2022/puzzle-23-02.cc b/2022/puzzle-23-02.cc new file mode 100644 index 0000000..27216a2 --- /dev/null +++ b/2022/puzzle-23-02.cc @@ -0,0 +1,211 @@ +// +// Created by Matthew Gretton-Dann on 16/12/2022. +// + +#include +#include +#include +#include +#include +#include +#include +#include + +using Int = std::int64_t; +using UInt = std::uint64_t; + +using Point = std::pair; +using Grid = std::vector; +using Dirs = std::list>; + +constexpr Point north{0, -1}; +constexpr Point north_east{1, -1}; +constexpr Point east{1, 0}; +constexpr Point south_east{1, 1}; +constexpr Point south{0, 1}; +constexpr Point south_west{-1, 1}; +constexpr Point west{-1, 0}; +constexpr Point north_west{-1, -1}; + +auto next_state(Grid const& grid, Dirs const& dirs) -> Grid +{ + constexpr std::array all_dirs{north, north_east, east, south_east, + south, south_west, west, north_west}; + + UInt const width{grid.at(0).size()}; + UInt const height{grid.size()}; + Int num_pts{0}; + Grid result(height, std::string(width, '.')); + // We have designed the grid so we shouldn't need to check the edges. + for (unsigned y{1}; y < height - 1; ++y) { + for (unsigned x{1}; x < width - 1; ++x) { + if (grid.at(y).at(x) == '.') { + continue; + } + ++num_pts; + + if (std::all_of(all_dirs.begin(), all_dirs.end(), [&x, &y, &grid](auto const& dir) { + return grid.at(dir.second + y).at(dir.first + x) == '.'; + })) { + result.at(y).at(x) = '#'; + continue; + } + + bool moved{false}; + Point direction{0, 0}; + for (auto const& ds : dirs) { + if (std::all_of(ds.begin(), ds.end(), [&x, &y, &grid](auto const& d) { + return grid.at(y + d.second).at(x + d.first) == '.'; + })) { + moved = true; + direction = ds[1]; + } + if (moved) { + break; + } + } + + char const coord{result.at(y + direction.second).at(x + direction.first)}; + if (result.at(y + direction.second).at(x + direction.first) == '.') { + result.at(y + direction.second).at(x + direction.first) = + static_cast('#' + (direction.second * 4) + direction.first); + } + else { + result.at(y).at(x) = '#'; + int dx{0}; + int dy{0}; + if (coord != 'M') { + switch (coord) { + case '#' - 4 - 1: + dx = 1; + dy = 1; + break; + case '#' - 4: + dx = 0; + dy = 1; + break; + case '#' - 4 + 1: + dx = -1; + dy = 1; + break; + case '#' - 1: + dx = 1; + dy = 0; + break; + case '#' + 1: + dx = -1; + dy = 0; + break; + case '#' + 4 - 1: + dx = 1; + dy = -1; + break; + case '#' + 4: + dx = 0; + dy = -1; + break; + case '#' + 4 + 1: + dx = -1; + dy = -1; + break; + default: + abort(); + } + result.at(y + direction.second).at(x + direction.first) = 'M'; + result.at(y + direction.second + dy).at(x + direction.first + dx) = '#'; + } + } + } + } + + for (unsigned y{0}; y < height; ++y) { + for (unsigned x{0}; x < width; ++x) { + if (result.at(y).at(x) == 'M') { + result.at(y).at(x) = '.'; + } + else if (result.at(y).at(x) != '.') { + result.at(y).at(x) = '#'; + --num_pts; + } + } + } + + assert(num_pts == 0); + return result; +} + +auto calc_score(Grid const& grid) -> UInt +{ + UInt const width{grid.at(0).size()}; + UInt const height{grid.size()}; + UInt num_pts{0}; + UInt min_x{std::numeric_limits::max()}; + UInt min_y{std::numeric_limits::max()}; + UInt max_x{0}; + UInt max_y{0}; + + for (UInt y{0}; y < height; ++y) { + for (UInt x{0}; x < width; ++x) { + if (grid[y][x] == '#') { + min_x = std::min(min_x, x); + min_y = std::min(min_y, y); + max_x = std::max(max_x, x); + max_y = std::max(max_y, y); + ++num_pts; + } + } + } + + return (max_x - min_x + 1) * (max_y - min_y + 1) - num_pts; +} + +using namespace std::string_literals; +auto main() -> int +{ + std::string line; + Grid grid; + + Dirs dirs_to_consider = {{north_west, north, north_east}, + {south_east, south, south_west}, + {south_west, west, north_west}, + {north_east, east, south_east}}; + + // We surround each line of the grid with extra dots so we don't have to resize as we go along. + std::size_t width{0}; + while (std::getline(std::cin, line)) { + grid.push_back(line); + width = std::max(width, line.size()); + } + for (auto& s : grid) { + s.resize(width, '.'); + } + + Grid last_grid; + UInt num_rounds{0}; + while (grid != last_grid) { +#if 0 + std::cout << "\n\nStep " << num_rounds << "\n"; + for (auto const& r : grid) { + std::cout << r << "\n"; + } +#endif + ++num_rounds; + for (auto& r : grid) { + r.insert(r.begin(), '.'); + r.insert(r.end(), '.'); + } + width += 2; + grid.insert(grid.begin(), std::string(width, '.')); + grid.insert(grid.end(), std::string(width, '.')); + last_grid = grid; + + grid = next_state(grid, dirs_to_consider); + dirs_to_consider.push_back(dirs_to_consider.front()); + dirs_to_consider.pop_front(); + } + + UInt const score{calc_score(grid)}; + std::cout << "Score: " << score << "\n"; + std::cout << "Number of turns: " << num_rounds<< "\n"; + return EXIT_SUCCESS; +}