From efd8be82079fb6fc079f7edd3b89ac0d9435c448 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Thu, 7 Dec 2023 07:56:56 +0200 Subject: [PATCH] AOC2023: implement day7 --- userspace/aoc2023/CMakeLists.txt | 1 + userspace/aoc2023/day7/CMakeLists.txt | 22 ++++ userspace/aoc2023/day7/main.cpp | 167 ++++++++++++++++++++++++++ 3 files changed, 190 insertions(+) create mode 100644 userspace/aoc2023/day7/CMakeLists.txt create mode 100644 userspace/aoc2023/day7/main.cpp diff --git a/userspace/aoc2023/CMakeLists.txt b/userspace/aoc2023/CMakeLists.txt index 3a44bc67..1c5f2c67 100644 --- a/userspace/aoc2023/CMakeLists.txt +++ b/userspace/aoc2023/CMakeLists.txt @@ -9,6 +9,7 @@ set(AOC2023_PROJECTS day4 day5 day6 + day7 ) set(BANAN_AOC2023_BIN ${BANAN_BIN}/aoc2023) diff --git a/userspace/aoc2023/day7/CMakeLists.txt b/userspace/aoc2023/day7/CMakeLists.txt new file mode 100644 index 00000000..74e2b825 --- /dev/null +++ b/userspace/aoc2023/day7/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.26) + +project(aoc2023_day7 CXX) + +set(SOURCES + main.cpp +) + +add_executable(aoc2023_day7 ${SOURCES}) +target_compile_options(aoc2023_day7 PUBLIC -O2 -g) +target_link_libraries(aoc2023_day7 PUBLIC libc ban) + +add_dependencies(aoc2023_day7 libc-install ban-install) + +add_custom_target(aoc2023_day7-install + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/aoc2023_day7 ${BANAN_AOC2023_BIN}/day7 + DEPENDS aoc2023_day7 + DEPENDS aoc2023_always +) + +add_dependencies(aoc2023 aoc2023_day7) +add_dependencies(aoc2023-install aoc2023_day7-install) diff --git a/userspace/aoc2023/day7/main.cpp b/userspace/aoc2023/day7/main.cpp new file mode 100644 index 00000000..567c8ba9 --- /dev/null +++ b/userspace/aoc2023/day7/main.cpp @@ -0,0 +1,167 @@ +#include +#include + +#include +#include +#include + +using i64 = int64_t; + +i64 parse_i64(BAN::StringView part) +{ + i64 result = 0; + for (char c : part) + { + if (!isdigit(c)) + break; + result = (result * 10) + (c - '0'); + } + return result; +} + +struct Hand +{ + BAN::String hand; + i64 bid; +}; + +i64 card_score(char card, bool joker) +{ + if (card == 'A') + return 14; + if (card == 'K') + return 13; + if (card == 'Q') + return 12; + if (card == 'J') + return joker ? 1 : 11; + if (card == 'T') + return 10; + + ASSERT('2' <= card && card <= '9'); + return card - '0'; +} + +i64 hand_score_no_type(const Hand& hand, bool joker) +{ + ASSERT(hand.hand.size() == 5); + i64 score = 0; + for (char c : hand.hand) + score = (score << 4) | card_score(c, joker); + ASSERT(score < 1'000'000); + return score; +} + +i64 hand_score(const Hand& hand, bool joker) +{ + ASSERT(hand.hand.size() == 5); + + i64 joker_count = 0; + i64 cnt[26 + 10] {}; + for (char c : hand.hand) + { + if (isdigit(c)) + cnt[c - '0' + 0]++; + else if (c == 'J') + joker_count++; + else + cnt[c - 'A' + 10]++; + } + + if (!joker) + { + cnt['J' - 'A' + 10] = joker_count; + joker_count = 0; + } + + for (size_t i = 0; i < 36; i++) + if (cnt[i] + joker_count >= 5) + return 6'000'000 + hand_score_no_type(hand, joker); + + for (size_t i = 0; i < 36; i++) + if (cnt[i] + joker_count >= 4) + return 5'000'000 + hand_score_no_type(hand, joker); + + for (size_t i = 0; i < 36; i++) + for (size_t j = 0; j < 36; j++) + if (i != j && cnt[i] + joker_count >= 3 && cnt[j] >= 2) + return 4'000'000 + hand_score_no_type(hand, joker); + + for (size_t i = 0; i < 36; i++) + if (cnt[i] + joker_count >= 3) + return 3'000'000 + hand_score_no_type(hand, joker); + + for (size_t i = 0; i < 36; i++) + for (size_t j = 0; j < 36; j++) + if (i != j && cnt[i] + joker_count >= 2 && cnt[j] >= 2) + return 2'000'000 + hand_score_no_type(hand, joker); + + for (size_t i = 0; i < 36; i++) + if (cnt[i] + joker_count >= 2) + return 1'000'000 + hand_score_no_type(hand, joker); + + return hand_score_no_type(hand, joker); +} + +i64 puzzle(FILE* fp, bool joker) +{ + BAN::Vector hands; + + char buffer[128]; + while (fgets(buffer, sizeof(buffer), fp)) + { + BAN::StringView line(buffer); + if (line.size() < 7) + continue; + + Hand hand; + hand.hand = line.substring(0, 5); + hand.bid = parse_i64(line.substring(6)); + MUST(hands.push_back(hand)); + } + + // Very slow sorting algorithm + for (size_t i = 0; i < hands.size(); i++) + { + i64 l_score = hand_score(hands[i], joker); + for (size_t j = i + 1; j < hands.size(); j++) + { + i64 r_score = hand_score(hands[j], joker); + if (r_score > l_score) + { + Hand tmp = BAN::move(hands[i]); + hands[i] = BAN::move(hands[j]); + hands[j] = BAN::move(tmp); + l_score = r_score; + } + } + } + + i64 score = 0; + for (size_t i = 0; i < hands.size(); i++) + score += (hands.size() - i) * hands[i].bid; + return score; +} + +int main(int argc, char** argv) +{ + const char* file_path = "/usr/share/aoc2023/day7_input.txt"; + + if (argc >= 2) + file_path = argv[1]; + + FILE* fp = fopen(file_path, "r"); + if (fp == nullptr) + { + perror("fopen"); + return 1; + } + + printf("puzzle1: %lld\n", puzzle(fp, false)); + + fseek(fp, 0, SEEK_SET); + + printf("puzzle2: %lld\n", puzzle(fp, true)); + + fclose(fp); +}