跳至主要內容

三国杀2

李镓永2024年11月28日大约 4 分钟教学文档模拟

三国杀算法 2

题目描述

假设现在有两个玩家A和B,分别使用孙权和神吕蒙。场上有两张闪电牌,每回合开始时,当前玩家需要进行闪电牌的判定。如果判定结果为黑桃2~9,则当前玩家会受到3点雷电伤害,闪电牌从场上移除。每名玩家的初始手牌中都有一张无懈可击牌,可以在闪电牌判定之前使用,以抵消闪电牌的判定效果,避免受到3点伤害。

请编写一个函数来计算,在双方都采取最优策略的情况下,玩家A和B何时使用无懈可击牌,使得各自受到的伤害最小。返回一个元组 (use_wuxie_A, use_wuxie_B),表示玩家A和B分别在哪一回合使用无懈可击牌。

输入格式

  • health_A: 孙权的初始血量,范围为[1, 10]。
  • health_B: 神吕蒙的初始血量,范围为[1, 10]。
  • turns: 总回合数,范围为[1, 10]。
  • deck: 牌堆中的牌,包含字符串"black_2"到"black_9"表示黑桃2到9,其他值表示不会触发伤害。

输出格式

返回一个元组 (use_wuxie_A, use_wuxie_B),表示玩家A和B分别在哪一回合使用无懈可击牌。

示例

示例1

输入:

health_A = 5
health_B = 6
turns = 5
deck = ["black_2", "black_3", "black_4", "black_5", "black_6", "black_7", "black_8", "black_9", "red_10", "club_10"]

输出:

(1, 2)

解释:

  • 第一回合,孙权受到3点伤害,使用无懈可击牌抵消。
  • 第二回合,神吕蒙受到3点伤害,使用无懈可击牌抵消。
  • 后续回合,双方都不会受到闪电牌的伤害。

示例2

输入:

health_A = 4
health_B = 4
turns = 3
deck = ["black_2", "black_9", "black_3", "red_10", "club_10"]

输出:

(1, 3)

解释:

  • 第一回合,孙权受到3点伤害,使用无懈可击牌抵消。
  • 第二回合,神吕蒙不受伤害。
  • 第三回合,神吕蒙受到3点伤害,使用无懈可击牌抵消。

参考答案

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

// 定义牌的结构体
typedef struct {
    char suit;  // 花色:'S' 黑桃, 'H' 红桃, 'D' 方片, 'C' 梅花
    int value;  // 牌面值
} Card;

// 判断牌是否为黑桃2~9
int is_black_2_to_9(Card card) {
    return card.suit == 'S' && card.value >= 2 && card.value <= 9;
}

// 计算当前牌堆中黑桃2~9的数量
int count_black_2_to_9(Card *deck, int deck_size) {
    int count = 0;
    for (int i = 0; i < deck_size; i++) {
        if (is_black_2_to_9(deck[i])) {
            count++;
        }
    }
    return count;
}

// 计算当前回合闪电牌判定为黑桃2~9的概率
double calculate_probability(Card *deck, int deck_size) {
    if (deck_size == 0) return 0.0;
    int black_2_to_9_count = count_black_2_to_9(deck, deck_size);
    return (double)black_2_to_9_count / deck_size;
}

// 主函数
void optimal_wuxie_usage(int health_A, int health_B, int turns, Card *deck, int deck_size) {
    int use_wuxie_A = -1;
    int use_wuxie_B = -1;

    srand(time(NULL));  // 初始化随机数种子

    for (int turn = 0; turn < turns; turn++) {
        double probability_black_2_to_9 = calculate_probability(deck, deck_size);

        if (turn % 2 == 0) {  // 当前回合是孙权的回合
            if (probability_black_2_to_9 > 0 && use_wuxie_A == -1) {
                use_wuxie_A = turn + 1;
                continue;
            }
        } else {  // 当前回合是神吕蒙的回合
            if (probability_black_2_to_9 > 0 && use_wuxie_B == -1) {
                use_wuxie_B = turn + 1;
                continue;
            }
        }

        // 进行闪电牌判定
        if (probability_black_2_to_9 > 0) {
            int index = rand() % deck_size;
            if (is_black_2_to_9(deck[index])) {
                if (turn % 2 == 0) {
                    health_A = health_A - 3;
                } else {
                    health_B = health_B - 3;
                }
                // 移除已使用的闪电牌
                for (int i = index; i < deck_size - 1; i++) {
                    deck[i] = deck[i + 1];
                }
                deck_size--;
            }
        }
    }

    printf("(%d, %d)\n", use_wuxie_A, use_wuxie_B);
}

int main() {
    int health_A = 5;
    int health_B = 6;
    int turns = 5;
    Card deck[] = {
        {'S', 2}, {'S', 3}, {'S', 4}, {'S', 5}, {'S', 6}, {'S', 7}, {'S', 8}, {'S', 9},
        {'H', 10}, {'C', 10}
    };
    int deck_size = sizeof(deck) / sizeof(deck[0]);

    optimal_wuxie_usage(health_A, health_B, turns, deck, deck_size);

    return 0;
}

解释

  1. 定义牌的结构体Card 结构体用于表示一张牌,包含花色和牌面值。
  2. 判断牌是否为黑桃2~9is_black_2_to_9 函数用于判断一张牌是否为黑桃2~9。
  3. 计算当前牌堆中黑桃2~9的数量count_black_2_to_9 函数遍历牌堆,统计黑桃2~9的数量。
  4. 计算当前回合闪电牌判定为黑桃2~9的概率calculate_probability 函数计算当前牌堆中黑桃2~9的概率。
  5. 主函数optimal_wuxie_usage 函数模拟每个回合的过程,决定何时使用无懈可击牌。
  6. 主函数调用:在 main 函数中初始化玩家血量、回合数和牌堆,然后调用 optimal_wuxie_usage 函数。
上次编辑于: 2024/11/28 11:01:47
贡献者: lukzia