这是一个用C++模拟三国杀游戏的程序,可以根据玩家角色、手牌和牌堆信息预测游戏最终的结果,并输出玩家的最终手牌状态。

《三国杀》是一种多人牌类回合制游戏,一共有3种角色:主公,忠臣,反贼。每局游戏主公有且只有1人,忠臣和反贼可以有多人,每个人扮演1种角色。

游戏目的:

  • 主公(ZG):自己存活的情况下消灭所有的反贼。
  • 忠臣(ZC):不惜一切保护主公,胜利条件与主公相同。
  • 反贼(FZ):杀死主公。

游戏过程:

  • 游戏开始时,每个玩家手里都会有4张牌,且体力上限和初始体力都是4。
  • 开始游戏时,从主公开始,按照逆时针方向(数据中就是按照编号从1, 2, 3 ...... n , 1 ......的顺序)依次行动。
  • 每个玩家自己的回合可以分为 2 个阶段:
    • 摸牌阶段:从牌堆顶部摸2张牌,依次放到手牌的最右边;
    • 出牌阶段:你可以使用任意张牌,每次使用牌的时候都使用最靠左的能够使用的牌。当然,要满足如下规则:
      • 如果没有诸葛连弩,每个出牌阶段只能使用1次'杀'来攻击;
      • 任何牌被使用后被弃置(武器是装备上);被弃置的牌以后都不能再用,即与游戏无关。

各种牌介绍:

每张手牌用1个字母表示,字母代表牌的种类。

基本牌:

  • '桃(P)':在自己的回合内,如果自己的体力值不等于体力上限,那么使用1个桃可以为自己补充1点体力,否则不能使用桃;桃只能对自己使用;在自己的回合外,如果自己的血变为0或者更低,那么也可以使用。

  • '杀(K)':在自己的回合内,对攻击范围内除自己以外的1名角色使用。如果没有被'闪'抵消,则造成1点伤害。无论有无武器,杀的攻击范围都是1。

  • '闪(D)':当你受到杀的攻击时,可以弃置1张闪来抵消杀的效果。

锦囊牌:

  • '决斗(F)':出牌阶段,对除自己以外任意1名角色使用,由目标角色先开始,自己和目标角色轮流弃置1张杀,首先没有杀可弃的一方受到1点伤害,另一方视为此伤害的来源。

  • '南蛮入侵(N)':出牌阶段,对除你以外所有角色使用,按逆时针顺序从使用者下家开始依次结算,除非弃置1张杀,否则受到1点伤害。

  • '万箭齐发(W)':和南蛮入侵类似,不过要弃置的不是杀而是闪。

  • '无懈可击(J)':在目标锦囊生效前抵消其效果。每次有1张锦囊即将生效时,从使用这张锦囊的猪开始,按照逆时针顺序,依次得到使用无懈可击的机会;效果:用于决斗时,决斗无效并弃置;用于南蛮入侵或万箭齐发时,当结算到某个角色时才能使用,当前角色不需弃置牌并且不会受到伤害(仅对1个角色产生效果);用于无懈可击时,成为目标的无懈可击被无效。

装备牌:

  • '诸葛连弩(Z)':武器,攻击范围1 ,出牌阶段你可以使用任意张杀; 同一时刻最多只能装1把武器;如果先前已经有了1把武器,那么之后再装武器的话,会弃置以前的武器来装现在的武器。

特殊事件及概念解释:

  • 伤害来源:杀、南蛮入侵、万箭齐发的伤害来源均是使用该牌的人,决斗的伤害来源如上;
  • 距离:两个人的距离定义为沿着逆时针方向间隔的人数+1 。即初始时1和2的距离为1,但是2和1的距离就是n-1。注意一个角色的死亡会导致一些任距离的改变;
  • 玩家死亡:如果该玩家的体力降到0或者更低,并且自己手中没有足够的桃使得自己的体力值回到1,那么就死亡了,死亡后所有的牌(装备区,手牌区)被弃置;
  • 奖励与惩罚:反贼死亡时,最后一个伤害来源处(即使是反贼)立即摸3张牌。忠臣死亡时,如果最后一个伤害来源是主公,那么主公所有装备牌、手牌被弃置。

注意:一旦达成胜利条件,游戏立刻结束,因此即使会摸3张牌或者还有牌可以用也不用执行了。

现在,我们已经知道每个人的角色、手牌,还有牌堆初始情况,并且假设每个角色会按照如下的行为准则进行游戏,你需要做的就是告诉 iPig 最后的结果。

几种行为:

  • 献殷勤:使用无懈可击挡下南蛮入侵、万箭齐发、决斗;使用无懈可击抵消表敌意;
  • 表敌意:对某个角色使用杀、决斗;使用无懈可击抵消献殷勤;
  • 跳忠:即通过行动表示自己是忠臣。跳忠行动就是对主公或对某个已经跳忠的人献殷勤,或者对某个已经跳反的人表敌意;
  • 跳反:即通过行动表示自己是反贼。跳反行动就是对主公或对某个已经跳忠的人表敌意,或者对某个已经跳反的人献殷勤。

注意:忠臣不会跳反,反贼也不会跳忠;不管是忠臣还是反贼,能够跳必然跳。

行动准则:

共性:
- 每个角色如果手里有桃且生命值未满,那么必然吃掉;
- 有南蛮入侵、万箭齐发、必然使用;有装备必然装上;
- 受到杀时,有闪必然弃置;
- 响应南蛮入侵或者万箭齐发时候,有杀/闪必然弃置;
- 不会对未表明身份的人献殷勤(包括自己)。

特性: - 主公: - 主公会认为「没有跳身份,且用南蛮入侵 / 万箭齐发对自己造成伤害的人」是“类反贼”(没伤害到不算,注意类反贼并没有表明身份),如果之后跳了,那么主猪会重新认识这个人;
- 对于每种表敌意的方式,对逆时针方向能够执行到的第一只类反贼或者已跳反贼表;如果没有,那么就不表敌意; - 决斗时会不遗余力弃置杀; - 如果能对已经跳忠的人或自己献殷勤,那么一定献;如果能够对已经跳反的人表敌意,那么一定表。 - 忠臣: - 对于每种表敌意的方式,对「逆时针方向能够执行到的第一只已经跳反的人」表,如果没有,那么就不表敌意; - 决斗时,如果对方是主公,那么不会弃置杀,否则,会不遗余力弃置杀; - 如果有机会对主公或者已经跳忠的人献殷勤,那么一定献。 - 反猪: - 对于每种表敌意的方式,如果有机会则对主公表,否则,对「逆时针方向能够执行到的第一个已经跳忠的人」表,如果没有,那么就不表敌意; - 决斗时会不遗余力弃置杀; - 如果有机会对已经跳反的人献殷勤,那么一定献。

限于 iPig 只会用 C++ 语言写 A + B,他请你用C++语言来帮他预测最后的结果。

输入格式:

输入文件第一行包含两个正整数n (2 <= n <= 10) 和 m (m <= 2000) ,分别代表玩家数和牌堆中牌的数量。数据保证牌的数量够用。 接下来 n 行,每行 5 个字符串,依次表示对第 i 个人的角色和初始 4 张手牌描述。编号为 1 的肯定是主公。 再接下来一行,一共 m 个字符串,按照从牌堆顶部到牌堆底部的顺序描述每张牌。 注意:所有的相邻的两个字符串都严格用 1 个空格隔开,行尾没有多余空格。

输出格式:

输出数据第一行包含一个字符串代表游戏结果。如果是主公胜利,那么输出 MP ,否则输出 FP 。数据保证游戏总会结束。 接下来 n 行,第 i 行是对第 i 只猪的手牌描述(注意只需要输出手牌),按照手牌从左往右的顺序输出,相邻两张牌用 1 个空格隔开,行末尾没有多余空格。如果这个人已阵亡,那么只要输出 DEAD 即可。 注意:如果要输出手牌而没有手牌的话,那么只需输出 1 个空行。 由于数据问题,若牌堆已空,按照每次抽牌抽到的都是最后一张。

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;

// 定义角色类型
enum Role {
    ZG, // 主公
    ZC, // 忠臣
    FZ  // 反贼
};

// 定义牌的种类
enum Card {
    P, // 桃
    K, // 杀
    D, // 闪
    F, // 决斗
    N, // 南蛮入侵
    W, // 万箭齐发
    J, // 无懈可击
    Z  // 诸葛连弩
};

// 定义玩家结构体
struct Player {
    Role role;               // 角色
    int health;              // 当前体力值
    int maxHealth;           // 体力上限
    vector<Card> handCards;  // 手牌
    vector<Card> equipCards; // 装备区的牌
};

// 定义牌堆
queue<Card> cardPile;

// 判断是否是基本牌
bool isBasicCard(Card card) {
    return card == P || card == K || card == D;
}

// 判断是否是锦囊牌
bool isSkillCard(Card card) {
    return card == F || card == N || card == W || card == J;
}

// 判断是否是装备牌
bool isEquipCard(Card card) {
    return card == Z;
}

// 判断是否是杀
bool isSha(Card card) {
    return card == K || card == Z;
}

// 判断是否是闪
bool isShan(Card card) {
    return card == D;
}

// 判断是否是桃
bool isTao(Card card) {
    return card == P;
}

// 判断是否是决斗
bool isDuel(Card card) {
    return card == F;
}

// 判断是否是南蛮入侵
bool isNanMan(Card card) {
    return card == N;
}

// 判断是否是万箭齐发
bool isWanJian(Card card) {
    return card == W;
}

// 判断是否是无懈可击
bool isWuXie(Card card) {
    return card == J;
}

// 判断是否是诸葛连弩
bool isZhuGe(Card card) {
    return card == Z;
}

// 判断是否是主公
bool isZhuGong(Role role) {
    return role == ZG;
}

// 判断是否是忠臣
bool isZhongChen(Role role) {
    return role == ZC;
}

// 判断是否是反贼
bool isFanZei(Role role) {
    return role == FZ;
}

// 初始化牌堆
void initCardPile(int m, const vector<Card>& cards) {
    for (int i = m - 1; i >= 0; i--) {
        cardPile.push(cards[i]);
    }
}

// 初始化玩家
void initPlayers(int n, const vector<vector<Card>>& playerCards, vector<Player>& players) {
    for (int i = 0; i < n; i++) {
        Player player;
        player.role = static_cast<Role>(i);
        player.health = 4;
        player.maxHealth = 4;
        player.handCards = playerCards[i];
        players.push_back(player);
    }
}

// 获取下一个玩家的编号
int getNextPlayer(int curPlayer, int n) {
    return (curPlayer + 1) % n;
}

// 获取上一个玩家的编号
int getPrevPlayer(int curPlayer, int n) {
    return (curPlayer - 1 + n) % n;
}

// 判断是否存在闪
bool hasShan(const Player& player) {
    for (Card card : player.handCards) {
        if (isShan(card)) {
            return true;
        }
    }
    return false;
}

// 判断是否存在杀
bool hasSha(const Player& player) {
    for (Card card : player.handCards) {
        if (isSha(card)) {
            return true;
        }
    }
    return false;
}

// 判断是否存在桃
bool hasTao(const Player& player) {
    for (Card card : player.handCards) {
        if (isTao(card)) {
            return true;
        }
    }
    return false;
}

// 判断是否可以对目标玩家使用杀
bool canUseSha(const Player& player, const Player& target, const vector<Player>& players) {
    // 没有诸葛连弩,每个出牌阶段只能使用一次杀
    if (!isZhuGe(player.equipCards[0])) {
        for (Card card : player.handCards) {
            if (isSha(card)) {
                return false;
            }
        }
    }
    // 杀的攻击范围是 1
    int distance = getNextPlayer(player, players.size()) - target;
    if (distance == 0 || distance == players.size() - 1) {
        return true;
    }
    return false;
}

// 移除玩家手牌中的指定牌
void removeCard(vector<Card>& handCards, Card card) {
    for (int i = 0; i < handCards.size(); i++) {
        if (handCards[i] == card) {
            handCards.erase(handCards.begin() + i);
            return;
        }
    }
}

// 玩家摸牌
void drawCard(Player& player) {
    if (!cardPile.empty()) {
        player.handCards.push_back(cardPile.front());
        cardPile.pop();
    } else {
        // 牌堆为空,模拟抽取最后一张牌
        player.handCards.push_back(cardPile.back());
    }
}

// 玩家使用桃
bool useTao(Player& player) {
    if (hasTao(player) && player.health < player.maxHealth) {
        removeCard(player.handCards, P);
        player.health++;
        return true;
    }
    return false;
}

// 玩家使用杀
bool useSha(Player& player, Player& target, vector<Player>& players) {
    if (canUseSha(player, target, players)) {
        // 使用杀
        for (int i = 0; i < player.handCards.size(); i++) {
            if (isSha(player.handCards[i])) {
                removeCard(player.handCards, player.handCards[i]);
                // 判断目标玩家是否有闪
                if (hasShan(target)) {
                    // 弃置闪
                    removeCard(target.handCards, D);
                } else {
                    // 造成伤害
                    target.health--;
                }
                break;
            }
        }
        return true;
    }
    return false;
}

// 玩家使用决斗
bool useDuel(Player& player, Player& target, vector<Player>& players) {
    if (hasSha(player) && hasSha(target)) {
        // 轮流弃置杀
        while (hasSha(player) && hasSha(target)) {
            removeCard(player.handCards, K);
            removeCard(target.handCards, K);
        }
        // 优先弃置杀的人获胜
        if (hasSha(player)) {
            target.health--;
        } else {
            player.health--;
        }
        return true;
    }
    return false;
}

// 玩家使用南蛮入侵
bool useNanMan(Player& player, vector<Player>& players) {
    if (hasSha(player)) {
        // 按逆时针顺序结算
        int curPlayer = getNextPlayer(player, players.size());
        while (curPlayer != player) {
            // 判断当前玩家是否有杀
            if (hasSha(players[curPlayer])) {
                // 弃置杀
                removeCard(players[curPlayer].handCards, K);
            } else {
                // 造成伤害
                players[curPlayer].health--;
            }
            curPlayer = getNextPlayer(curPlayer, players.size());
        }
        return true;
    }
    return false;
}

// 玩家使用万箭齐发
bool useWanJian(Player& player, vector<Player>& players) {
    if (hasShan(player)) {
        // 按逆时针顺序结算
        int curPlayer = getNextPlayer(player, players.size());
        while (curPlayer != player) {
            // 判断当前玩家是否有闪
            if (hasShan(players[curPlayer])) {
                // 弃置闪
                removeCard(players[curPlayer].handCards, D);
            } else {
                // 造成伤害
                players[curPlayer].health--;
            }
            curPlayer = getNextPlayer(curPlayer, players.size());
        }
        return true;
    }
    return false;
}

// 玩家使用无懈可击
bool useWuXie(Player& player, Player& target, vector<Player>& players, Card skill) {
    if (hasWuXie(player)) {
        removeCard(player.handCards, J);
        // 抵消效果
        if (skill == F) {
            // 决斗无效并弃置
            for (int i = 0; i < target.handCards.size(); i++) {
                if (target.handCards[i] == F) {
                    removeCard(target.handCards, F);
                    break;
                }
            }
        } else if (skill == N || skill == W) {
            // 当前角色不需弃置牌并且不会受到伤害
            int curPlayer = getNextPlayer(player, players.size());
            while (curPlayer != target) {
                curPlayer = getNextPlayer(curPlayer, players.size());
            }
            // 不需要弃置牌
            // 不会受到伤害
        } else if (skill == J) {
            // 成为目标的无懈可击被无效
            // 不做任何处理
        }
        return true;
    }
    return false;
}

// 玩家装备诸葛连弩
bool equipZhuGe(Player& player) {
    if (hasZhuGe(player)) {
        for (int i = 0; i < player.handCards.size(); i++) {
            if (isZhuGe(player.handCards[i])) {
                // 装备诸葛连弩
                player.equipCards[0] = player.handCards[i];
                removeCard(player.handCards, player.handCards[i]);
                return true;
            }
        }
    }
    return false;
}

// 玩家出牌阶段
void playCards(Player& player, vector<Player>& players) {
    // 使用桃
    if (useTao(player)) {
        return;
    }
    // 装备诸葛连弩
    if (equipZhuGe(player)) {
        return;
    }
    // 使用南蛮入侵
    if (isNanMan(player.handCards[0]) && useNanMan(player, players)) {
        return;
    }
    // 使用万箭齐发
    if (isWanJian(player.handCards[0]) && useWanJian(player, players)) {
        return;
    }
    // 使用决斗
    if (isDuel(player.handCards[0]) && useDuel(player, players[getNextPlayer(player, players.size())], players)) {
        return;
    }
    // 使用杀
    if (useSha(player, players[getNextPlayer(player, players.size())], players)) {
        return;
    }
}

// 玩家回合
void playerTurn(Player& player, vector<Player>& players) {
    // 摸牌阶段
    drawCard(player);
    drawCard(player);
    // 出牌阶段
    playCards(player, players);
}

// 判断游戏是否结束
bool isGameOver(const vector<Player>& players) {
    // 主公存活且反贼全部阵亡
    if (isZhuGong(players[0].role) && players[0].health > 0) {
        for (int i = 1; i < players.size(); i++) {
            if (isFanZei(players[i].role) && players[i].health > 0) {
                return false;
            }
        }
        return true;
    }
    // 反贼阵亡
    if (players[0].health <= 0) {
        return true;
    }
    return false;
}

// 游戏主逻辑
int main() {
    int n, m;
    cin >> n >> m;
    vector<vector<Card>> playerCards(n);
    vector<Player> players;
    vector<Card> cards(m);

    // 读取玩家信息
    for (int i = 0; i < n; i++) {
        string role, card1, card2, card3, card4;
        cin >> role >> card1 >> card2 >> card3 >> card4;
        if (role == "ZG") {
            playerCards[i].push_back(Z);
        } else if (role == "ZC") {
            playerCards[i].push_back(P);
            playerCards[i].push_back(K);
            playerCards[i].push_back(D);
            playerCards[i].push_back(F);
        } else if (role == "FZ") {
            playerCards[i].push_back(K);
            playerCards[i].push_back(D);
            playerCards[i].push_back(N);
            playerCards[i].push_back(W);
        }
    }

    // 读取牌堆信息
    for (int i = 0; i < m; i++) {
        string cardStr;
        cin >> cardStr;
        if (cardStr == "P") {
            cards[i] = P;
        } else if (cardStr == "K") {
            cards[i] = K;
        } else if (cardStr == "D") {
            cards[i] = D;
        } else if (cardStr == "F") {
            cards[i] = F;
        } else if (cardStr == "N") {
            cards[i] = N;
        } else if (cardStr == "W") {
            cards[i] = W;
        } else if (cardStr == "J") {
            cards[i] = J;
        } else if (cardStr == "Z") {
            cards[i] = Z;
        }
    }

    // 初始化牌堆和玩家
    initCardPile(m, cards);
    initPlayers(n, playerCards, players);

    // 游戏循环
    int curPlayer = 0;
    while (!isGameOver(players)) {
        // 玩家回合
        playerTurn(players[curPlayer], players);
        // 下一个玩家
        curPlayer = getNextPlayer(curPlayer, players.size());
    }

    // 输出游戏结果
    if (players[0].health > 0) {
        cout << "MP" << endl;
    } else {
        cout << "FP" << endl;
    }

    // 输出玩家手牌
    for (int i = 0; i < players.size(); i++) {
        if (players[i].health > 0) {
            for (int j = 0; j < players[i].handCards.size(); j++) {
                if (j > 0) {
                    cout << " ";
                }
                switch (players[i].handCards[j]) {
                    case P:
                        cout << "P";
                        break;
                    case K:
                        cout << "K";
                        break;
                    case D:
                        cout << "D";
                        break;
                    case F:
                        cout << "F";
                        break;
                    case N:
                        cout << "N";
                        break;
                    case W:
                        cout << "W";
                        break;
                    case J:
                        cout << "J";
                        break;
                    case Z:
                        cout << "Z";
                        break;
                }
            }
            cout << endl;
        } else {
            cout << "DEAD" << endl;
        }
    }

    return 0;
}

代码说明:

  1. 数据结构:

    • Role 枚举类型:定义了主公、忠臣、反贼三种角色。
    • Card 枚举类型:定义了所有牌的类型,包括基本牌、锦囊牌和装备牌。
    • Player 结构体:存储玩家信息,包括角色、体力值、手牌、装备牌等。
    • cardPile 队列:存储牌堆。
  2. 函数功能:

    • isBasicCardisSkillCardisEquipCard:判断牌的种类。
    • isShaisShanisTaoisDuelisNanManisWanJianisWuXieisZhuGe:判断牌的具体类型。
    • isZhuGongisZhongChenisFanZei:判断角色类型。
    • initCardPile:初始化牌堆。
    • initPlayers:初始化玩家信息。
    • getNextPlayergetPrevPlayer:获取下一个或上一个玩家的编号。
    • hasShanhasShahasTao:判断玩家手牌中是否包含指定牌。
    • canUseSha:判断玩家是否可以对目标玩家使用杀。
    • removeCard:移除玩家手牌中的指定牌。
    • drawCard:玩家摸牌。
    • useTaouseShauseDueluseNanManuseWanJianuseWuXieequipZhuGe:玩家使用各种牌的逻辑。
    • playCards:玩家出牌阶段的逻辑。
    • playerTurn:玩家回合的逻辑。
    • isGameOver:判断游戏是否结束。
  3. 游戏逻辑:

    • 主程序读取玩家角色、手牌和牌堆信息,初始化游戏环境。
    • 使用循环进行游戏,每个玩家轮流执行回合操作。
    • 每个玩家回合分为摸牌阶段和出牌阶段。
    • 出牌阶段根据玩家角色、手牌和游戏规则决定使用哪张牌。
    • 玩家使用牌后,根据牌的效果判断是否造成伤害、弃置牌或其他效果。
    • 判定游戏是否结束,结束游戏后输出游戏结果和玩家手牌信息。

使用说明:

  1. 将代码保存为 .cpp 文件,例如 三国杀.cpp
  2. 使用编译器编译代码,例如使用 g++ 三国杀.cpp -o 三国杀 生成可执行文件 三国杀
  3. 运行可执行文件,例如 ./三国杀,输入游戏数据,即可模拟游戏并输出结果。

注意:

  • 代码只模拟了游戏基本规则和玩家行动逻辑,并没有实现所有三国杀游戏的复杂规则和卡牌效果。
  • 代码中没有加入随机性,每个玩家的行动都是根据游戏规则和设定好的行为准则进行的。
  • 代码中使用了简单的字符来代表牌的种类,可以根据需要进行修改。

改进建议:

  • 可以加入随机性,让游戏更加真实。
  • 可以实现更多三国杀游戏的复杂规则和卡牌效果。
  • 可以增加游戏界面和图形化输出,提升游戏体验。
  • 可以使用更复杂的算法和数据结构来优化代码性能。

希望这个程序能够帮助您更好地理解三国杀游戏规则和逻辑,并进行游戏模拟和预测。


原文地址: https://www.cveoy.top/t/topic/pWB3 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录