diff --git a/day11/Makefile b/day11/Makefile new file mode 100644 index 0000000..e9397cd --- /dev/null +++ b/day11/Makefile @@ -0,0 +1,15 @@ +CC=g++ +BIN_NAME=day11 +CCFLAGS=-o $(BIN_NAME) -g -std=c++17 +LDFLAGS=-lfolly + +.PHONY: all, clean + +all: $(BIN_NAME) + +clean: + rm -f $(BIN_NAME) + +$(BIN_NAME): day11.cpp + $(CC) $(CCFLAGS) $(LDFLAGS) day11.cpp + diff --git a/day11/day11.cpp b/day11/day11.cpp index d3c8483..9318a01 100644 --- a/day11/day11.cpp +++ b/day11/day11.cpp @@ -13,6 +13,8 @@ constexpr char EMPTY_CHAR = 'L'; constexpr char FLOOR_CHAR = '.'; constexpr char OCCUPIED_CHAR = '#'; +constexpr int PART_1_OCCUPIED_THRESHOLD = 4; +constexpr int PART_2_OCCUPIED_THRESHOLD = 5; std::vector readInput(const std::string &filename) { std::vector input; @@ -25,7 +27,15 @@ std::vector readInput(const std::string &filename) { return input; } -std::vector getNeighbors(const std::vector &state, int row, int column) { +void printState(const std::vector &state) { + for (const std::string &row : state) { + std::cout << row << std::endl; + } + + std::cout << " " << std::endl; +} + +std::vector getPart1Neighbors(const std::vector &state, int row, int column) { std::vector neighbors; for (int dRow = -1; dRow <= 1; dRow++) { for (int dCol = -1; dCol <= 1; dCol++) { @@ -35,7 +45,7 @@ std::vector getNeighbors(const std::vector &state, int row, i int candidateRow = row + dRow; int candidateCol = column + dCol; - if (candidateRow < 0 || candidateRow >= state.size() || candidateRow < 0 || + if (candidateRow < 0 || candidateRow >= state.size() || candidateCol < 0 || candidateCol >= state.at(candidateRow).size()) { continue; } @@ -48,39 +58,80 @@ std::vector getNeighbors(const std::vector &state, int row, i return neighbors; } -char applyRules(const std::vector &state, int row, int column) { - std::vector neighbors = getNeighbors(state, row, column); - char item = state.at(row).at(column); +template +int sign(T val) { + // Taken from https://stackoverflow.com/questions/1903954/is-there-a-standard-sign-function-signum-sgn-in-c-c + return (T(0) < val) - (val < T(0)); +} + +/** + * Extend a pair in all directions it extends - e.g. (1, 0) becomes (2,0) + * @tparam T The type that the pair holds + * @param vec The vector to extend + */ +template +void extendVector(std::pair &vec) { + vec.first += sign(vec.first); + vec.second += sign(vec.second); +} + +std::vector getPart2Neighbors(const std::vector &state, int row, int column) { + std::vector neighbors; + for (int dRow = -1; dRow <= 1; dRow++) { + for (int dCol = -1; dCol <= 1; dCol++) { + if (dRow == 0 && dCol == 0) { + continue; + } + + std::pair deltaVector(dRow, dCol); + char neighbor = FLOOR_CHAR; + // Keep projecting our ray until we hit a non floor char + while (neighbor == FLOOR_CHAR) { + int candidateRow = row + deltaVector.first; + int candidateCol = column + deltaVector.second; + if (candidateRow < 0 || candidateRow >= state.size() || candidateCol < 0 || + candidateCol >= state.at(candidateRow).size()) { + break; + } + + neighbor = state.at(candidateRow).at(candidateCol); + extendVector(deltaVector); + } + + neighbors.push_back(neighbor); + } + } + + return neighbors; +} + +char applyRules(const std::vector &neighbors, char seatState, int occupiedThreshold) { int numOccupied = std::count_if(neighbors.begin(), neighbors.end(), [](char neighbor) { return neighbor == OCCUPIED_CHAR; }); - if (item == EMPTY_CHAR && numOccupied == 0) { + if (seatState == EMPTY_CHAR && numOccupied == 0) { return OCCUPIED_CHAR; - } else if (item == OCCUPIED_CHAR && numOccupied >= 4) { + } else if (seatState == OCCUPIED_CHAR && numOccupied >= occupiedThreshold) { return EMPTY_CHAR; } else { - return item; + return seatState; } } -void printState(const std::vector &state) { - for (const std::string &row : state) { - std::cout << row << std::endl; - } - - std::cout << " " << std::endl; -} - -int part1(const std::vector &input) { +int runSimulation( + const std::vector &input, int occupiedThreshold, + std::function(const std::vector, int, int)> getNeighbors) { std::vector state(input); std::vector nextState(input.size(), std::string(input.at(0).size(), ' ')); - while (state != nextState) { + for (int count = 0; state != nextState; count++) { for (int i = 0; i < state.size(); i++) { for (int j = 0; j < input.at(i).size(); j++) { - char res = applyRules(state, i, j); + std::vector neighbors = getNeighbors(state, i, j); + char res = applyRules(neighbors, state.at(i).at(j), occupiedThreshold); nextState.at(i).at(j) = res; } } + printState(state); std::swap(state, nextState); } @@ -89,6 +140,14 @@ int part1(const std::vector &input) { }); } +int part1(const std::vector &input) { + return runSimulation(input, PART_1_OCCUPIED_THRESHOLD, getPart1Neighbors); +} + +int part2(const std::vector &input) { + return runSimulation(input, PART_2_OCCUPIED_THRESHOLD, getPart2Neighbors); +} + int main(int argc, char *argv[]) { if (argc != 2) { std::cerr << argv[0] << " " << std::endl; @@ -97,5 +156,6 @@ int main(int argc, char *argv[]) { auto input = readInput(argv[1]); - std::cout << part1(input) << std::endl; + // std::cout << part1(input) << std::endl; + std::cout << part2(input) << std::endl; }