这是一个基于2022牛客多校(七)一道博弈题目K. Great Party做成的取石子博弈小游戏,有关证明比较复杂,有兴趣的可以看我上一条博文
#include#include #include #include #include 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 bb bb 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; }



