diff --git a/2023/CMakeLists.txt b/2023/CMakeLists.txt index b9edc31..de68f2f 100644 --- a/2023/CMakeLists.txt +++ b/2023/CMakeLists.txt @@ -10,7 +10,7 @@ link_directories(../GenericLib/lib) if (DEFINED AOC_DAY) add_subdirectory(${AOC_DAY}) else() - set(AOC_DAYS Day01;Day02;Day03;Day04;Day05;Day06) + set(AOC_DAYS Day01;Day02;Day03;Day04;Day05;Day06;Day07) foreach(DAY IN ITEMS ${AOC_DAYS}) add_subdirectory(${DAY}) endforeach() diff --git a/2023/Day07/CMakeLists.txt b/2023/Day07/CMakeLists.txt new file mode 100644 index 0000000..a462340 --- /dev/null +++ b/2023/Day07/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(Day07 main.cpp) +target_link_libraries(Day07 AoC_GenericLib_static) diff --git a/2023/Day07/main.cpp b/2023/Day07/main.cpp new file mode 100644 index 0000000..54df28e --- /dev/null +++ b/2023/Day07/main.cpp @@ -0,0 +1,316 @@ +#include +#include +#include + +#include +#include +#include +#include + +#include "FileHandler.hpp" +#include "StringParser.hpp" + +void outputVector(const std::vector & src) +{ + std::cout << "Vector contents:" << std::endl; + for (const auto & line : src) + { + std::cout << "\t" << line << std::endl; + } + std::cout << std::endl; +} + +void rank(std::vector & src, bool part2 = false) +{ + // order: A K Q J T 9 8 7 6 5 4 3 2 + std::map rankedCards = { {'A', 12}, {'K', 11}, {'Q', 10}, {'J', 9}, {'T', 8}, {'9', 7}, {'8', 6}, {'7', 5}, {'6', 4}, {'5', 3}, {'4', 2}, {'3', 1}, {'2', 0} }; + if (part2) + { + rankedCards['J'] = -1; // Joker is lowest ranked card + } + + for (auto it = src.begin(); it != src.end(); ++it) + { + for (auto it2 = src.begin(); it2 != it; it2++) + { + for (int i = 0; i < 5; i++) + { + if (rankedCards[(*it)[i]] > rankedCards[(*it2)[i]]) + { + std::iter_swap(it, it2); + break; + } + else if (rankedCards[(*it)[i]] < rankedCards[(*it2)[i]]) + { + break; + } + } + } + } +} + +long long part1(const std::vector & input) +{ + long long result = 0; + std::map handsAndBids; + std::vector fiveOfAKinds; + std::vector fourOfAKinds; + std::vector fullHouses; + std::vector threeOfAKinds; + std::vector twoPairs; + std::vector onePairs; + std::vector highCards; + + for (const std::string & line : input) + { + std::vector parsed = StringParser::toVector(line, " "); + const std::string currentCard = parsed[0]; + handsAndBids[currentCard] = std::stoi(parsed[1]); + std::map countPerCard; + for (const char & card : currentCard) + { + countPerCard[card]++; + } + + switch (countPerCard.size()) + { + case 5: + { + highCards.push_back(currentCard); + break; + } + case 4: + { + onePairs.push_back(currentCard); + break; + } + case 3: + { + for (const std::pair & cardAndCount : countPerCard) + { + if (cardAndCount.second == 3) + { + threeOfAKinds.push_back(currentCard); + break; + } + else if (cardAndCount.second == 2) + { + twoPairs.push_back(currentCard); + break; + } + } + break; + } + case 2: + { + for (const std::pair & cardAndCount : countPerCard) + { + if (cardAndCount.second == 4) + { + fourOfAKinds.push_back(currentCard); + break; + } + else if (cardAndCount.second == 3) + { + fullHouses.push_back(currentCard); + break; + } + } + break; + } + case 1: + { + fiveOfAKinds.push_back(currentCard); + break; + } + } + } + + rank(fiveOfAKinds); + rank(fourOfAKinds); + rank(fullHouses); + rank(threeOfAKinds); + rank(twoPairs); + rank(onePairs); + rank(highCards); + + std::vector completeRankedList; + completeRankedList.insert(completeRankedList.end(), fiveOfAKinds.begin(), fiveOfAKinds.end()); + completeRankedList.insert(completeRankedList.end(), fourOfAKinds.begin(), fourOfAKinds.end()); + completeRankedList.insert(completeRankedList.end(), fullHouses.begin(), fullHouses.end()); + completeRankedList.insert(completeRankedList.end(), threeOfAKinds.begin(), threeOfAKinds.end()); + completeRankedList.insert(completeRankedList.end(), twoPairs.begin(), twoPairs.end()); + completeRankedList.insert(completeRankedList.end(), onePairs.begin(), onePairs.end()); + completeRankedList.insert(completeRankedList.end(), highCards.begin(), highCards.end()); + + for (int i = 0; i < completeRankedList.size(); i++) + { + result += ((completeRankedList.size() - i) * handsAndBids[completeRankedList[i]]); + } + + return result; +} + +unsigned long long part2(const std::vector & input) +{ + unsigned long long result = 0; + + std::map handsAndBids; + std::vector fiveOfAKinds; + std::vector fourOfAKinds; + std::vector fullHouses; + std::vector threeOfAKinds; + std::vector twoPairs; + std::vector onePairs; + std::vector highCards; + + for (const std::string & line : input) + { + std::vector parsed = StringParser::toVector(line, " "); + const std::string currentCard = parsed[0]; + handsAndBids[currentCard] = std::stoi(parsed[1]); + std::map countPerCard; + for (const char & card : currentCard) + { + countPerCard[card]++; + } + + if (countPerCard.size() == 5) + { + if (countPerCard['J'] == 1) + { + onePairs.push_back(currentCard); + } + else + { + highCards.push_back(currentCard); + } + } + else if (countPerCard.size() == 4) + { + if (countPerCard['J'] == 1 || countPerCard['J'] == 2) + { + threeOfAKinds.push_back(currentCard); + } + else + { + onePairs.push_back(currentCard); + } + } + else if (countPerCard.size() == 3) + { + for (const std::pair & cardAndCount : countPerCard) + { + + if (cardAndCount.second == 3) + { + if (cardAndCount.first == 'J' || countPerCard['J'] == 1) + { + fourOfAKinds.push_back(currentCard); + } + else + { + threeOfAKinds.push_back(currentCard); + } + break; + } + else if (cardAndCount.second == 2) + { + if (cardAndCount.first == 'J' || countPerCard['J'] == 2) + { + fourOfAKinds.push_back(currentCard); + } + else if (countPerCard['J'] == 1) + { + fullHouses.push_back(currentCard); + } + else + { + twoPairs.push_back(currentCard); + } + break; + } + } + } + else if (countPerCard.size() == 2) + { + for (const std::pair & cardAndCount : countPerCard) + { + if (cardAndCount.second == 4) + { + if (cardAndCount.first == 'J' || countPerCard['J'] == 1) + { + fiveOfAKinds.push_back(currentCard); + } + else + { + fourOfAKinds.push_back(currentCard); + } + break; + } + else if (cardAndCount.second == 3) + { + if (cardAndCount.first == 'J' || countPerCard['J'] == 2) + { + fiveOfAKinds.push_back(currentCard); + } + else + { + fullHouses.push_back(currentCard); + } + break; + } + } + } + else if (countPerCard.size() == 1) + { + fiveOfAKinds.push_back(currentCard); + } + } + + rank(fiveOfAKinds, true); + rank(fourOfAKinds, true); + rank(fullHouses, true); + rank(threeOfAKinds, true); + rank(twoPairs, true); + rank(onePairs, true); + rank(highCards, true); + + std::vector completeRankedList; + completeRankedList.insert(completeRankedList.end(), fiveOfAKinds.begin(), fiveOfAKinds.end()); + completeRankedList.insert(completeRankedList.end(), fourOfAKinds.begin(), fourOfAKinds.end()); + completeRankedList.insert(completeRankedList.end(), fullHouses.begin(), fullHouses.end()); + completeRankedList.insert(completeRankedList.end(), threeOfAKinds.begin(), threeOfAKinds.end()); + completeRankedList.insert(completeRankedList.end(), twoPairs.begin(), twoPairs.end()); + completeRankedList.insert(completeRankedList.end(), onePairs.begin(), onePairs.end()); + completeRankedList.insert(completeRankedList.end(), highCards.begin(), highCards.end()); + + for (int i = 0; i < completeRankedList.size(); i++) + { + result += ((completeRankedList.size() - i) * handsAndBids[completeRankedList[i]]); + } + + return result; +} + +int main(void) +{ + FileHandler fileHandlerTest("input-files/2023/day07_testinput.txt"); + std::vector testInput = StringParser::toVector(fileHandlerTest.getBuffer(), "\n"); + assert(part1(testInput) == 6440); + + FileHandler fileHandler("input-files/2023/day07.txt"); + std::vector input = StringParser::toVector(fileHandler.getBuffer(), "\n"); + + auto t_begin = std::chrono::high_resolution_clock::now(); + std::cout << "Day 7, puzzle 1: " << std::flush << part1(input) << std::endl; + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "Completed in: " << std::chrono::duration(t_end - t_begin).count() << " ms" << std::endl; + + assert(part2(testInput) == 5905); + + t_begin = std::chrono::high_resolution_clock::now(); + std::cout << "Day 7, puzzle 2: " << std::flush << part2(input) << std::endl; + t_end = std::chrono::high_resolution_clock::now(); + std::cout << "Completed in: " << std::chrono::duration(t_end - t_begin).count() << " ms" << std::endl; +} \ No newline at end of file diff --git a/input-files b/input-files index 108bf2f..12a28c6 160000 --- a/input-files +++ b/input-files @@ -1 +1 @@ -Subproject commit 108bf2feafa0c1d5dcac85c3784d7fc7b0c8511b +Subproject commit 12a28c65cb30ee635534044c5c65ed7b2ea2ae1f diff --git a/run_aoc_year.sh b/run_aoc_year.sh index dbe57cd..0adec60 100755 --- a/run_aoc_year.sh +++ b/run_aoc_year.sh @@ -1,6 +1,7 @@ #!/bin/bash cd $1 +rm -rf _build cmake -H. -B_build -DCMAKE_BUILD_TYPE=Release cmake --build _build --config Release cd ..