diff --git a/day17/Makefile b/day17/Makefile index b6b95eb..7561e00 100644 --- a/day17/Makefile +++ b/day17/Makefile @@ -1,15 +1,19 @@ CC=g++ -BIN_NAME=day17 -CCFLAGS=-o $(BIN_NAME) -g -std=c++17 +PART_1_BIN_NAME=day17p1 +PART_2_BIN_NAME=day17p2 +CCFLAGS=-g -std=c++17 LDFLAGS=-lfolly .PHONY: all, clean -all: $(BIN_NAME) +all: $(PART_1_BIN_NAME) $(PART_2_BIN_NAME) clean: - rm -f $(BIN_NAME) + rm -f $(PART_1_BIN_NAME) $(PART_2_BIN_NAME) -$(BIN_NAME): day17.cpp - $(CC) $(CCFLAGS) $(LDFLAGS) day17.cpp +$(PART_1_BIN_NAME): day17p1.cpp + $(CC) -o $@ $(CCFLAGS) $(LDFLAGS) day17p1.cpp + +$(PART_2_BIN_NAME): day17p2.cpp + $(CC) -o $@ $(CCFLAGS) $(LDFLAGS) day17p2.cpp diff --git a/day17/day17.cpp b/day17/day17p1.cpp similarity index 98% rename from day17/day17.cpp rename to day17/day17p1.cpp index 30c1167..770c8d5 100644 --- a/day17/day17.cpp +++ b/day17/day17p1.cpp @@ -10,7 +10,7 @@ constexpr char ALIVE_CHAR = '#'; constexpr char DEAD_CHAR = '.'; -constexpr int PART_1_CYCLE_COUNT = 6; +constexpr int CYCLE_COUNT = 6; enum CellState { ALIVE, DEAD }; @@ -125,7 +125,7 @@ void printBoard(const Board &board) { int part1(const std::vector &input) { Board board = parseBoard(input); Board nextBoard = board; - for (int i = 0; i < PART_1_CYCLE_COUNT; i++) { + for (int i = 0; i < CYCLE_COUNT; i++) { printBoard(board); auto ranges = getRangeOnEachAxis(board); for (int row = std::get<0>(ranges.first) - 1; row <= std::get<0>(ranges.second) + 1; row++) { diff --git a/day17/day17p2.cpp b/day17/day17p2.cpp new file mode 100644 index 0000000..317aaa6 --- /dev/null +++ b/day17/day17p2.cpp @@ -0,0 +1,170 @@ +#include + +#include +#include +#include +#include +#include +#include +#include + +constexpr char ALIVE_CHAR = '#'; +constexpr char DEAD_CHAR = '.'; +constexpr int CYCLE_COUNT = 6; + +enum CellState { ALIVE, DEAD }; + +using Position = std::tuple; +using Board = std::map; + +std::vector readInput(const std::string &filename) { + std::vector input; + std::string line; + std::ifstream file(filename); + while (std::getline(file, line)) { + input.push_back(line); + } + + return input; +} + +Board parseBoard(const std::vector &input) { + Board board; + int rowCursor = 0; + for (auto rowIterator = input.cbegin(); rowIterator != input.cend(); (rowCursor++, ++rowIterator)) { + auto &line = *rowIterator; + int colCursor = 0; + for (auto colIterator = line.cbegin(); colIterator != line.cend(); (colCursor++, ++colIterator)) { + CellState state = *colIterator == ALIVE_CHAR ? ALIVE : DEAD; + Position position(rowCursor, colCursor, 0, 0); + board.emplace(std::move(position), std::move(state)); + } + } + + return board; +} + +int getNumAdjacentLiveNeighbors(const Board &board, int row, int col, int depth, int w) { + int count = 0; + for (int dRow = -1; dRow <= 1; dRow++) { + for (int dCol = -1; dCol <= 1; dCol++) { + for (int dDepth = -1; dDepth <= 1; dDepth++) { + for (int dW = -1; dW <= 1; dW++) { + if (dRow == 0 && dCol == 0 && dDepth == 0 && dW == 0) { + continue; + } + + Position position(row + dRow, col + dCol, depth + dDepth, w + dW); + if (board.find(position) == board.end()) { + continue; + } + + count += (board.at(position) == ALIVE); + } + } + } + } + + return count; +} + +template +std::pair getMinMax(const Board &board) { + std::vector> alivePositions; + std::copy_if( + board.cbegin(), + board.cend(), + std::back_inserter(alivePositions), + [](const std::pair &item) { return item.second == ALIVE; }); + + auto elements = std::minmax_element( + alivePositions.cbegin(), + alivePositions.cend(), + [](const std::pair &item, const std::pair &item2) { + return std::get(item.first) < std::get(item2.first); + }); + int minComponent = std::get(elements.first->first); + int maxComponent = std::get(elements.second->first); + + return std::pair(minComponent, maxComponent); +} + +std::pair getRangeOnEachAxis(const Board &board) { + std::pair rowRange = getMinMax<0>(board); + std::pair colRange = getMinMax<1>(board); + std::pair depthRange = getMinMax<2>(board); + std::pair wRange = getMinMax<3>(board); + + return std::pair( + Position(rowRange.first, colRange.first, depthRange.first, wRange.first), + Position(rowRange.second, colRange.second, depthRange.second, wRange.second)); +} + +template +Val getOrDefault(const std::map &map, Val defaultValue, Key key) { + if (map.find(key) == map.end()) { + return defaultValue; + } + + return map.at(key); +} + +void printBoard(const Board &board) { + auto ranges = getRangeOnEachAxis(board); + for (int depth = std::get<2>(ranges.first); depth <= std::get<2>(ranges.second); depth++) { + std::cout << "Depth z=" << depth << std::endl; + for (int w = std::get<3>(ranges.first); w <= std::get<3>(ranges.second); w++) { + std::cout << "Four-D w=" << w << std::endl; + for (int row = std::get<0>(ranges.first); row <= std::get<0>(ranges.second); row++) { + for (int col = std::get<1>(ranges.first); col <= std::get<1>(ranges.second); col++) { + Position position(row, col, depth, w); + CellState state = getOrDefault(board, DEAD, position); + std::cout << ((state == ALIVE) ? ALIVE_CHAR : DEAD_CHAR); + } + std::cout << std::endl; + } + } + } + std::cout << std::endl; +} +int run(const std::vector &input) { + Board board = parseBoard(input); + Board nextBoard = board; + for (int i = 0; i < CYCLE_COUNT; i++) { + printBoard(board); + auto ranges = getRangeOnEachAxis(board); + for (int row = std::get<0>(ranges.first) - 1; row <= std::get<0>(ranges.second) + 1; row++) { + for (int col = std::get<1>(ranges.first) - 1; col <= std::get<1>(ranges.second) + 1; col++) { + for (int depth = std::get<2>(ranges.first) - 1; depth <= std::get<2>(ranges.second) + 1; depth++) { + for (int w = std::get<3>(ranges.first) - 1; w <= std::get<3>(ranges.second) + 1; w++) { + int aliveNeighbors = getNumAdjacentLiveNeighbors(board, row, col, depth, w); + Position position(row, col, depth, w); + CellState state = getOrDefault(board, DEAD, position); + if (aliveNeighbors != 2 && aliveNeighbors != 3) { + state = DEAD; + } else if (state == DEAD && aliveNeighbors == 3) { + state = ALIVE; + } + + nextBoard[position] = state; + } + } + } + } + std::swap(nextBoard, board); + } + + return std::count_if( + board.cbegin(), board.cend(), [](const std::pair &item) { return item.second == ALIVE; }); +} + +int main(int argc, char *argv[]) { + if (argc != 2) { + std::cerr << argv[0] << " " << std::endl; + return 1; + } + + auto input = readInput(argv[1]); + + std::cout << run(input) << std::endl; +}