diff --git a/day11/Makefile b/day11/Makefile index e9397cd..8d7e6a6 100644 --- a/day11/Makefile +++ b/day11/Makefile @@ -1,7 +1,7 @@ CC=g++ BIN_NAME=day11 CCFLAGS=-o $(BIN_NAME) -g -std=c++17 -LDFLAGS=-lfolly +LDFLAGS= .PHONY: all, clean diff --git a/day11/day11.cpp b/day11/day11.cpp index 9318a01..0331e11 100644 --- a/day11/day11.cpp +++ b/day11/day11.cpp @@ -1,13 +1,8 @@ -#include - #include #include #include -#include -#include #include -#include -#include +#include #include constexpr char EMPTY_CHAR = 'L'; @@ -27,14 +22,13 @@ std::vector readInput(const std::string &filename) { return input; } -void printState(const std::vector &state) { - for (const std::string &row : state) { - std::cout << row << std::endl; - } - - std::cout << " " << std::endl; -} - +/** + * Get all of the neighbors for part 1 + * @param state The state of the board + * @param row The row to get neighbors for + * @param column The column to get neighbors for + * @return std::vector The neighbors of this position + */ std::vector getPart1Neighbors(const std::vector &state, int row, int column) { std::vector neighbors; for (int dRow = -1; dRow <= 1; dRow++) { @@ -65,17 +59,52 @@ int sign(T val) { } /** - * Extend a pair in all directions it extends - e.g. (1, 0) becomes (2,0) + * Extend a ray 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 + * @param ray The ray to extend */ template -void extendVector(std::pair &vec) { - vec.first += sign(vec.first); - vec.second += sign(vec.second); +void extendRay(std::pair &ray) { + ray.first += sign(ray.first); + ray.second += sign(ray.second); } +/** + * Cast the given ray until we hit a neighbor that is a seat + * @param state The current board state + * @param origin Where to start the ray from + * @param ray The ray to extend until it hits a seat + * @return optional An optional of the neighbor that was hit. If none, this extended off the board. + */ +std::optional castRayToSeat( + const std::vector &state, const std::pair &origin, const std::pair &ray) { + std::pair rayCursor(ray); + char neighbor; + // Keep projecting our ray until we hit a seat + while (neighbor != OCCUPIED_CHAR && neighbor != EMPTY_CHAR) { + int candidateRow = origin.first + rayCursor.first; + int candidateCol = origin.second + rayCursor.second; + if (candidateRow < 0 || candidateRow >= state.size() || candidateCol < 0 || + candidateCol >= state.at(candidateRow).size()) { + return std::optional(); + } + + neighbor = state.at(candidateRow).at(candidateCol); + extendRay(rayCursor); + } + + return std::optional(neighbor); +} + +/** + * Get all of the neighbors for part 2 + * @param state The state of the board + * @param row The row to get neighbors for + * @param column The column to get neighbors for + * @return std::vector The neighbors of this position + */ std::vector getPart2Neighbors(const std::vector &state, int row, int column) { + std::pair rayOrigin(row, column); std::vector neighbors; for (int dRow = -1; dRow <= 1; dRow++) { for (int dCol = -1; dCol <= 1; dCol++) { @@ -83,28 +112,24 @@ std::vector getPart2Neighbors(const std::vector &state, int r 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); + std::pair deltaRay(dRow, dCol); + std::optional neighbor = castRayToSeat(state, rayOrigin, deltaRay); + if (neighbor.has_value()) { + neighbors.push_back(*neighbor); } - - neighbors.push_back(neighbor); } } return neighbors; } +/** + * Apply the automata rules to a single seat + * @param neighbors The neighbors of the location to check + * @param seatState The state of the seat to check + * @param occupiedThreshold How many seats must be occupied surrounding the location to the seat + * @return char The new state for this position + */ 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; }); @@ -117,12 +142,19 @@ char applyRules(const std::vector &neighbors, char seatState, int occupied } } +/** + * Run the simulation to completion + * @param input The input for the puzzle + * @param occupiedThreshold The number of seats that need to be occupied surrounding a seat to empty it + * @param getNeighbors A function to get the neighbors surrounding a position + * @return int The puzzle answer + */ 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(), ' ')); - for (int count = 0; state != nextState; count++) { + while (state != nextState) { for (int i = 0; i < state.size(); i++) { for (int j = 0; j < input.at(i).size(); j++) { std::vector neighbors = getNeighbors(state, i, j); @@ -131,7 +163,6 @@ int runSimulation( } } - printState(state); std::swap(state, nextState); } @@ -156,6 +187,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; }