UNO

SunnyLHY 2026-05-23 19:12:04

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <ctime>
#include <cstdlib>
#include <thread> // 用于增加一点AI思考的停顿感

using namespace std;

// 定义颜色枚举
enum Color { RED, YELLOW, BLUE, GREEN, BLACK };

// 卡牌结构体
struct Card {
    Color color;
    string value; // 存储 "0"-"9", "Skip", "Reverse", "+2", "Wild", "+4"

    string getColorStr() const {
        switch (color) {
            case RED: return "红色";
            case YELLOW: return "黄色";
            case BLUE: return "蓝色";
            case GREEN: return "绿色";
            case BLACK: return "黑色";
            default: return "";
        }
    }

    void display() const {
        cout << "[" << getColorStr() << " " << value << "]";
    }
};

// 玩家类
class Player {
public:
    string name;
    vector<Card> hand;

    Player(string n) : name(n) {}

    void drawCard(const Card& card) {
        hand.push_back(card);
    }

    void showHand() const {
        cout << name << " 的手牌: ";
        for (size_t i = 0; i < hand.size(); ++i) {
            cout << i + 1 << ".";
            hand[i].display();
            cout << " ";
        }
        cout << endl;
    }
};

// 游戏主类
class UnoGame {
private:
    vector<Card> deck;
    vector<Card> discardPile;
    vector<Player> players;
    int currentPlayerIdx;
    int direction; // 1为顺时针,-1为逆时针

public:
    UnoGame() : currentPlayerIdx(0), direction(1) {
        srand(time(0));
        createDeck();
        // 初始化玩家:1个人类 + 3个AI
        players.emplace_back("");
        players.emplace_back("法国赌神");
        players.emplace_back("给我擦皮鞋");
        players.emplace_back("法修散打");
    }

    // 创建108张标准UNO牌
    void createDeck() {
        // 数字牌 0-9
        for (int c = 0; c < 4; ++c) {
            Color col = static_cast<Color>(c);
            deck.push_back({col, "0"}); // 0只有一张
            for (int i = 1; i <= 9; ++i) {
                deck.push_back({col, to_string(i)});
                deck.push_back({col, to_string(i)}); // 1-9各两张
            }
            // 功能牌
            for (int i = 0; i < 2; ++i) {
                deck.push_back({col, "Skip"});
                deck.push_back({col, "Reverse"});
                deck.push_back({col, "+2"});
            }
        }
        // 万能牌
        for (int i = 0; i < 4; ++i) {
            deck.push_back({BLACK, "Wild"});
            deck.push_back({BLACK, "+4"});
        }
        shuffleDeck();
    }

    void shuffleDeck() {
        random_shuffle(deck.begin(), deck.end());
    }

    void dealCards() {
        for (int i = 0; i < 7; ++i) {
            for (auto& p : players) {
                p.drawCard(deck.back());
                deck.pop_back();
            }
        }
        // 翻开第一张牌,如果是功能牌需特殊处理,这里简化为重新洗牌直到是数字牌
        while (deck.back().color == BLACK || (deck.back().value[0] >= 'A' && deck.back().value[0] <= 'Z')) {
             shuffleDeck();
        }
        discardPile.push_back(deck.back());
        deck.pop_back();
    }

    // 抽牌逻辑
    void drawCards(Player& p, int count) {
        cout << p.name << " 抽取了 " << count << " 张牌!" << endl;
        for (int i = 0; i < count; ++i) {
            if (deck.empty()) reshuffleDiscard();
            if (!deck.empty()) {
                p.drawCard(deck.back());
                deck.pop_back();
            }
        }
    }

    void reshuffleDiscard() {
        if (discardPile.size() <= 1) return;
        Card top = discardPile.back();
        discardPile.pop_back();
        deck = discardPile;
        discardPile.clear();
        discardPile.push_back(top);
        shuffleDeck();
        cout << "牌堆已重洗!" << endl;
    }

    // 检查出牌是否合法
    bool isValidMove(const Card& card, const Card& topCard) {
        if (card.color == BLACK) return true; // 万能牌
        if (card.color == topCard.color) return true;
        if (card.value == topCard.value) return true;
        return false;
    }

    // AI 专属的自动变色逻辑
    void aiChangeColor(Player& current) {
        // 简单策略:统计手牌中哪种颜色最多,就选哪种颜色
        int colorCount[4] = {0}; // 0:红, 1:黄, 2:蓝, 3:绿
        for (const auto& c : current.hand) {
            if (c.color != BLACK) {
                colorCount[c.color]++;
            }
        }
        
        int maxColor = 0;
        for (int i = 1; i < 4; i++) {
            if (colorCount[i] > colorCount[maxColor]) {
                maxColor = i;
            }
        }
        
        discardPile.back().color = static_cast<Color>(maxColor);
        cout << current.name << " 将颜色变更为: " << discardPile.back().getColorStr() << endl;
    }

    // 人类玩家手动变色逻辑
    void changeColor() {
        int colorChoice;
        cout << "请选择一种颜色 (1.红色 2.黄色 3.蓝色 4.绿色): ";
        cin >> colorChoice;
        Color newColor;
        switch (colorChoice) {
            case 1: newColor = RED; break;
            case 2: newColor = YELLOW; break;
            case 3: newColor = BLUE; break;
            case 4: newColor = GREEN; break;
            default: newColor = RED;
        }
        discardPile.back().color = newColor;
        cout << "颜色变更为: " << discardPile.back().getColorStr() << endl;
    }

    // 处理特殊牌效果
    void handleSpecialCard(const Card& card) {
        int nextPlayerIdx = (currentPlayerIdx + direction + players.size()) % players.size();
        
        if (card.value == "Skip") {
            cout << "使用了【跳过】,下家暂停一回合!" << endl;
            currentPlayerIdx = (nextPlayerIdx + direction + players.size()) % players.size();
        } 
        else if (card.value == "Reverse") {
            cout << "使用了【反转】,出牌顺序反转!" << endl;
            direction *= -1;
            currentPlayerIdx = nextPlayerIdx; 
            // 双人模式下反转等于跳过,多人模式下正常反转
            if (players.size() == 2) currentPlayerIdx = (currentPlayerIdx + direction + players.size()) % players.size();
        }
        else if (card.value == "+2") {
            cout << "使用了【+2】,下家罚抽2张并跳过回合!" << endl;
            drawCards(players[nextPlayerIdx], 2);
            currentPlayerIdx = (nextPlayerIdx + direction + players.size()) % players.size();
        }
        else if (card.value == "Wild") {
            cout << "使用了【变色】!";
            if (currentPlayerIdx == 0) changeColor(); // 人类选颜色
            else aiChangeColor(players[currentPlayerIdx]); // AI 自动选颜色
            currentPlayerIdx = nextPlayerIdx;
        }
        else if (card.value == "+4") {
            cout << "使用了【+4】!";
            if (currentPlayerIdx == 0) changeColor();
            else aiChangeColor(players[currentPlayerIdx]);
            drawCards(players[nextPlayerIdx], 4);
            currentPlayerIdx = (nextPlayerIdx + direction + players.size()) % players.size();
        }
        else {
            // 普通牌
            currentPlayerIdx = nextPlayerIdx;
        }
    }

    // 基础版 AI 出牌逻辑
    void playAITurn() {
        Player& current = players[currentPlayerIdx];
        Card& topCard = discardPile.back();

        cout << "\n-----------------------------\n";
        cout << "当前弃牌堆顶牌: ";
        topCard.display();
        cout << endl;
        cout << current.name << " (AI) 正在思考..." << endl;
        
        // 稍微停顿一下,模拟思考
        this_thread::sleep_for(chrono::milliseconds(1000));

        // AI 遍历手牌寻找可出的牌 (简单策略:找到第一张就出)
        int cardIndex = -1;
        for (size_t i = 0; i < current.hand.size(); ++i) {
            if (isValidMove(current.hand[i], topCard)) {
                cardIndex = i;
                break; 
            }
        }

        if (cardIndex != -1) {
            // 出牌成功
            Card selectedCard = current.hand[cardIndex];
            current.hand.erase(current.hand.begin() + cardIndex);
            discardPile.push_back(selectedCard);
            
            cout << current.name << " 打出了: ";
            selectedCard.display();
            cout << endl;

            // UNO 喊话
            if (current.hand.size() == 1) {
                cout << current.name << " 大喊: UNO!!!" << endl;
            }
            if (current.hand.empty()) {
                cout << "\n游戏结束!" << current.name << " 获胜!" << endl;
                exit(0);
            }

            // 处理特殊牌效果
            handleSpecialCard(selectedCard);
        } else {
            // 没有能出的牌,抽一张
            drawCards(current, 1);
            cout << current.name << " 没有可出的牌,选择抽牌。" << endl;
            currentPlayerIdx = (currentPlayerIdx + direction + players.size()) % players.size();
        }
    }

    // 游戏主循环回合
    void playTurn() {
        // 索引 0 是人类玩家,其他是 AI
        if (currentPlayerIdx == 0) {
            Player& current = players[currentPlayerIdx];
            Card& topCard = discardPile.back();

            cout << "\n-----------------------------\n";
            cout << "当前弃牌堆顶牌: ";
            topCard.display();
            cout << endl;
            current.showHand();

            int choice;
            cout << current.name << " 请选择出牌编号 (输入 0 抽牌): ";
            cin >> choice;

            if (choice == 0) {
                drawCards(current, 1);
                // 抽牌后如果能出则允许出,这里简化为直接换人
                currentPlayerIdx = (currentPlayerIdx + direction + players.size()) % players.size();
                return;
            }

            if (choice < 1 || choice > current.hand.size()) {
                cout << "无效输入,请重试。" << endl;
                return; // 不消耗回合
            }

            Card selectedCard = current.hand[choice - 1];

            if (isValidMove(selectedCard, topCard)) {
                // 出牌成功
                current.hand.erase(current.hand.begin() + choice - 1);
                discardPile.push_back(selectedCard);

                // UNO 喊话检测
                if (current.hand.size() == 1) {
                    cout << current.name << " 大喊: UNO!!! (只剩一张牌了)" << endl;
                }
                if (current.hand.empty()) {
                    cout << "\n恭喜 " << current.name << " 获胜!游戏结束。" << endl;
                    exit(0);
                }

                // 处理特殊牌效果
                handleSpecialCard(selectedCard);
            } else {
                cout << "这张牌不能出!(颜色或数字/功能不匹配)" << endl;
            }
        } else {
            // AI 回合
            playAITurn();
        }
    }

    void start() {
        cout << "====== 欢迎来到 UNO 游戏 (1人 vs 3AI) ======" << endl;
        dealCards();
        while (true) {
            playTurn();
        }
    }
};

int main() {
    UnoGame game;
    game.start();
    return 0;
}

共 1 条回复

yumi

又来