From c980fdf735f40b8f3b86691a9aee1277d1f6137d Mon Sep 17 00:00:00 2001 From: Nick Krichevsky Date: Sun, 27 Dec 2020 14:36:29 -0500 Subject: [PATCH] Refactor move to take a number of cups to move in day 23 --- day23/day23.cpp | 73 ++++++++++++------------------------------------- 1 file changed, 17 insertions(+), 56 deletions(-) diff --git a/day23/day23.cpp b/day23/day23.cpp index e319498..98ba3e9 100644 --- a/day23/day23.cpp +++ b/day23/day23.cpp @@ -131,86 +131,45 @@ class CupGraph { CupGraph::const_iterator(*this, start), CupGraph::const_iterator(*this, CupGraph::const_iterator::END)); } - /** - * Move the cup at key to be clockwise to dest - * - * **This is not used in the final solution, but is kept for posterity** - * - * @param key The cup to move - * @param dest The cup that will be counterclockwise to key (i.e. key will be clockwise to dest) - */ - void move(int key, int dest) { - auto keyIt = this->neighbors.left.find(key); - auto destIt = this->neighbors.left.find(dest); - if (keyIt == this->neighbors.left.end() || destIt == this->neighbors.left.end()) { - throw std::out_of_range("Item not in map"); - } - - auto counterclockwiseFromKeyIt = this->neighbors.right.find(key); - if (counterclockwiseFromKeyIt == this->neighbors.right.end()) { - throw std::invalid_argument("Key has no counterclockwise neighbor"); - } - - int clockwiseFromKey = keyIt->second; - int clockwiseFromDest = destIt->second; - int counterclockwiseFromKey = counterclockwiseFromKeyIt->second; - // Unfortunately, using replace doesn't work because we expect that each side has exactly one of each element, - // so doing this shuffle is not possible with replace, without some serious edgecasing. - this->neighbors.right.erase(key); - this->neighbors.left.erase(key); - this->neighbors.left.erase(dest); - - // Stitch the counterclockwise neighbor to be the one clockwise to keyIt - this->neighbors.left.insert({counterclockwiseFromKey, clockwiseFromKey}); - // Stitching the key to have the same neighbor as the destination did - this->neighbors.left.insert({key, clockwiseFromDest}); - // Stitch the destination to be adjacent to the key - this->neighbors.left.insert({dest, key}); - } - /** * The same as move, but moves key, key's neighbor, and key's neighbor's neighbor, at once * @param key The key to move * @param dest The destination to move to */ - void move3(int key, int dest) { + void move(int key, int dest, int numToMove) { auto keyIt = this->neighbors.left.find(key); auto destIt = this->neighbors.left.find(dest); if (keyIt == this->neighbors.left.end() || destIt == this->neighbors.left.end()) { throw std::out_of_range("Item not in map"); } - // Get the two elements after the key. - auto keyIt2 = this->neighbors.left.find(keyIt->second); - if (keyIt2 == this->neighbors.left.end()) { - throw "Invalid state: elements are not linked together"; - } - - auto keyIt3 = this->neighbors.left.find(keyIt2->second); - if (keyIt3 == this->neighbors.left.end()) { - throw "Invalid state: elements are not linked together"; - } - auto counterclockwiseFromKeyIt = this->neighbors.right.find(key); if (counterclockwiseFromKeyIt == this->neighbors.right.end()) { throw std::invalid_argument("Key has no counterclockwise neighbor"); } - int key3 = keyIt3->first; - int clockwiseFromKey3 = keyIt3->second; + auto endOfRangeIt = keyIt; + for (int i = 1; i < numToMove; i++) { + endOfRangeIt = this->neighbors.left.find(endOfRangeIt->second); + if (endOfRangeIt == this->neighbors.left.end()) { + throw "Invalid state: elements are not linked together"; + } + } + + int endOfRangeKey = endOfRangeIt->first; + int clockwiseFromEndOfRangeKey = endOfRangeIt->second; int clockwiseFromDest = destIt->second; int counterclockwiseFromKey = counterclockwiseFromKeyIt->second; // Unfortunately, using replace doesn't work because we expect that each side has exactly one of each element, // so doing this shuffle is not possible with replace, without some serious edgecasing. this->neighbors.right.erase(key); - this->neighbors.left.erase(key3); - // this->neighbors.left.erase(key); + this->neighbors.left.erase(endOfRangeKey); this->neighbors.left.erase(dest); // Stitch the counterclockwise neighbor to be the one clockwise to the final element in our range - this->neighbors.left.insert({counterclockwiseFromKey, clockwiseFromKey3}); + this->neighbors.left.insert({counterclockwiseFromKey, clockwiseFromEndOfRangeKey}); // Stitching the final element of our range to have the same neighbor as the destination did - this->neighbors.left.insert({key3, clockwiseFromDest}); + this->neighbors.left.insert({endOfRangeKey, clockwiseFromDest}); // Stitch the destination to be adjacent to the key this->neighbors.left.insert({dest, key}); } @@ -362,7 +321,9 @@ void runGame(int startingCup, CupGraph &graph, int numIterations) { // Since we move three at a time, we only need to get the first picked up cup int firstPickedUpCup = graph.getNext(currentCup); - graph.move3(firstPickedUpCup, destinationCup); + using tupleType = typename std::result_of::type; + constexpr auto numCupsToMove = std::tuple_size::value; + graph.move(firstPickedUpCup, destinationCup, numCupsToMove); currentCup = graph.getNext(currentCup); }