在 C++ 中使用递归将倒计时减法倒计时为零的游戏模式
Subtraction count down to zero game pattern with recursion in c++
使用递归,我必须为一个游戏制作一个AI,其中计算机将从4,3或1中进行选择,并从1到99(包括1到99(之间的给定数字中减去它。这个游戏将在人工智能和人类之间进行。但是,AI 无法从 4、3 或 1 中选择任何随机数。它必须始终选择有助于它赢得游戏的值。此外,当数字像 2 时,人工智能或人类不能选择 4 或 3,因为它大于 2,所以他们必须选择 1。还假设 AI 是玩家 2,而人类始终是玩家 1。
例如:如果起始号码是n = 7,那么玩家1选择1,n = 6,那么计算机选择4和新的n = 2。玩家 1 将选择 1 和 n = 1。然后 AI 将选择 1 和 n = 0。因此,人工智能赢得了比赛。
到目前为止,我对这个问题的看法:
我知道不同的数字,直到 6 应该由 AI 选择(从 4、3 或 1(来赢得比赛。
例如:当 n = 1 时,选择 1 n = 2,选择 1 ; n = 3,选择 3 ; n =4,选择 4 ; n = 5,选择 3 ; n = 6,选择4
;
但是我找不到一种通用算法,可以应用于从 1 到 99 的所有数字以赢得比赛。 我想知道并理解如何获得一个通用的递归方程和递归算法,就像斐波那契级数中的函数递归一样:
斐波那契(n - 1( + 斐波那契(n - 2(
通过AI在4 3或1之间选择数字以赢得比赛。
我没有递归经验,所以请尝试详细解释算法。
我假设不能采取行动的玩家输掉了比赛。 你似乎没有在任何地方提到它,但这就是它的样子。
首先,请注意,每个数字要么是获胜位置,要么是失败位置,供玩家回合,无论它是哪个玩家。 例如,数字 7 是一个失败的位置:如果当前玩家选择 1,另一个玩家以 4 响应;如果是 3 或 4,则分别为 4 或 3。
递归关系如下所示:
win(x) = not win(x-1) or not win(x-3) or not win(x-4)
事实上,如果有一个动作导致亏损,我们可以通过选择这个动作来获胜。如果没有,我们的对手将获胜,假设他们从那时起就打得很完美。
现在,不是实现递归,而是使用它从下到上计算每个数字的输赢状态,并将其存储在数组中,如下所示:
win[0] := false
win[1] := true
win[2] := false
win[3] := true
for x := 4, 5, ..., 99:
win[x] := not win[x-1] or not win[x-3] or not win[x-4]
这样,您只需进行 100 次简单的计算,而不是遍历从数字 99 开始的所有可能游戏的巨大递归树。
现在,计算了这个win
数组,如何从数字x
移动? 如果win[x] = false
,任何一步都可以:如果我们的对手打得完美,我们无论如何都会输。 如果win[x] = true
,找出win[x-1]
、win[x-3]
和win[x-4]
中存在(小心下溢!(并且是假的,然后进行该移动。
最后,观察计算数组如下所示:
[0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1]
显然,有一个周期 7. 因此,对于这个确切的游戏,只需查看我们的数模 7 的其余部分,就可以完全不使用数组来制定自定义策略。 事实上,你在问题中几乎做到了,只是在前面加上"余模 7 是......"并添加一些关于零的内容:
例如:当 n = 1 时,选择 1 n = 2,选择 1 ; n = 3,选择 3 ; n =4,选择 4 ; n = 5,选择3 ; n = 6,选择 4 ;
这是我针对您的问题的代码,它可能会对您有所帮助
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int main(){
//init nimbers
int arr[100];
fill(arr,arr+100,-1);
arr[0]=0;
queue<int> q;
q.push(0);
while(q.size()>0){
int u=q.front();
q.pop();
if (u+1<100 && arr[u+1]!=1)
{
arr[u+1]=(arr[u]+1)%2;
q.push(u+1);
}
if (u+3<100 && arr[u+3]!=1)
{
arr[u+3]=(arr[u]+1)%2;
q.push(u+3);
}
if (u+4<100 && arr[u+4]!=1)
{
arr[u+4]=(arr[u]+1)%2;
q.push(u+4);
}
}
int n=7;
cout<<"Welcome to the Gamen";
cout<<"You are player 1n AI is player 2n";
int play=0;
while(n>0){
if (play%2==0)
{
int step=-1;
cout<<"Enter your move?";
cin>>step;
n-=step;
cout<<"Now n="<<n<<endl;
}
else{
int step=1;
if(n-1>=0 && arr[n-1]==0) step=1;
if(n-3>=0 && arr[n-3]==0) step=3;
if(n-4>=0 && arr[n-4]==0) step=4;
n-=step;
cout<<"AI played "<<step<<" moven";
cout<<"Now n="<<n<<endl;
}
play=(play+1)%2;
}
if (play)
{
cout<<"You won";
}
else cout<<"AI won";
return 0;
}
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 为什么在保护模式下继承升级不起作用
- 如何在全屏模式下(在OpenGL中)使背景透明
- 为什么使用__LINE_的代码在发布模式下在MSVC下编译,而不是在调试模式下
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- 此模式的C++RegEx
- avrogencpp能为模式中的每种类型生成单独的头文件吗
- 使用可变模板的Broadcaster/Listener模式
- c++方法参数只能在linux的发布模式下自行更改
- 资源管理设计模式
- 使用 mod_gsoap 部署服务时,如何在 Gsoap 中更改 soap 上下文的模式?
- C++ 无法在字符数组中使用 for 循环打印字母模式
- 小字符串优化(调试与发布模式)
- 可视化C++:发布模式的运行时库作为'Multi-threaded Debug DLL'
- 如何设计具有不同类型的通知和观察器的观察者模式?
- 在C++的一系列数字中查找重复模式
- 是否允许使用带有"w+"模式的 freopen 进行标准设置?
- C++ 使用存储在动态数组中的文本文件中的数据查找模式
- С++ wxWidgets:代码架构,设计原则和模式
- 在 C++ 中使用递归将倒计时减法倒计时为零的游戏模式