博弈小游戏

这是一个基于2022牛客多校(七)一道博弈题目K. Great Party做成的取石子博弈小游戏,有关证明比较复杂,完整证明点着

#include<iostream>
#include<cstdlib>
#include<ctime>
#include<string>
#include<windows.h>
using namespace std;
//新型博弈小游戏 
const int maxm = 50;
const string name = "鑫神";
int arr[10], n, _2p[30];
void prework()
{
	int t = 1;
	for (int i = 1; i < 30; i++)//就要1开始 
	{
		_2p[i] = t;
		t *= 2;
	}
}
inline void err() { cout << "输入有误!请重新输入:"; }
inline bool win(string name)
{
	if (!n)
	{
		cout << name << "获胜!\n";
		return 1;
	}
	return 0;
}
inline void stu()
{
	if (!n)return;
	cout << "当前状况:" << n << "堆石子,数量" << (n != 1 ? "分别" : "") << "为";
	for (int i = 0; i < n; i++)
	{
		cout << arr[i];
		if (i != n - 1)cout << "、";
		else cout << "。\n";
	}
}
void make()
{
	n = rand() % 4 + 3;
	for (int i = 0; i < n; i++)arr[i] = rand() % maxm + 1;
	stu();
}
inline bool subtr(int st, int d, int dst = -1)
{
	if (dst == -1)arr[st] -= d;
	else
	{
		arr[dst] += arr[st];
		arr[st] = 0;
	}
	if (!arr[st])
	{
		for (int i = st; i < n - 1; i++)
		{
			arr[i] = arr[i + 1];
		}
		n--;
		return 0;
	}
	return 1;
}
inline void thinking()
{
	cout << "电脑思考中";
	int times = rand() % 5 + 2;
	while (times--)
	{
		for (int i = 0; i < 3; i++)
		{
			Sleep(200);
			cout << ".";
		}
		cout << "\b \b\b \b\b \b";
	}
	cout << "\r";
}
inline void choose(int id, int d = -1, int f = -1)//记得如果是不合并的记得给f传个0,传入的是按照1开始的顺序来的 
{
	int tn = n;
	subtr(id, f == -1 ? d = arr[id] : d);
	cout << "电脑选定第几个石堆:" << id + 1 << "\n选定取石子个数:" << d << "\n";
	stu();
	if (f == -1 || n < tn)return;
	cout << "电脑选择将剩余石子合并到第几堆(0表示不合并):" << f << "\n";
	if (f != -1 && f)
	{
		subtr(id, -100, --f);
	}
	stu();
}
inline int most(int s)
{
	int k = 0;
	while (s)k++, s >>= 1;
	return k;
}
void game()
{
	cout << "电脑将随机生成n堆石头,为了游戏趣味性也兼顾人脑可玩性,本次游戏保证初始时堆数n在3~6范围内,并且保证每堆石子初始数量不高于" << maxm << "\n";
	cout << "游戏规则如下:玩家每回合有两个步骤的操作,第一个步骤为选定其中任一堆并取任意数量(>=1)的石子,第二个步骤为不再操作或者将选定堆再合并到别的石堆上," << name << "先手,二者轮流操作,直到无法操作判负。祝您游戏愉快!\n";
	cout << name << "选择是(1)否(0)播放“电脑思考中”动画:";
	int tkf;
	while (cin >> tkf && tkf != 0 && tkf != 1)err();
	make();
	int st, m, dst;
	while (1)
	{
		cout << name << "选定第几个石堆:";
		while (cin >> st && (st<1 || st>n))err();
		st--;
		cout << name << "选定取石子个数:";
		while (cin >> m && (m<1 || m>arr[st]))err();
		if (subtr(st, m))
		{
			stu();
			cout << name << "选择将剩余石子合并到第几堆(0表示不合并):";
			while (cin >> dst && (dst<0 || dst>n || dst == st + 1))err();
			if (dst--)subtr(st, -1, dst);
		}
		if (win(name))return;
		stu();
		if (tkf)thinking();
		int s = 0, sk;
		for (int i = 0; i < n; i++)s ^= arr[i] - 1;
		sk = most(s);
		if (n & 1)
		{
			if (n == 1)choose(0);
			else
			{
				for (int i = 0; i < n; i++)
				{
					if (!s || (arr[i] - 1) / _2p[sk] & 1)//!s
					{
						int b = (arr[i] - 1) ^ s, bk = most(b);
						if (!bk)choose(i);
						else for (int j = 0; j < n; j++)
						{
							if (i != j && !((arr[j] - 1) / _2p[bk] & 1))
							{
								int tmp[50], tt = arr[j] - 1, c = 0, bb = 0;
								for (int t = 0; t < bk; t++)
								{
									int bt = b & 1, ttt = tt & 1;
									if (c)
									{
										if (bt)bt = 0;
										else bt = 1;
									}
									tmp[t] = bt;
									if (bt + c + ttt >= 2)c = 1;
									else c = 0;
									tt >>= 1;
									b >>= 1;
									bb += tmp[t] * _2p[t + 1];
								}
								int d = arr[i] - bb;
								choose(i, d, j + 1);
								break;
							}
						}
						break;
					}
				}
			}
		}
		else
		{
			if (!s)
			{
				int id = rand() % n, d = rand() % arr[id] + 1;
				choose(id, d, 0);
			}
			else
			{
				for (int i = 0; i < n; i++)
				{
					if ((arr[i] - 1) / _2p[sk] & 1)
					{
						int d = arr[i] - 1 - ((arr[i] - 1) ^ s);
						choose(i, d, 0);
						break;
					}
				}
			}
		}
		if (win("电脑"))return;
	}
}
int main()
{
	srand((unsigned)time(0));
	prework();
	while (1)
	{
		game();
		system("pause");
		system("cls");
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值