diff --git a/day23/Makefile b/day23/Makefile new file mode 100644 index 0000000..9fefeaa --- /dev/null +++ b/day23/Makefile @@ -0,0 +1,15 @@ +CC=g++ +BIN_NAME=day23 +CCFLAGS=-o $(BIN_NAME) -g -std=c++17 +LDFLAGS= + +.PHONY: all, clean + +all: $(BIN_NAME) + +clean: + rm -f $(BIN_NAME) + +$(BIN_NAME): day23.cpp + $(CC) $(CCFLAGS) $(LDFLAGS) day23.cpp + diff --git a/day23/day23.cpp b/day23/day23.cpp new file mode 100644 index 0000000..3b7066c --- /dev/null +++ b/day23/day23.cpp @@ -0,0 +1,123 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +constexpr int NUM_CRAB_TURNS = 100; + +std::vector readInput(const std::string &filename) { + std::vector input; + std::string line; + std::ifstream file(filename); + while (std::getline(file, line)) { + input.push_back(line); + } + + return input; +} + +std::vector makeCupList(const std::string &inputLine) { + std::vector cups; + std::transform(inputLine.cbegin(), inputLine.cend(), std::back_inserter(cups), [](char rawNum) { + if (rawNum < '0' || rawNum > '9') { + throw std::invalid_argument("Not numeric"); + } + + return rawNum - '0'; + }); + + return cups; +} + +std::tuple getPickedUpCups(int currentCupIndex, const std::vector &cupList) { + return std::make_tuple( + cupList.at((currentCupIndex + 1) % cupList.size()), + cupList.at((currentCupIndex + 2) % cupList.size()), + cupList.at((currentCupIndex + 3) % cupList.size())); +} + +template +bool tupleContainsItem(Tuple tuple, ValueType value) { + return boost::hana::any_of(tuple, [value](ValueType item) { return item == value; }); +} + +int findDestinationCup(int currentCupIndex, const std::vector &cupList) { + int currentCup = cupList.at(currentCupIndex); + std::tuple pickedUpCups = getPickedUpCups(currentCupIndex, cupList); + auto cupMinMaxIterators = std::minmax_element(cupList.cbegin(), cupList.cend()); + std::pair cupMinMax = std::make_pair(*(cupMinMaxIterators.first), *(cupMinMaxIterators.second)); + + int destinationCup = currentCup; + do { + destinationCup--; + if (destinationCup < cupMinMax.first) { + destinationCup = cupMinMax.second; + } + } while (tupleContainsItem(pickedUpCups, destinationCup)); + + return destinationCup; +} + +std::string makeFullCupLabel(const std::vector cups) { + std::string output; + output.reserve(cups.size() - 1); + auto startIt = std::find(cups.cbegin(), cups.cend(), 1); + for (int i = (startIt - cups.begin() + 1) % cups.size(); cups.at(i) != 1; i = (i + 1) % cups.size()) { + output.push_back(cups.at(i) + '0'); + } + + return output; +} + +std::string part1(const std::string &inputLine) { + std::vector cups = makeCupList(inputLine); + int currentCup = cups.front(); + for (int i = 0; i < NUM_CRAB_TURNS; i++) { + auto currentCupIt = std::find(cups.cbegin(), cups.cend(), currentCup); + int destinationCup = findDestinationCup(currentCupIt - cups.cbegin(), cups); + std::tuple pickedUpCups = getPickedUpCups(currentCupIt - cups.cbegin(), cups); + + // Perform the cup moves + std::vector newCups; + newCups.reserve(cups.size()); + for (int cup : cups) { + if (tupleContainsItem(pickedUpCups, cup)) { + continue; + } + + newCups.push_back(cup); + // Copy the existing cups over + if (cup == destinationCup) { + boost::hana::for_each(pickedUpCups, [&newCups](int item) { newCups.push_back(item); }); + } + } + + // Get the new current cup + cups = std::move(newCups); + currentCupIt = std::find(cups.cbegin(), cups.cend(), currentCup); + if (currentCupIt + 1 == cups.cend()) { + currentCup = cups.front(); + } else { + currentCup = *(currentCupIt + 1); + } + } + + return makeFullCupLabel(cups); +} + +int main(int argc, char *argv[]) { + if (argc != 2) { + std::cerr << argv[0] << " " << std::endl; + return 1; + } + + auto input = readInput(argv[1]); + + std::cout << part1(input.at(0)) << std::endl; +}