#include #include #include #include #include #include #include #include enum class Color { Red, Green, Blue, Yellow }; std::string colorToString(Color c) { switch (c) { case Color::Red: return "Red"; case Color::Green: return "Green"; case Color::Blue: return "Blue"; case Color::Yellow: return "Yellow"; default: return "Unknown"; } } struct Card { Color color; int number; void print() const { fmt::color fmt_color; switch (color) { case Color::Red: fmt_color = fmt::color::red; break; case Color::Green: fmt_color = fmt::color::green; break; case Color::Blue: fmt_color = fmt::color::blue; break; case Color::Yellow: fmt_color = fmt::color::yellow; break; } fmt::print(fmt::fg(fmt_color), "[{} {}] ", colorToString(color), number); } bool matches(const Card& other) const { return color == other.color || number == other.number; } }; std::vector createDeck() { std::vector deck; for (int c = 0; c < 4; ++c) { for (int n = 0; n <= 9; ++n) { // Two of each card (except 0 which appears once) deck.push_back({ static_cast(c), n }); if (n != 0) deck.push_back({ static_cast(c), n }); } } std::random_device rd; std::mt19937 g(rd()); // Mersenne Twister random number generator for (int i = 0; i < 10; ++i) { std::shuffle(deck.begin(), deck.end(), g); } return deck; } Card drawCard(std::vector& deck) { if (deck.empty()) throw std::runtime_error("Deck is empty!"); Card c = deck.back(); deck.pop_back(); return c; } void printHand(const std::vector& hand) { for (size_t i = 0; i < hand.size(); ++i) { fmt::print("[{}] ", i); hand[i].print(); fmt::print("\n"); } } bool hasPlayableCard(const std::vector& hand, const Card& topCard) { for (const auto& card : hand) { if (card.matches(topCard)) return true; } return false; } void clearScreen() { #ifdef _WIN32 std::system("cls"); #else std::system("clear"); #endif } std::string rightAlign(std::string text, size_t width = 50) { if (text.length() >= width) return text; return std::string(width - text.length(), ' ') + text; } int main() { auto deck = createDeck(); std::vector playerHand, aiHand; for (int i = 0; i < 7; ++i) { playerHand.push_back(drawCard(deck)); aiHand.push_back(drawCard(deck)); } Card topCard = drawCard(deck); bool playerTurn = true; while (true) { clearScreen(); // Prepare UNO! labels if needed std::string playerUno = (playerHand.size() == 1) ? rightAlign(fmt::format(fmt::emphasis::bold, "YOU: UNO!")) : ""; std::string aiUno = (aiHand.size() == 1) ? rightAlign(fmt::format(fmt::emphasis::bold, "AI: UNO!")) : ""; // Print top card and UNO! indicator fmt::print("Top card: "); topCard.print(); if (!playerUno.empty()) fmt::print("{}", playerUno); if (!aiUno.empty()) fmt::print("{}", aiUno); fmt::print("\n"); fmt::print("AI has {} card(s).\n\n", aiHand.size()); if (playerHand.empty()) { fmt::print(fmt::fg(fmt::color::green), "You win!\n"); break; } if (aiHand.empty()) { fmt::print(fmt::fg(fmt::color::red), "AI wins!\n"); break; } if (deck.empty()) { fmt::print(fmt::fg(fmt::color::gray), "Deck is empty! Reshuffling...\n"); deck = createDeck(); // not perfect, doesn’t exclude cards in play } if (playerTurn) { fmt::print(fmt::fg(fmt::color::cyan), "Your turn:\n"); printHand(playerHand); if (!hasPlayableCard(playerHand, topCard)) { fmt::print("No playable card. Press 'd' to draw: "); char input; std::cin >> input; if (input == 'd' || input == 'D') { Card drawn = drawCard(deck); playerHand.push_back(drawn); fmt::print("You drew: "); drawn.print(); fmt::print("\nPress Enter to continue..."); std::cin.ignore(std::numeric_limits::max(), '\n'); std::cin.get(); std::cin.putback('\n'); playerTurn = false; continue; } } else { while (true) { fmt::print("Choose card index to play or 'd' to draw: "); std::string input; std::cin >> input; if (input == "d" || input == "D") { Card drawn = drawCard(deck); playerHand.push_back(drawn); fmt::print("You drew: "); drawn.print(); fmt::print("\nPress Enter to continue..."); std::cin.ignore(std::numeric_limits::max(), '\n'); std::cin.get(); std::cin.putback('\n'); playerTurn = false; break; } try { int choice = std::stoi(input); if (choice >= 0 && choice < static_cast(playerHand.size())) { if (playerHand[choice].matches(topCard)) { topCard = playerHand[choice]; playerHand.erase(playerHand.begin() + choice); playerTurn = false; break; } else { fmt::print("Invalid move. You must match color or number.\n"); } } else { fmt::print("Invalid index.\n"); } } catch (...) { fmt::print("Invalid input.\n"); } } } } else { fmt::print(fmt::fg(fmt::color::yellow), "AI's turn...\n"); bool played = false; for (size_t i = 0; i < aiHand.size(); ++i) { if (aiHand[i].matches(topCard)) { topCard = aiHand[i]; aiHand.erase(aiHand.begin() + i); fmt::print("AI played: "); topCard.print(); fmt::print("\n"); played = true; break; } } if (!played) { aiHand.push_back(drawCard(deck)); fmt::print("AI drew a card.\n"); } fmt::print("Press Enter to continue..."); std::cin.ignore(std::numeric_limits::max(), '\n'); std::cin.get(); playerTurn = true; } } return 0; }