Replace day 20 part 1 with an iterative solution

master
Nick Krichevsky 2020-12-23 23:57:40 -05:00
parent d542f48da8
commit 1b5fcd12f7
1 changed files with 61 additions and 101 deletions

View File

@ -201,8 +201,11 @@ void printBoard(const std::map<std::pair<int, int>, CameraFrame> &board, int max
for (int j = 0; j < maxCol; j++) { for (int j = 0; j < maxCol; j++) {
auto frame = board.find(std::make_pair(i, j)); auto frame = board.find(std::make_pair(i, j));
auto frameRowStr = (frame == board.end() ? emptyFrame : frame->second).getFrame().at(frameRow); auto frameRowStr = (frame == board.end() ? emptyFrame : frame->second).getFrame().at(frameRow);
std::cout << frameRowStr << " ";
} }
std::cout << std::endl;
} }
std::cout << std::endl;
} }
} }
@ -248,109 +251,68 @@ bool isBoardFilled(const std::map<std::pair<int, int>, CameraFrame> board, int m
return true; return true;
} }
std::optional<CameraFrame> findPossibleFrame(
const std::vector<CameraFrame> &availableFrames, std::function<bool(const CameraFrame &)> findFrame) {
auto result = std::find_if(availableFrames.cbegin(), availableFrames.cend(), findFrame);
if (result == availableFrames.cend()) {
return std::nullopt;
}
return *result;
}
std::optional<std::map<std::pair<int, int>, CameraFrame>> findLinedUpArrangement( std::optional<std::map<std::pair<int, int>, CameraFrame>> findLinedUpArrangement(
const std::map<std::pair<int, int>, CameraFrame> &board, const CameraFrame &startingFrame, const std::vector<CameraFrame> &frames, int maxRow, int maxCol) {
const std::vector<CameraFrame> &availableFrames, std::map<std::pair<int, int>, CameraFrame> board;
std::map<std::pair<int, int>, int> &visited, std::vector<CameraFrame> availableFrames(frames);
int row, board.emplace(std::make_pair(0, 0), startingFrame);
int col, for (int row = 0; row < maxRow; row++) {
int maxRow, for (int col = 0; col < maxCol; col++) {
int maxCol, if (row == 0 && col == 0) {
int depth = 0) { continue;
auto performRecursion = [&board, maxRow, maxCol, depth, &visited]( }
const CameraFrame &cursor,
const std::vector<CameraFrame> &availableFrames, bool found = false;
const std::string &edge1, for (const CameraFrame &currentFrame : availableFrames) {
const std::function<std::string(const CameraFrame &)> getEdge2, auto transformed = getPossibleTransforms(currentFrame);
int nextRow, for (const CameraFrame &currentTransformedFrame : transformed) {
int nextCol) -> std::optional<std::map<std::pair<int, int>, CameraFrame>> { std::optional<CameraFrame> matchingFrame;
for (const CameraFrame &candidateFrame : availableFrames) { if (col == 0) {
auto operations = getPossibleTransforms(candidateFrame); CameraFrame &aboveFrame = board.at(std::make_pair(row - 1, col));
std::vector<CameraFrame> nextAvailableFrames(availableFrames); matchingFrame = findPossibleFrame(transformed, [aboveFrame](const CameraFrame &frame) {
nextAvailableFrames.erase( return aboveFrame.getBottomEdge() == frame.getTopEdge();
std::find(nextAvailableFrames.cbegin(), nextAvailableFrames.cend(), candidateFrame)); });
for (const CameraFrame &operatedFrame : operations) { } else {
auto edge2 = getEdge2(operatedFrame); CameraFrame &leftFrame = board.at(std::make_pair(row, col - 1));
if (edge1 == edge2) { matchingFrame = findPossibleFrame(transformed, [leftFrame](const CameraFrame &frame) {
std::map<std::pair<int, int>, CameraFrame> nextBoard(board); return leftFrame.getRightEdge() == frame.getLeftEdge();
nextBoard.emplace(std::make_pair(nextRow, nextCol), operatedFrame); });
return findLinedUpArrangement( }
nextBoard, nextAvailableFrames, visited, nextRow, nextCol, maxRow, maxCol, depth + 1);
if (matchingFrame) {
found = true;
board.emplace(std::make_pair(row, col), *matchingFrame);
availableFrames.erase(
std::remove(availableFrames.begin(), availableFrames.end(), currentFrame));
// printBoard(board, maxRow, maxCol);
break;
}
}
if (found) {
break;
} }
} }
if (!found) {
return std::nullopt;
}
} }
}
return std::nullopt; if (!isBoardFilled(board, maxRow, maxCol)) {
};
const CameraFrame &cursor = board.at(std::make_pair(row, col));
// If we've already visited this configuration, and backtracked, we're done.
auto visitedCheck = visited.find(std::make_pair(row, col));
if (isBoardFilled(board, maxRow, maxCol)) {
return board;
} else if (availableFrames.empty() || (visitedCheck != visited.end() && visitedCheck->second == cursor.getID())) {
return std::nullopt; return std::nullopt;
} }
visited.emplace(std::make_pair(row, col), cursor.getID());
// Any operation involving the top edge cannot occur if this tile is already at the top
if (row > 0 && board.find(std::make_pair(row - 1, col)) == board.end()) {
auto result = performRecursion(
cursor,
availableFrames,
cursor.getTopEdge(),
[](const CameraFrame &candidate) { return candidate.getBottomEdge(); },
row - 1,
col);
if (result) { return board;
return *result;
}
}
if (row < maxRow - 1 && board.find(std::make_pair(row + 1, col)) == board.end()) {
auto result = performRecursion(
cursor,
availableFrames,
cursor.getBottomEdge(),
[](const CameraFrame &candidate) { return candidate.getTopEdge(); },
row + 1,
col);
if (result) {
return *result;
}
}
// Any operation involving the left edge cannot occur if this tile is already at the left
if (col > 0 && board.find(std::make_pair(row, col - 1)) == board.end()) {
auto result = performRecursion(
cursor,
availableFrames,
cursor.getLeftEdge(),
[](const CameraFrame &candidate) { return candidate.getRightEdge(); },
row,
col - 1);
if (result) {
return *result;
}
}
// Any operation involving the right edge cannot occur if the tile is at the right
if (col < maxCol - 1 && board.find(std::make_pair(row, col + 1)) == board.end()) {
auto result = performRecursion(
cursor,
availableFrames,
cursor.getRightEdge(),
[](const CameraFrame &candidate) { return candidate.getLeftEdge(); },
row,
col + 1);
if (result) {
return *result;
}
}
return std::nullopt;
} }
long part1(const std::vector<CameraFrame> &frames) { long part1(const std::vector<CameraFrame> &frames) {
@ -358,12 +320,10 @@ long part1(const std::vector<CameraFrame> &frames) {
for (const CameraFrame &frame : frames) { for (const CameraFrame &frame : frames) {
std::vector<CameraFrame> availableFrames(frames); std::vector<CameraFrame> availableFrames(frames);
availableFrames.erase(std::remove(availableFrames.begin(), availableFrames.end(), frame)); availableFrames.erase(std::remove(availableFrames.begin(), availableFrames.end(), frame));
auto operations = getPossibleTransforms(frame);
for (const CameraFrame &operatedFrame : operations) { auto transformed = getPossibleTransforms(frame);
std::map<std::pair<int, int>, CameraFrame> board; for (const CameraFrame &transformedFrame : transformed) {
std::map<std::pair<int, int>, int> visited; auto res = findLinedUpArrangement(transformedFrame, availableFrames, boardSize, boardSize);
board.emplace(std::make_pair(0, 0), operatedFrame);
auto res = findLinedUpArrangement(board, availableFrames, visited, 0, 0, boardSize, boardSize);
if (res) { if (res) {
return 1L * res->at(std::make_pair(0, 0)).getID() * res->at(std::make_pair(0, boardSize - 1)).getID() * return 1L * res->at(std::make_pair(0, 0)).getID() * res->at(std::make_pair(0, boardSize - 1)).getID() *
res->at(std::make_pair(boardSize - 1, 0)).getID() * res->at(std::make_pair(boardSize - 1, 0)).getID() *