4 个版本 (稳定版)

1.1.1 2024年5月8日
1.1.0 2024年5月6日
1.0.0 2024年5月2日
0.0.1 2024年4月24日

#158 in 游戏开发

GPL-3.0-or-later

1MB
4K SLoC

crates badge crates docs tests build status

Coup

这是一个编码游戏,你创建的机器人将玩流行的卡牌游戏COUP

你编写一个机器人来与其他机器人玩COUP,并调整其行为,直到找到获胜策略。

如果你购买实体卡牌游戏,并在午餐休息时间玩几次,这会更好

目标是进行三轮(1,000,000)游戏,找到获胜者(累计得分)。在每一轮之间,你有时间调整你的机器人。

它是如何工作的?

规则

  1. 4K SLoC
  2. COUP
  3. 这是一个编码游戏,你创建的机器人将玩流行的卡牌游戏COUP
  4. 你编写一个机器人来与其他机器人玩COUP,并调整其行为,直到找到获胜策略。
  5. 如果你购买实体卡牌游戏,并在午餐休息时间玩几次,这会更好
  6. 目标是进行三轮(1,000,000)游戏,找到获胜者(累计得分)。在每一轮之间,你有时间调整你的机器人。
  7. 它是如何工作的?

计分

规则

计分

  • 如何运行游戏
  • 如何构建机器人

如何运行游戏

引擎是如何工作的

变更日志

变更日志

use coup::{
	bots::{HonestBot, RandomBot, StaticBot},
	Coup,
};

fn main() {
	let mut coup_game = Coup::new(vec![
		Box::new(StaticBot),
		Box::new(StaticBot),
		Box::new(HonestBot),
		Box::new(HonestBot),
		Box::new(RandomBot),
		Box::new(RandomBot),
	]);

	coup_game.play();
}

变更日志

变更日志

use coup::{
	bots::{HonestBot, RandomBot, StaticBot},
	Coup,
};

fn main() {
	let mut coup_game = Coup::new(vec![
		Box::new(StaticBot),
		Box::new(StaticBot),
		Box::new(HonestBot),
		Box::new(HonestBot),
		Box::new(RandomBot),
		Box::new(RandomBot),
	]);

	coup_game.looping(1_000_000);
}

如何构建机器人

实现BotInterface,并覆盖您想控制的每个方法的默认实现。默认实现是StaticBot的方法,它只接受Income,如果积累的硬币数等于或大于10,则被迫由引擎进行政变。它不挑战、反击或反击挑战。

通过将每个方法回退到静态行为来构建机器人的最简单方法可能是

use coup::bot::BotInterface;

pub struct MyBot;

impl BotInterface for MyBot {
	fn get_name(&self) -> String {
		String::from("MyBot")
	}
}

(这就是StaticBot。)

从那里,您可以选择更改以下方法中的哪些,而不是所有方法,以使这个机器人成为您的专属。

机器人的方法

BotInterface的方法将定义您机器人的行为。

  • get_name – 在Coup游戏的实例化过程中仅调用一次,以识别您的机器人
  • on_turn – 当轮到您决定要做什么时调用
  • on_auto_coup – 当您的硬币数等于或超过10时调用,必须进行政变。
  • on_challenge_action_round – 当其他机器人执行了动作,每个人都可以决定是否要挑战该动作时调用。
  • on_counter – 当有人执行了可以使用您可能持有的牌进行反击的动作时调用。
  • on_challenge_counter_round – 当一个机器人执行了反击时调用。现在每个人都必须决定是否要挑战那张反击牌。
  • on_swapping_cards – 当您执行了大使牌后,需要决定您想保留哪些牌。
  • on_card_loss – 当您失去一张牌后,必须决定您想失去哪一张。

上下文

每个函数都会传入包含以下信息的context

描述
名称 您的机器人名称在引擎去重后。这意味着如果您的机器人名称相同,它们将在名称后附加一个空格和一个数字,用作标识符。
您仍持有的牌/影响
硬币 您的硬币
playing_bots 本回合所有正在玩的游戏机器人列表
discard_pile 到目前为止游戏中所有已丢弃的牌列表
历史 到目前为止游戏中发生的事件列表
score 当前游戏得分

引擎是如何工作的

引擎尽最大努力执行游戏中规定的所有规则。在规则模糊或无法在计算机世界中执行的区域,它尽力接近现实世界游戏。

算法

match action
	Assassination | Stealing
		=>
			- challenge round
			- counter from target
			- counter challenge
			- action
	Coup | Income
		=>
			- action
	ForeignAid
		=>
			- counter round from everyone
			- counter challenge round
			- action
	Swapping | Tax
		=>
			- challenge round
			- action

挑战

对于机器人,我们区分两种不同的挑战

  • 对动作的挑战
  • 对反击动作的挑战

因为游戏规则指出,任何人都可以发起挑战(顺序从未明确说明),并且因为引擎不能同时调用所有机器人,所以引擎会逐个从刚刚触发挑战的机器人的动作开始。

因此,如果玩家A执行了动作,那么第一个被询问是否要挑战这个动作的机器人是玩家B。如果玩家C执行了动作,那么第一个机器人将是玩家D。

这在测试中可能最明显。

针对其他机器人

因为某些动作需要你告诉引擎你想对谁施加这个动作,所以引擎期望你给它一个名字。这个名字是从每个机器人的 get_name 方法中提取出来的。引擎确保在游戏实例化时,不会有多个机器人有相同的名字,它会给重复的名字后面添加空格和数字。

所以如果我们有这个机器人列表

  • 蒂奇
  • 鲍勃
  • 克拉拉
  • 鲍勃

引擎会将名字改为

  • 蒂奇
  • 鲍勃
  • 克拉拉
  • 鲍勃 2

然后通过 上下文 结构将这些名字传递给你。

自动辞职

规则规定,如果玩家有10个或更多的硬币,他们必须在下次轮到他们的时候辞职。引擎通过在机器人轮到的时候调用 on_auto_coup 方法而不是 on_turn 方法来强制执行这一点。

处罚

引擎会检查机器人所进行的动作是否合法。如果机器人因为资金不足(辞职暗杀)而无法执行某个动作,它将惩罚这个机器人,从该机器人那里抽取一张牌(并通过调用 on_card_loss 方法询问机器人是哪一张牌)。

如果机器人返回一个目标无效的动作(不存在的机器人的名字),也会发生同样的事情。

变更日志

v1.1.1

修复了引擎,确保目标机器人不仅存在,而且正在游戏中。在机器人可以针对不在本轮游戏中(我们有多于6个机器人)的另一个机器人之前,这可能导致恐慌,因为这些机器人可能没有两张牌。

v1.1.0

通过确保第一个被要求挑战的机器人是下一个按机器人位置排列的机器人,使挑战和反挑战更加公平。这样,对于每个可挑战的动作,我们的反动作的第一个机器人是不同的,而不是像以前那样是游戏中的第一个机器人。

v1.0.0

新Rust引擎的初始发布

依赖项

~3–16MB
~160K SLoC