From 4abe71ccf5ddec50e31231cb5177288570f81e84 Mon Sep 17 00:00:00 2001 From: Nick Krichevsky Date: Sun, 27 Dec 2020 04:24:21 -0500 Subject: [PATCH] Optimize day 23 by moving three cups at a time --- day23/day23.cpp | 57 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/day23/day23.cpp b/day23/day23.cpp index 16abadc..ce6b838 100644 --- a/day23/day23.cpp +++ b/day23/day23.cpp @@ -138,6 +138,9 @@ class CupGraph { /** * 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) */ @@ -170,6 +173,53 @@ class CupGraph { 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) { + 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; + 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(dest); + + // Stitch the counterclockwise neighbor to be the one clockwise to the final element in our range + this->neighbors.left.insert({counterclockwiseFromKey, clockwiseFromKey3}); + // Stitching the final element of our range to have the same neighbor as the destination did + this->neighbors.left.insert({key3, clockwiseFromDest}); + // Stitch the destination to be adjacent to the key + this->neighbors.left.insert({dest, key}); + } + /** * Get the neighbor of this element * @param n The item to get the neighbor @@ -316,11 +366,10 @@ void runGame(int startingCup, CupGraph &graph, int numIterations) { int currentCup = startingCup; for (int i = 0; i < numIterations; i++) { int destinationCup = findDestinationCup(currentCup, graph, cupMinMax.first, cupMinMax.second); - std::tuple pickedUpCups = getPickedUpCups(currentCup, graph); - graph.move(std::get<0>(pickedUpCups), destinationCup); - graph.move(std::get<1>(pickedUpCups), std::get<0>(pickedUpCups)); - graph.move(std::get<2>(pickedUpCups), std::get<1>(pickedUpCups)); + // Since we move three at a time, we only need to get the first picked up cup + int firstPickedUpCup = graph.getNext(currentCup); + graph.move3(graph.getNext(currentCup), destinationCup); currentCup = graph.getNext(currentCup); }