diff --git a/2023/puzzle-07-01.cc b/2023/puzzle-07-01.cc new file mode 100644 index 0000000..4a837a0 --- /dev/null +++ b/2023/puzzle-07-01.cc @@ -0,0 +1,144 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using UInt = std::uint64_t; +using Cards = std::array; + +enum class HandType +{ + high_card, + one_pair, + two_pair, + three, + full_house, + four, + five +}; + +auto operator<<(std::ostream& os, HandType type) -> std::ostream& +{ + switch (type) { + case HandType::high_card: + return os << "High card"; + case HandType::one_pair: + return os << "One pair"; + case HandType::two_pair: + return os << "Two pair"; + case HandType::three: + return os << "Three of a kind"; + case HandType::full_house: + return os << "Full house"; + case HandType::four: + return os << "Four of a kind"; + case HandType::five: + return os << "Five of a kind"; + } +} + +[[nodiscard]] auto operator<=>(HandType lhs, HandType rhs) -> std::strong_ordering +{ + auto const l{static_cast>(lhs)}; + auto const r{static_cast>(rhs)}; + return l <=> r; +} + +auto operator<<(std::ostream& os, Cards const& cards) -> std::ostream& +{ + for (auto const c : cards) { os << c; } + return os; +} + +[[nodiscard]] auto operator<=>(Cards const& lhs, Cards const& rhs) -> std::strong_ordering +{ + static auto const* order = "23456789TJQKA"; + for (auto lhs_it{lhs.begin()}, rhs_it{rhs.begin()}; lhs_it != lhs.end(); ++lhs_it, ++rhs_it) { + if (auto l = std::strchr(order, *lhs_it), r = std::strchr(order, *rhs_it); l != r) { + return l <=> r; + } + } + return std::strong_ordering::equal; +} + +[[nodiscard]] auto classify(Cards const& cards) -> HandType +{ + std::map holding; + for (auto card : cards) { holding.insert({card, 0}).first->second++; } + unsigned max_count{1}; + unsigned pairs_seen{0}; + for (auto [card, count] : holding) { + max_count = std::max(count, max_count); + if (count == 2) { ++pairs_seen; } + } + if (max_count == 5) { return HandType::five; } + if (max_count == 4) { return HandType::four; } + if (max_count == 3 && pairs_seen == 1) { return HandType::full_house; } + if (max_count == 3) { return HandType::three; } + if (max_count == 2 && pairs_seen == 2) { return HandType::two_pair; } + if (max_count == 2 && pairs_seen == 1) { return HandType::one_pair; } + assert(max_count == 1); + return HandType::high_card; +} + +struct Hand +{ + explicit Hand(std::string_view line) + : cards_({line[0], line[1], line[2], line[3], line[4]}), type_(classify(cards_)), + bid_(std::strtoul(line.data() + 5, nullptr, 10)) + { + } + + [[nodiscard]] auto operator<=>(Hand const& rhs) const -> std::strong_ordering + { + auto type_order = type_ <=> rhs.type_; + if (type_order != std::strong_ordering::equal) { return type_order; } + return cards_ <=> rhs.cards_; + } + + Cards cards_; + HandType type_; + UInt bid_; +}; + +auto operator<<(std::ostream& os, Hand const& hand) -> std::ostream& +{ + return os << std::setw(16) << hand.type_ << ' ' << hand.cards_ << ' ' << std::setw(5) << hand. + bid_; +} + + +auto main() -> int try { + std::string line; + std::vector hands; + + while (std::getline(std::cin, line)) { + hands.emplace_back(line); + } + + std::sort(hands.begin(), hands.end()); + + UInt score{0}; + for (std::size_t i{0}; i != hands.size(); ++i) { + score += (i + 1) * hands[i].bid_; + std::cout << std::setw(5) << i + 1 << ' ' << hands[i] << ' ' << score << '\n'; + } + + std::cout << "Score: " << score; + + return EXIT_SUCCESS; +} +catch (...) { + std::cerr << "Uncaught exception.\n"; + return EXIT_FAILURE; +} diff --git a/2023/puzzle-07-02.cc b/2023/puzzle-07-02.cc new file mode 100644 index 0000000..2d1113c --- /dev/null +++ b/2023/puzzle-07-02.cc @@ -0,0 +1,171 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using UInt = std::uint64_t; +using Cards = std::array; + +enum class HandType +{ + high_card, + one_pair, + two_pair, + three, + full_house, + four, + five +}; + +auto operator<<(std::ostream& os, HandType const type) -> std::ostream& +{ + switch (type) { + case HandType::high_card: + return os << "High card"; + case HandType::one_pair: + return os << "One pair"; + case HandType::two_pair: + return os << "Two pair"; + case HandType::three: + return os << "Three of a kind"; + case HandType::full_house: + return os << "Full house"; + case HandType::four: + return os << "Four of a kind"; + case HandType::five: + return os << "Five of a kind"; + } +} + +[[nodiscard]] auto operator<=>(HandType lhs, HandType rhs) -> std::strong_ordering +{ + auto const l{static_cast>(lhs)}; + auto const r{static_cast>(rhs)}; + return l <=> r; +} + +auto operator<<(std::ostream& os, Cards const& cards) -> std::ostream& +{ + for (auto const c : cards) { os << c; } + return os; +} + +[[nodiscard]] auto operator<=>(Cards const& lhs, Cards const& rhs) -> std::strong_ordering +{ + static auto const* order = "J23456789TQKA"; + for (auto lhs_it{lhs.begin()}, rhs_it{rhs.begin()}; lhs_it != lhs.end(); ++lhs_it, ++rhs_it) { + if (auto l = std::strchr(order, *lhs_it), r = std::strchr(order, *rhs_it); l != r) { + return l <=> r; + } + } + return std::strong_ordering::equal; +} + +[[nodiscard]] auto classify(Cards const& cards) -> HandType +{ + std::map holding; + for (auto card : cards) { holding.insert({card, 0}).first->second++; } + unsigned max_count{1}; + unsigned pairs_seen{0}; + unsigned jokers_seen{0}; + for (auto [card, count] : holding) { + max_count = std::max(count, max_count); + if (count == 2) { ++pairs_seen; } + if (card == 'J') { jokers_seen = count; } + } + if (max_count == 5 || (max_count != jokers_seen && max_count + jokers_seen == 5) || + (max_count == 4 && jokers_seen == 4) || + (max_count == 3 && jokers_seen == 3 && pairs_seen == 1)) { + // xxxxx, xxxxJ, xxxJJ, xxJJJ, xJJJJ, JJJJJ + return HandType::five; + } + assert(max_count < 5); + if (max_count == 4 || (max_count != jokers_seen && max_count + jokers_seen == 4) || ( + pairs_seen == 2 && jokers_seen == 2) || + (max_count == 3 && jokers_seen == 3)) { + // xxxx., xxxJ., xxJJ., xJJJ., JJJJ. + return HandType::four; + } + assert(max_count < 4); + if ((max_count == 3 && pairs_seen == 1) || (pairs_seen == 2 && jokers_seen == 1)) { + // xxxyy, xxyyJ, JJJxx, JJxx. + return HandType::full_house; + } + if (max_count == 3 || (pairs_seen == 1 && jokers_seen == 1) || jokers_seen == 2) { + // xxx.., JJJ.., xxJ.., JJ... + return HandType::three; + } + assert(max_count < 3); + if (max_count == 2 && pairs_seen == 2) { + assert(jokers_seen == 0); + return HandType::two_pair; + } + if (max_count == 2 && pairs_seen == 1 || (max_count == 1 && jokers_seen == 1)) { + return HandType::one_pair; + } + assert(max_count == 1); + return HandType::high_card; +} + +struct Hand +{ + explicit Hand(std::string_view const line) + : cards_({line[0], line[1], line[2], line[3], line[4]}), type_(classify(cards_)), + bid_(std::strtoul(line.data() + 5, nullptr, 10)) + { + } + + [[nodiscard]] auto operator<=>(Hand const& rhs) const -> std::strong_ordering + { + if (auto const type_order = type_ <=> rhs.type_; type_order != std::strong_ordering::equal) { + return type_order; + } + return cards_ <=> rhs.cards_; + } + + Cards cards_; + HandType type_; + UInt bid_; +}; + +auto operator<<(std::ostream& os, Hand const& hand) -> std::ostream& +{ + return os << std::setw(16) << hand.type_ << ' ' << hand.cards_ << ' ' << std::setw(5) << hand. + bid_; +} + + +auto main() -> int try { + std::string line; + std::vector hands; + + while (std::getline(std::cin, line)) { + hands.emplace_back(line); + } + + std::sort(hands.begin(), hands.end()); + + UInt score{0}; + for (std::size_t i{0}; i != hands.size(); ++i) { + score += (i + 1) * hands[i].bid_; + std::cout << std::setw(5) << i + 1 << ' ' << hands[i] << ' ' << score << '\n'; + } + + std::cout << "Score: " << score; + + return EXIT_SUCCESS; +} +catch (...) { + std::cerr << "Uncaught exception.\n"; + return EXIT_FAILURE; +}