关于对对碰游戏的研究

(封面图片来源于网络侵权删)

关于灵感

小学时不知道同学从哪里带回来的游戏,规则是这样的:

两个玩家首先比出两个1的手势,情况是这样的:

a玩家:左手:1,右手:1

b玩家:左手:1,右手:1

然后决定先后顺序,依次在每个自己的回合做出一下行动:使用自己的左手或右手碰一下对方的左手或右手,然后将碰到的两只手所表示的数值相加,自己碰的那只手就变为该数值。如:

原局面:

a玩家:左手:1,右手:1

b玩家:左手:1,右手:1

a玩家使用左手碰了对方的右手后:

a玩家:左手:1+1=2,右手:1

b玩家:左手:1,右手:1

到b玩家时,b玩家可以用左手碰对方的右手:

a玩家:左手:2,右手:1

b玩家:左手:3,右手:1

谁先将两只手都到达目标数字(一般是10)就赢了

我在一次某讲座上和同学玩这个游戏时突然想到,这个游戏有没有必胜的策略?遂作此程序。(不知道这算不算博弈论了反正先当标题党写上吧)

思路

那当然是!dfs直接打爆力求解!

这部分没什么好说的,不会的可以去我的专栏或B站

于是我们得到以下代码:

#include "bits/stdc++.h"
#include <conio.h>
#include <windows.h>

using namespace std;

bool handMarker[20][20][20][20];
int endNumber, aLeftHand, aRightHand, bLeftHand, bRightHand;
int aMayWin = 0, bMayWin = 0;

void color(int m) {
	HANDLE consolehend;
	consolehend = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleTextAttribute(consolehend, m);
}

void dfs(int aLeftHand, int aRightHand, int bLeftHand, int bRightHand, int step) {
	// 成功后输出
	if ((aLeftHand == endNumber && aRightHand == endNumber) || (bLeftHand == endNumber && bRightHand == endNumber)) {
		if ((step - 1) % 2 == 0) {
			aMayWin++;
		} else {
			bMayWin++;
		}
		// color(0x02);
		for (int i = 1; i <= step - 1; i++) {
			printf(u8"│ ");
		}
		printf(u8"├─");
		printf(u8"%c:Win!:)\n", (step - 1) % 2 + 'a');
		for (int i = 1; i <= step - 1; i++) {
			printf(u8"│ ");
		}
		printf(u8"└─");
		printf(u8"Used Step: %d.\n", step);
		// color(0x0F);
		return ;
	}
	handMarker[aLeftHand][aRightHand][bLeftHand][bRightHand] = 1;
	// 输出
	if (step >= 1) {
		for (int i = 1; i <= step - 1; i++) {
			printf(u8"│ ");
		}
		printf(u8"├─");
		printf(u8"%c:My turn!\n", (step + 1) % 2 + 'a');
		for (int i = 1; i <= step - 1; i++) {
			printf(u8"│ ");
		}
		printf(u8"├─");
		printf(u8"back:a:%d %d  b:%d %d\n", aLeftHand, aRightHand, bLeftHand, bRightHand);
	}
	int newHand;
	if (step % 2 == 0) {
		if (aLeftHand != endNumber) {
			if (bLeftHand != endNumber) {
				newHand = (aLeftHand + bLeftHand) % (endNumber + 1);
				if (newHand == 0) {
					newHand = 1;
				}
				if (!handMarker[newHand][aRightHand][bLeftHand][bRightHand]) {
					dfs(newHand, aRightHand, bLeftHand, bRightHand, step + 1);
				}
			}
			if (bRightHand != endNumber) {
				newHand = (aLeftHand + bRightHand) % (endNumber + 1);
				if (newHand == 0) {
					newHand = 1;
				}
				if (!handMarker[newHand][aRightHand][bLeftHand][bRightHand]) {
					dfs(newHand, aRightHand, bLeftHand, bRightHand, step + 1);
				}
			}
		}
		if (aRightHand != endNumber) {
			if (bLeftHand != endNumber) {
				newHand = (aRightHand + bLeftHand) % (endNumber + 1);
				if (newHand == 0) {
					newHand = 1;
				}
				if (!handMarker[aLeftHand][newHand][bLeftHand][bRightHand]) {
					dfs(aLeftHand, newHand, bLeftHand, bRightHand, step + 1);
				}
			}
			if (bRightHand != endNumber) {
				newHand = (aRightHand + bRightHand) % (endNumber + 1);
				if (newHand == 0) {
					newHand = 1;
				}
				if (!handMarker[aLeftHand][newHand][bLeftHand][bRightHand]) {
					dfs(aLeftHand, newHand, bLeftHand, bRightHand, step + 1);
				}
			}
		}
	}
	if (step % 2 == 1) {
		if (bLeftHand != endNumber) {
			if (aLeftHand != endNumber) {
				newHand = (bLeftHand + aLeftHand) % (endNumber + 1);
				if (newHand == 0) {
					newHand = 1;
				}
				if (!handMarker[aLeftHand][aRightHand][newHand][bRightHand]) {
					dfs(aLeftHand, aRightHand, newHand, bRightHand, step + 1);
				}
			}
			if (aRightHand != endNumber) {
				newHand = (bLeftHand + aRightHand) % (endNumber + 1);
				if (newHand == 0) {
					newHand = 1;
				}
				if (!handMarker[aLeftHand][aRightHand][newHand][bRightHand]) {
					dfs(aLeftHand, aRightHand, newHand, bRightHand, step + 1);
				}
			}
		}
		if (bRightHand != endNumber) {
			if (aLeftHand != endNumber) {
				newHand = (bRightHand + aLeftHand) % (endNumber + 1);
				if (newHand == 0) {
					newHand = 1;
				}
				if (!handMarker[aLeftHand][aRightHand][bLeftHand][newHand]) {
					dfs(aLeftHand, aRightHand, bLeftHand, newHand, step + 1);
				}
			}
			if (aRightHand != endNumber) {
				newHand = (bRightHand + aRightHand) % (endNumber + 1);
				if (newHand == 0) {
					newHand = 1;
				}
				if (!handMarker[aLeftHand][aRightHand][bLeftHand][newHand]) {
					dfs(aLeftHand, aRightHand, bLeftHand, newHand, step + 1);
				}
			}
		}
	}
}

int main() {
	printf("Change to which number will win?");
	scanf("%d", &endNumber); // 输入
	printf("Beginning number?");
	scanf("%d%d%d%d", &aLeftHand, &aRightHand, &bLeftHand, &bRightHand);
	freopen("out.txt", "w", stdout);
	printf(u8"back:a:%d %d  b:%d %d\n", aLeftHand, aRightHand, bLeftHand, bRightHand);
	dfs(aLeftHand, aRightHand, bLeftHand, bRightHand, 0);
	printf(u8"Total Win: a:%d b:%d\n", aMayWin, bMayWin);
	printf(u8"The possibility of a's winning: %.2f%%\n", 1.0 * aMayWin / (aMayWin + bMayWin) * 100);
	printf(u8"The possibility of b's winning: %.2f%%\n", 1.0 * bMayWin / (aMayWin + bMayWin) * 100);
    return 0; 
}

(做了一点输出优化)

如果你想要在控制台看的话就把main()里的freopen注释掉再把dfs里的color函数取消注释。

结果

很神奇

似乎是一个区间一个区间来的

首先,如果目标数是2的话,a玩家完胜:

Total Win: a:4 b:0
The possibility of a's winning: 100.00%
The possibility of b's winning: 0.00%

目标数在3到7的区间里(含3和7)的话,b玩家的胜率先是一下提高,然后缓降:

3:
Total Win: a:8 b:11
The possibility of a's winning: 42.11%
The possibility of b's winning: 57.89%

4:
Total Win: a:21 b:22
The possibility of a's winning: 48.84%
The possibility of b's winning: 51.16%

5:
Total Win: a:32 b:32
The possibility of a's winning: 50.00%
The possibility of b's winning: 50.00%

6:
Total Win: a:48 b:42
The possibility of a's winning: 53.33%
The possibility of b's winning: 46.67%

7:
Total Win: a:86 b:67
The possibility of a's winning: 56.21%
The possibility of b's winning: 43.79%

随后在8到11的区间内又缓升:

8:
Total Win: a:107 b:98
The possibility of a's winning: 52.20%
The possibility of b's winning: 47.80%

9:
Total Win: a:140 b:136
The possibility of a's winning: 50.72%
The possibility of b's winning: 49.28%

10:
Total Win: a:163 b:169
The possibility of a's winning: 49.10%
The possibility of b's winning: 50.90%

11:
Total Win: a:197 b:211
The possibility of a's winning: 48.28%
The possibility of b's winning: 51.72%

而后又降:

12:
Total Win: a:244 b:248
The possibility of a's winning: 49.59%
The possibility of b's winning: 50.41%

(后面没算了有人跑出来的话发一下评论区谢谢了)

(我猜会不会到后面双方胜率无限接近于50%)

(所以这个游戏最好去重玩,保证不会出现重复局面)

总结

我真无聊,写这个破玩意写到现在,明天还要月考(啊我靠1点了???

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值