雷霆骗子酒馆
2026-08-15 16:43:51
发布于:广东
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib> // for rand(), srand()
#include <algorithm> // for random_shuffle, find_if (manual implementation needed if not available)
#include <iomanip>
#include <ctime>
#include <map>
#include <cctype>
// 老版本不支持 enum class,使用传统 enum
enum PlayerType { HUMAN, AI };
enum ItemType { HEAL, POISON, SHIELD, REVERSE, STEAL, BLIND, DOUBLE, DISARM, SABOTAGE, LUCKY, SILENCE, NONE };
enum GameState { PREPARE, PLAYING, FINISHED };
struct Item {
ItemType type;
std::string name;
std::string effect;
bool used;
// 老版本需要显式构造函数或初始化
Item() : type(NONE), used(false) {}
Item(ItemType t, const std::string& n, const std::string& e) : type(t), name(n), effect(e), used(false) {}
};
struct Player {
std::string name;
int health;
int maxHealth;
int turnOrder;
PlayerType type;
std::vector<Item> inventory;
bool isAlive;
bool hasShield;
bool isBlind;
bool isSilenced;
int stolenItems;
// 老版本构造函数
Player() : health(100), maxHealth(100), turnOrder(0), type(HUMAN), isAlive(true), hasShield(false), isBlind(false), isSilenced(false), stolenItems(0) {}
Player(const std::string& n, PlayerType t) :
name(n), type(t), health(100), maxHealth(100), turnOrder(0),
isAlive(true), hasShield(false), isBlind(false), isSilenced(false), stolenItems(0) {
inventory.reserve(5);
}
};
// 辅助函数:老版本不支持 Lambda,需单独写判断函数
bool isItemUnused(const Item& i) {
return !i.used;
}
bool isItemOfTypeAndUnused(const Item& i, ItemType type) {
return !i.used && i.type == type;
}
class Game {
private:
std::vector<Player> players;
GameState state;
int currentPlayerIndex;
// 老版本随机数生成使用 rand()
std::map<ItemType, std::string> itemNames;
std::map<ItemType, std::string> itemEffects;
void initializeMaps() {
itemNames[HEAL] = "治疗药水"; itemNames[POISON] = "毒药"; itemNames[SHIELD] = "护盾";
itemNames[REVERSE] = "逆转卷轴"; itemNames[STEAL] = "偷窃手套"; itemNames[BLIND] = "致盲粉";
itemNames[DOUBLE] = "双倍骰子"; itemNames[DISARM] = "解除武装"; itemNames[SABOTAGE] = "破坏装置";
itemNames[LUCKY] = "幸运符"; itemNames[SILENCE] = "沉默药剂"; itemNames[NONE] = "无";
itemEffects[HEAL] = "恢复30点生命值";
itemEffects[POISON] = "使目标损失20点生命值";
itemEffects[SHIELD] = "免疫下一次伤害";
itemEffects[REVERSE] = "交换两名玩家血量";
itemEffects[STEAL] = "偷取一名玩家一件道具";
itemEffects[BLIND] = "使目标下回合无法使用道具";
itemEffects[DOUBLE] = "下一次攻击伤害翻倍";
itemEffects[DISARM] = "移除目标所有道具";
itemEffects[SABOTAGE] = "随机破坏一件道具";
itemEffects[LUCKY] = "立即获得一件随机道具";
itemEffects[SILENCE] = "禁止目标使用道具一回合";
}
void initializeItems() {
// 手动构建物品列表
ItemType allItems[] = {HEAL, POISON, SHIELD, REVERSE, STEAL, BLIND, DOUBLE, DISARM, SABOTAGE, LUCKY, SILENCE};
int numItems = 11;
for (size_t p = 0; p < players.size(); ++p) {
for (int i = 0; i < 3; ++i) {
// 老版本随机数: rand() % N
ItemType type = allItems[rand() % numItems];
players[p].inventory.push_back(Item(type, itemNames[type], itemEffects[type]));
}
}
}
void displayStatus() {
std::cout << "\n" << std::string(60, '=') << "\n";
std::cout << "当前状态:\n";
for (size_t i = 0; i < players.size(); ++i) {
const Player& p = players[i];
std::cout << std::left << std::setw(12) << p.name
<< "血量: " << std::setw(3) << p.health << "/" << p.maxHealth
<< " | 状态: " << (p.isAlive ? "存活" : "淘汰")
<< (p.hasShield ? " [护盾]" : "")
<< (p.isBlind ? " [致盲]" : "")
<< (p.isSilenced ? " [沉默]" : "")
<< " | 道具: " << p.inventory.size() << "件\n";
}
std::cout << std::string(60, '=') << "\n";
}
void displayInventory(const Player& p) {
std::cout << "\n" << p.name << " 的道具:\n";
bool hasValidItem = false;
for (size_t i = 0; i < p.inventory.size(); ++i) {
if (!p.inventory[i].used) {
std::cout << " [" << i + 1 << "] " << p.inventory[i].name << " — " << p.inventory[i].effect << "\n";
hasValidItem = true;
}
}
if (!hasValidItem) {
std::cout << " 无可用道具\n";
}
}
void useItem(Player& user, Player& target, ItemType type) {
switch (type) {
case HEAL:
user.health = std::min(user.maxHealth, user.health + 30);
std::cout << user.name << " 使用治疗药水,恢复30点生命值!\n";
break;
case POISON:
target.health = std::max(0, target.health - 20);
std::cout << user.name << " 使用毒药," << target.name << " 损失20点生命值!\n";
break;
case SHIELD:
user.hasShield = true;
std::cout << user.name << " 激活护盾,下一次伤害将被免疫!\n";
break;
case REVERSE:
std::swap(user.health, target.health);
std::cout << user.name << " 使用逆转卷轴,与" << target.name << " 交换血量!\n";
break;
case STEAL:
if (!target.inventory.empty()) {
// 手动查找未使用的物品
int foundIndex = -1;
for (size_t k = 0; k < target.inventory.size(); ++k) {
if (!target.inventory[k].used) {
foundIndex = k;
break;
}
}
if (foundIndex != -1) {
user.inventory.push_back(target.inventory[foundIndex]);
target.inventory[foundIndex].used = true;
user.stolenItems++;
std::cout << user.name << " 偷走了" << target.name << " 的" << target.inventory[foundIndex].name << "!\n";
}
} else {
std::cout << user.name << " 试图偷窃,但" << target.name << " 没有可用道具!\n";
}
break;
case BLIND:
target.isBlind = true;
std::cout << user.name << " 使用致盲粉," << target.name << " 下回合无法使用道具!\n";
break;
case DOUBLE:
std::cout << user.name << " 使用双倍骰子,下一次攻击伤害翻倍!\n";
break;
case DISARM:
for (size_t k = 0; k < target.inventory.size(); ++k) {
target.inventory[k].used = true;
}
std::cout << user.name << " 使用解除武装,清空了" << target.name << " 的所有道具!\n";
break;
case SABOTAGE:
if (!target.inventory.empty()) {
int foundIndex = -1;
for (size_t k = 0; k < target.inventory.size(); ++k) {
if (!target.inventory[k].used) {
foundIndex = k;
break;
}
}
if (foundIndex != -1) {
target.inventory[foundIndex].used = true;
std::cout << user.name << " 使用破坏装置,摧毁了" << target.name << " 的" << target.inventory[foundIndex].name << "!\n";
}
}
break;
case LUCKY:
{
ItemType newItemType = static_cast<ItemType>(rand() % 11);
user.inventory.push_back(Item(newItemType, itemNames[newItemType], itemEffects[newItemType]));
std::cout << user.name << " 使用幸运符,获得随机道具:" << itemNames[newItemType] << "!\n";
}
break;
case SILENCE:
target.isSilenced = true;
std::cout << user.name << " 使用沉默药剂," << target.name << " 下回合无法使用道具!\n";
break;
default:
break;
}
}
int rollDice() {
return rand() % 6 + 1;
}
void aiChooseAction(Player& ai, std::vector<Player>& opponents) {
if (ai.isSilenced || ai.isBlind) {
std::cout << ai.name << " 无法行动(沉默/致盲)。\n";
return;
}
// 低血量优先治疗
if (ai.health < 40) {
int healIndex = -1;
for (size_t k = 0; k < ai.inventory.size(); ++k) {
if (isItemOfTypeAndUnused(ai.inventory[k], HEAL)) {
healIndex = k;
break;
}
}
if (healIndex != -1) {
useItem(ai, ai, HEAL);
ai.inventory[healIndex].used = true;
return;
}
}
// 寻找血量最低的对手
Player* target = NULL;
int minHealth = 1000;
for (size_t i = 0; i < opponents.size(); ++i) {
if (opponents[i].isAlive && opponents[i].health < minHealth) {
minHealth = opponents[i].health;
target = &opponents[i];
}
}
if (target == NULL) return;
// 尝试使用攻击性道具
ItemType attackItems[] = {POISON, SABOTAGE, DISARM, BLIND, SILENCE};
int numAttackItems = 5;
for (int j = 0; j < numAttackItems; ++j) {
ItemType type = attackItems[j];
int itemIndex = -1;
for (size_t k = 0; k < ai.inventory.size(); ++k) {
if (isItemOfTypeAndUnused(ai.inventory[k], type)) {
itemIndex = k;
break;
}
}
if (itemIndex != -1) {
useItem(ai, *target, type);
ai.inventory[itemIndex].used = true;
return;
}
}
// 普通攻击
int damage = rollDice() * 10;
if (target->hasShield) {
target->hasShield = false;
std::cout << ai.name << " 攻击" << target->name << ",但被护盾抵消!\n";
} else {
target->health = std::max(0, target->health - damage);
std::cout << ai.name << " 攻击" << target->name << ",造成" << damage << "点伤害!\n";
}
}
void humanChooseAction(Player& human, std::vector<Player>& opponents) {
std::cout << "\n" << human.name << " 的回合!\n";
displayInventory(human);
int choice;
std::cout << "选择操作:\n1. 使用道具\n2. 普通攻击\n3. 跳过回合\n输入选择:";
std::cin >> choice;
if (choice == 1 && !human.inventory.empty()) {
int itemIndex;
std::cout << "选择道具编号(1-" << human.inventory.size() << "):";
std::cin >> itemIndex;
// 边界检查
if (itemIndex < 1 || itemIndex > static_cast<int>(human.inventory.size()) || human.inventory[itemIndex - 1].used) {
std::cout << "无效道具!\n";
return;
}
Item& item = human.inventory[itemIndex - 1];
if (item.type == HEAL || item.type == LUCKY) {
useItem(human, human, item.type);
} else {
std::cout << "选择目标玩家(输入编号):\n";
for (size_t i = 0; i < opponents.size(); ++i) {
if (opponents[i].isAlive) {
std::cout << i + 1 << ". " << opponents[i].name << " (" << opponents[i].health << "HP)\n";
}
}
int targetIndex;
std::cin >> targetIndex;
if (targetIndex < 1 || targetIndex > static_cast<int>(opponents.size()) || !opponents[targetIndex - 1].isAlive) {
std::cout << "无效目标!\n";
return;
}
useItem(human, opponents[targetIndex - 1], item.type);
}
item.used = true;
} else if (choice == 2) {
std::cout << "选择攻击目标(输入编号):\n";
for (size_t i = 0; i < opponents.size(); ++i) {
if (opponents[i].isAlive) {
std::cout << i + 1 << ". " << opponents[i].name << " (" << opponents[i].health << "HP)\n";
}
}
int targetIndex;
std::cin >> targetIndex;
if (targetIndex < 1 || targetIndex > static_cast<int>(opponents.size()) || !opponents[targetIndex - 1].isAlive) {
std::cout << "无效目标!\n";
return;
}
int damage = rollDice() * 10;
if (opponents[targetIndex - 1].hasShield) {
opponents[targetIndex - 1].hasShield = false;
std::cout << human.name << " 攻击" << opponents[targetIndex - 1].name << ",但被护盾抵消!\n";
} else {
opponents[targetIndex - 1].health = std::max(0, opponents[targetIndex - 1].health - damage);
std::cout << human.name << " 攻击" << opponents[targetIndex - 1].name << ",造成" << damage << "点伤害!\n";
}
} else if (choice == 3) {
std::cout << human.name << " 跳过回合。\n";
}
}
public:
Game() {
srand(static_cast<unsigned int>(time(NULL))); // 老版本随机种子初始化
initializeMaps();
state = PREPARE;
currentPlayerIndex = 0;
}
void setupGame() {
int playerCount;
std::cout << "欢迎来到骗子酒馆!\n";
std::cout << "请输入玩家总数(2-4人):";
std::cin >> playerCount;
if (playerCount < 2 || playerCount > 4) {
playerCount = 4;
std::cout << "无效输入,已设为4人。\n";
}
int aiCount;
std::cout << "请输入AI玩家数量(0-" << (playerCount - 1) << "):";
std::cin >> aiCount;
if (aiCount < 0 || aiCount > playerCount - 1) {
aiCount = playerCount / 2;
std::cout << "无效输入,已设为" << aiCount << "名AI。\n";
}
for (int i = 0; i < playerCount; ++i) {
std::string name;
if (i < aiCount) {
name = "AI玩家" + static_cast<char>('0' + (i + 1)); // 简单转换,避免 to_string
players.push_back(Player(name, AI));
} else {
std::cout << "请输入玩家" << (i - aiCount + 1) << "的姓名:";
std::cin >> name;
players.push_back(Player(name, HUMAN));
}
}
// 老版本使用 random_shuffle
std::random_shuffle(players.begin(), players.end());
for (size_t i = 0; i < players.size(); ++i) {
players[i].turnOrder = static_cast<int>(i) + 1;
}
initializeItems();
state = PLAYING;
currentPlayerIndex = 0;
}
void playTurn() {
Player& current = players[currentPlayerIndex];
if (!current.isAlive) {
currentPlayerIndex = (currentPlayerIndex + 1) % static_cast<int>(players.size());
return;
}
std::cout << "\n=== 第 " << (currentPlayerIndex + 1) << " 回合: " << current.name << " 的回合 ===\n";
displayStatus();
if (current.isSilenced) {
current.isSilenced = false;
std::cout << current.name << " 的沉默效果已结束。\n";
}
if (current.isBlind) {
current.isBlind = false;
std::cout << current.name << " 的致盲效果已结束。\n";
}
std::vector<Player> opponents;
for (size_t i = 0; i < players.size(); ++i) {
if (players[i].isAlive && i != static_cast<size_t>(currentPlayerIndex)) {
opponents.push_back(players[i]);
}
}
if (current.type == HUMAN) {
humanChooseAction(current, opponents);
} else {
aiChooseAction(current, opponents);
}
// 检查死亡
for (size_t i = 0; i < players.size(); ++i) {
if (players[i].health <= 0 && players[i].isAlive) {
players[i].isAlive = false;
std::cout << players[i].name << " 被淘汰了!\n";
}
}
int aliveCount = 0;
for (size_t i = 0; i < players.size(); ++i) {
if (players[i].isAlive) aliveCount++;
}
if (aliveCount <= 1) {
state = FINISHED;
std::cout << "\n=== 游戏结束! ===\n";
for (size_t i = 0; i < players.size(); ++i) {
if (players[i].isAlive) {
std::cout << "[胜利] 胜利者:" << players[i].name << "!获得" << players[i].stolenItems << "件偷窃道具!\n";
break;
}
}
return;
}
currentPlayerIndex = (currentPlayerIndex + 1) % static_cast<int>(players.size());
}
void run() {
setupGame();
while (state == PLAYING) {
playTurn();
std::cout << "\n按回车继续...";
std::cin.get(); // 消耗之前的换行符
std::cin.get(); // 等待输入
}
}
};
int main() {
Game game;
game.run();
return 0;
}
```cpp
```cpp
```cpp
删除文本
全部评论 1
有 3 个严重问题 + 几个明确逻辑缺陷:
-
致命:攻击的其实是玩家副本。
opponents.push_back(players[i])会复制Player;后续攻击、毒药、致盲、解除武装等都修改opponents,而不是原始players。因此真实玩家血量基本不会下降,死亡检测检查的又是原始players,游戏可能一直无法结束。偷窃还会出现“自己获得道具,但对方原道具没丢”的复制问题。 -
严重 UB:AI 名称生成写错。
name = "AI玩家" + static_cast<char>('0' + (i + 1));这里不是字符串拼接,而是对字符串字面量做指针偏移,可能出现乱码、异常名称甚至崩溃。应至少改成
std::string("AI玩家") + char(...)。 -
潜在悬空引用。
Item& item = human.inventory[...]后,STEAL/LUCKY会向同一个inventory执行push_back();若 vector 扩容,item引用立即失效,之后再执行item.used = true属于未定义行为。 -
沉默/致盲实际上不会生效。
玩家回合刚开始就先把isSilenced、isBlind清成false,然后才执行玩家行动,所以“下回合无法使用道具”的效果被提前解除。 -
DOUBLE道具完全没有实际效果。
使用时只有一句输出,没有保存“双倍伤害”状态;普通攻击仍直接使用rollDice() * 10。 -
SABOTAGE文案说“随机破坏”,实际永远破坏第一件未使用道具。
另外,
std::random_shuffle属于旧接口,现代 C++17 标准已移除,跨编译器可能存在兼容问题。4天前 来自 浙江
1我编这个代码是用的老版本DEVC++,新版本确实有些bug,已经在改了,感谢提醒~

3天前 来自 广东
1
-
























有帮助,赞一个