Add day 17 part 2 soln
parent
74547ffe7a
commit
cef898b2ed
|
@ -1,15 +1,19 @@
|
||||||
CC=g++
|
CC=g++
|
||||||
BIN_NAME=day17
|
PART_1_BIN_NAME=day17p1
|
||||||
CCFLAGS=-o $(BIN_NAME) -g -std=c++17
|
PART_2_BIN_NAME=day17p2
|
||||||
|
CCFLAGS=-g -std=c++17
|
||||||
LDFLAGS=-lfolly
|
LDFLAGS=-lfolly
|
||||||
|
|
||||||
.PHONY: all, clean
|
.PHONY: all, clean
|
||||||
|
|
||||||
all: $(BIN_NAME)
|
all: $(PART_1_BIN_NAME) $(PART_2_BIN_NAME)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(BIN_NAME)
|
rm -f $(PART_1_BIN_NAME) $(PART_2_BIN_NAME)
|
||||||
|
|
||||||
$(BIN_NAME): day17.cpp
|
$(PART_1_BIN_NAME): day17p1.cpp
|
||||||
$(CC) $(CCFLAGS) $(LDFLAGS) day17.cpp
|
$(CC) -o $@ $(CCFLAGS) $(LDFLAGS) day17p1.cpp
|
||||||
|
|
||||||
|
$(PART_2_BIN_NAME): day17p2.cpp
|
||||||
|
$(CC) -o $@ $(CCFLAGS) $(LDFLAGS) day17p2.cpp
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
constexpr char ALIVE_CHAR = '#';
|
constexpr char ALIVE_CHAR = '#';
|
||||||
constexpr char DEAD_CHAR = '.';
|
constexpr char DEAD_CHAR = '.';
|
||||||
constexpr int PART_1_CYCLE_COUNT = 6;
|
constexpr int CYCLE_COUNT = 6;
|
||||||
|
|
||||||
enum CellState { ALIVE, DEAD };
|
enum CellState { ALIVE, DEAD };
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ void printBoard(const Board &board) {
|
||||||
int part1(const std::vector<std::string> &input) {
|
int part1(const std::vector<std::string> &input) {
|
||||||
Board board = parseBoard(input);
|
Board board = parseBoard(input);
|
||||||
Board nextBoard = board;
|
Board nextBoard = board;
|
||||||
for (int i = 0; i < PART_1_CYCLE_COUNT; i++) {
|
for (int i = 0; i < CYCLE_COUNT; i++) {
|
||||||
printBoard(board);
|
printBoard(board);
|
||||||
auto ranges = getRangeOnEachAxis(board);
|
auto ranges = getRangeOnEachAxis(board);
|
||||||
for (int row = std::get<0>(ranges.first) - 1; row <= std::get<0>(ranges.second) + 1; row++) {
|
for (int row = std::get<0>(ranges.first) - 1; row <= std::get<0>(ranges.second) + 1; row++) {
|
|
@ -0,0 +1,170 @@
|
||||||
|
#include <folly/String.h>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
constexpr char ALIVE_CHAR = '#';
|
||||||
|
constexpr char DEAD_CHAR = '.';
|
||||||
|
constexpr int CYCLE_COUNT = 6;
|
||||||
|
|
||||||
|
enum CellState { ALIVE, DEAD };
|
||||||
|
|
||||||
|
using Position = std::tuple<int, int, int, int>;
|
||||||
|
using Board = std::map<Position, CellState>;
|
||||||
|
|
||||||
|
std::vector<std::string> readInput(const std::string &filename) {
|
||||||
|
std::vector<std::string> input;
|
||||||
|
std::string line;
|
||||||
|
std::ifstream file(filename);
|
||||||
|
while (std::getline(file, line)) {
|
||||||
|
input.push_back(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
Board parseBoard(const std::vector<std::string> &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 <int componentIndex>
|
||||||
|
std::pair<int, int> getMinMax(const Board &board) {
|
||||||
|
std::vector<std::pair<Position, CellState>> alivePositions;
|
||||||
|
std::copy_if(
|
||||||
|
board.cbegin(),
|
||||||
|
board.cend(),
|
||||||
|
std::back_inserter(alivePositions),
|
||||||
|
[](const std::pair<Position, CellState> &item) { return item.second == ALIVE; });
|
||||||
|
|
||||||
|
auto elements = std::minmax_element(
|
||||||
|
alivePositions.cbegin(),
|
||||||
|
alivePositions.cend(),
|
||||||
|
[](const std::pair<Position, CellState> &item, const std::pair<Position, CellState> &item2) {
|
||||||
|
return std::get<componentIndex>(item.first) < std::get<componentIndex>(item2.first);
|
||||||
|
});
|
||||||
|
int minComponent = std::get<componentIndex>(elements.first->first);
|
||||||
|
int maxComponent = std::get<componentIndex>(elements.second->first);
|
||||||
|
|
||||||
|
return std::pair<int, int>(minComponent, maxComponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<Position, Position> getRangeOnEachAxis(const Board &board) {
|
||||||
|
std::pair<int, int> rowRange = getMinMax<0>(board);
|
||||||
|
std::pair<int, int> colRange = getMinMax<1>(board);
|
||||||
|
std::pair<int, int> depthRange = getMinMax<2>(board);
|
||||||
|
std::pair<int, int> wRange = getMinMax<3>(board);
|
||||||
|
|
||||||
|
return std::pair<Position, Position>(
|
||||||
|
Position(rowRange.first, colRange.first, depthRange.first, wRange.first),
|
||||||
|
Position(rowRange.second, colRange.second, depthRange.second, wRange.second));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Key, typename Val>
|
||||||
|
Val getOrDefault(const std::map<Key, Val> &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<std::string> &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<Position, CellState> &item) { return item.second == ALIVE; });
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
if (argc != 2) {
|
||||||
|
std::cerr << argv[0] << " <input_file>" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto input = readInput(argv[1]);
|
||||||
|
|
||||||
|
std::cout << run(input) << std::endl;
|
||||||
|
}
|
Loading…
Reference in New Issue