游戏中的人机对战是啥原理?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了游戏中的人机对战是啥原理?相关的知识,希望对你有一定的参考价值。

参考技术A 人机中的“机”就是指电脑AI,它的行为就是一系列提前设计好的行为根据不同条件租和成的,专业点叫做“行为树”

程序员可以提前设计好电脑的行为,跑、跳、攻击、防守等等,然后将其与条件绑定在一起。比如玩家跑,电脑就执行跑;玩家攻击,电脑就执行防御;玩家不动,电脑就执行攻击;

人机对战的难度,其实就是电脑AI设置的难度,你觉得电脑简单,是因为这个难度设计的状态行为相对简单。

人机中的套路,基本上就是电脑的程序漏洞,除了电脑自行学习和随机要素两点之外,在A条件下必定触发B动作的情况,还是非常多的,只要玩家抓住这种技巧,就能轻松战胜电脑。各种类型的 游戏 中都能找到体现。

人机对战就是这么简单的原理

你好,我是阿恒,非常愿意解答这个问题。

首先和人机对战的人无非就三种心理。

1.体验乐趣的心理,有许多小伙伴打匹配模式打不赢玩家,老是被他人单杀,这这就让他十分恼火,感觉打不赢,所以才会去打人机,体验赢的感觉。

2.优越的心理。那些在匹配模式打不赢玩家的小伙伴,就想在人机中大杀四方,体验优越的感觉。

3.提升自己技术的心理。有的小伙伴,为了把某些英雄玩好,不坑队友,就疯狂的打人机去练习自己的技术,只为把这个英雄玩好。

如果大家觉得阿恒说的有道理,可以关注一下,非常乐意和大家一起分享 游戏 里的日常。

游戏 中的人力对战,或者说NPC(怪物也可以说成 游戏 里面的NPC)的AI主要采用“行为树”和“状态机”两种模式。(比较形象的解释,可能不太准确)行为树就像给了你很多锦囊,符合哪种条件你就开锦囊,然后按照指示继续做。状态机就像竖了几个牌,符合这个状态你就要做什么。行为树和状态机和单独使用,也可以结合使用。

我举个例子:在一个MMO 游戏 中的小怪,比如1级哥布林。他被放入了几条命令。

1:会在A→B之间来回巡逻(忽略速度)。

2:可以发现周身半径5米的敌人。

3:求救技能,可以寻找周身半径5米以内的同类来帮助,释放条件时自身血量少于50%。

4:战斗,直至死亡。

看到这几个简单的命令,我们可以想象到。我从这个哥布林身边经过,他就发现我,然后开打。打到一半发现搞不过我,就呼叫同伴来群殴(1级怪物有这个难度有点卑鄙)。不会逃跑(还好),然后力战而死。

这就是一个简单的行为树的NPC的AI设计方案。

所以以前不论是MMO的BOSS,还是MOBA、FPS、赛车等等其他类型的 游戏 ,我们可以设置很多很复杂的条件。这种情况考虑的越周密,那么玩家能够感到这个AI越难,或者越真实。总之,就是靠设计者不断地去添砖加瓦,丰富这个AI。

2、在深度学习算法出来以后,目前大多数 游戏 的怪物AI还是采用以前的模式,深度学习算法更多的被运用到匹配等规则较明确的功能当中。 游戏 中为什么不用深度学习算法来做AI呢?有几个先决条件要解决:

1:如何将你的规则明确化。深度学习算法不是万金油,你得先让电脑懂这套规则,才能开始学习。电脑不是人类,教几次就会,你得帮他总结规则。所以规则复杂的 游戏 ,有一道坎。万一你版本更新,改规则了,又得让机器知道,帮他重新迭代下。程序想要打死产品经理的节奏。

2:通过人机对战获得大数据。这个在尤其上线运营之后还好解决,不过研发阶段就得自己想办法机器和机器打了。

虽然新闻上说深度学习算的电脑可以玩星际争霸,玩dota等等。但是让他来玩我们 游戏 试试?

以上是一个门外汉的介绍,不对勿怪。

AI 游戏 里的机器人十分复杂,首先他有不同的状态,而在不同的状态条件下执行不同的行为。你要让AI像人,那你得把人的行为尽可能的用树状结构进行分类并且得出不同的执行目标。

这里就要提到机器学习,机器学习是什么呢?——使计算机无需编程即可行动的科学。深度学习是机器学习的一个子集,用非常简单的术语来说,它可以被认为是预测分析的自动化。常用的机器学习算法有:

监督学习:标记数据集,以便可以检测模式并用于标记新数据集

无监督学习:数据集未标记,并根据相似性或差异进行排序

强化学习:数据集没有标记,但在执行动作或多个动作后,AI系统会得到反馈

所以,在提到AI的时候总是和大数据相关联,没有数据的支持人工智能离人工智障不远了。

这个非常的简单其实他就是一段程序。

举个大家都比较熟悉的例子,早先还没有互联网的年代,就有了很多PC 游戏 (或者其他形式)。这种 游戏 都是单机的(受当时互联网的限制)。拿一个单机的象棋 游戏 来说,制作者想让这个 游戏 有市场,有人爱玩。那么首先要解决的就是玩家跟谁玩的问题。在那个年代,能做的事情最简单的就是用程序去模拟一个对手。至于怎么模拟,设计的人显然就是要用程序去实现一种方式,让玩家感觉“对手”像人。那么这段程序其实是“机器”在跑,只不过模拟人的行为,所以就有了人机对战这个说法。

可以算是一种人工智能算法,但是那个年代应该还没有机器学习。当然,如果一个 游戏 的“机器”代码,写的复杂一点,能不停的从跟玩家对战的行为中不断的建立自己的“数据库”,并从中演化出更深、更广的行为,其实也就是在机器学习了。我相信在现在的机器学习的词语出现前,一定有这样的 游戏 。但是 游戏 中的AI定义和目前科学上的AI定义不完全一样。

科学的AI比较偏向机器学习,也就是得学习的。

游戏 中绝大多数的AI都是定死的逻辑,也不用学习。比如最常见的就是警戒范围,在魔兽3里的有攻击性的中立单位,如果你不靠近到一定范围内,他是不会靠近攻击的。



段位越高人机越强,且自带透视 在皇冠局及以上没抢碰到人机基本上就是死

就是玩家和电脑bot对战

1让萌新练枪提高自己的胆识

2可以更好的帮助听声辩位

3可以算人头分

4可以提高自己的kda

有请坦克世界资深AI之父,二雷来回答。

人机就是AI, 游戏 团队设置的AI,所以他可以与你对战

井字棋(人机对战版)

游戏介绍

井字棋,英文名叫Tic-Tac-Toe,是一种在3*3格子上进行的连珠游戏,和五子棋类似。然后由分别代表O和X的两个游戏者轮流在格子里留下标记(一般来说先手者为X),任意三个标记形成一条直线(包括行、列、对角线、反对角线),则为获胜。

解决策略

重点在于电脑方如何下棋,我们采取估计棋局每个位置的权重,首先要对棋局进行分类。

---3个为空,重要性最低,权值设置为1    //视为暂时不管

---2个空1个对方,重要性次低,权值为10    //一下三个区别不大,可比较随意的设置

----1个空格1个对方1个己方,重要行较低,权值50 

----2个空格1个己方,重要性较高,权值为100

---1个空格2个对方,重要性次高,权值500  //不堵住会输

---1个空格2个己方,重要性最高,权值1000    //可以直接赢

注意几点:

1、权值之间的间距可以设大一点

2、对每个空位置,权值等于行权值+列权值+对角线权值+反对角线权值,这4中权值都可以用上面的估算,但不做改进会出bug

考虑如下情况:

(1,3)-->(3,1)-->(1,1)-->(2,1)电脑就输了

技术分享图片---->技术分享图片--->技术分享图片-->技术分享图片-->人获胜

关键在于第二步,应该选择一个非角的位置,原因在于此时右上角位置的权值大于中上位置,分析权值的来源

右上角时,10+10+100(对角线己方),而中上时,10+100(行己方),所以同样是2空1己方时,己方位于行或列的权重应大于己方位于对角线

所以按行或列计算时,2空1己方的权值可改为200

代码实现

  1 #include<stdio.h>
  2 #include<Windows.h>
  3 
  4 const int ROW = 3;
  5 const int COL = 3;
  6 int chessboard[ROW][COL];
  7 int score[ROW][COL];
  8 
  9 void Initmap();
 10 void Showmap();        //打印棋局
 11 bool isWin();        //判断是否有一方获胜
 12 bool isFull();        //判断棋盘是否为满
 13 void PcPlay();        //电脑下棋
 14 void HumanPlay();    //人下棋
 15 
 16 int main()
 17 {
 18     Initmap();
 19     Showmap();
 20     while ((!isFull()) && (!isWin()))
 21     {
 22         HumanPlay();
 23         system("cls");
 24         Showmap();
 25         if (isWin())
 26             break;
 27 
 28         Sleep(500);    //模拟实际过程,让电脑慢点,hh
 29         PcPlay();
 30         system("cls");
 31         Showmap();
 32     }
 33 
 34     if (isFull())
 35         printf("

平局
");
 36 
 37     system("pause");
 38     return 0;
 39 }
 40 
 41 void Initmap()
 42 {
 43     for (int i = 0; i < ROW; i++)
 44         for (int j = 0; j < COL; j++)
 45             chessboard[i][j] = 1;
 46 }
 47 
 48 void Showmap()
 49 {
 50     for (int i = 0; i < ROW; i++)
 51     {
 52         for (int j = 0; j < COL; j++)
 53         {
 54             if (chessboard[i][j] == 1)    //"1"代表空
 55                 printf("");
 56             if (chessboard[i][j] == 2)    //"2"代表人
 57                 printf("");
 58             if (chessboard[i][j] == 5)    //"5"代表电脑
 59                 printf("");
 60         }
 61         printf("
");
 62     }
 63 }
 64 
 65 bool isWin()
 66 {
 67     int sum = 0;
 68     for (int i = 0; i < ROW; i++)      //对每行判断是否获胜
 69     {
 70         for (int j = 0; j < COL; j++)
 71             sum += chessboard[i][j];
 72 
 73         if (sum == 6)
 74         {
 75             printf("人获胜!
");
 76             return true;
 77         }
 78         if (sum == 15)
 79         {
 80             printf("电脑获胜!
");
 81             return true;
 82         }
 83         sum = 0;
 84     }
 85 
 86     for (int j = 0; j < ROW; j++)      //对每列判断是否获胜
 87     {
 88         for (int i = 0; i < COL; i++)
 89             sum += chessboard[i][j];
 90 
 91         if (sum == 6)
 92         {
 93             printf("人获胜!
");
 94             return true;
 95         }
 96         if (sum == 15)
 97         {
 98             printf("电脑获胜!
");
 99             return true;
100         }
101         sum = 0;
102     }
103 
104     for (int i = 0; i < ROW; i++)     //对对角线判断是否获胜
105         sum += chessboard[i][i];
106     if (sum == 6)
107     {
108         printf("人获胜!
");
109         return true;
110     }
111     if (sum == 15)
112     {
113         printf("电脑获胜!
");
114         return true;
115     }
116 
117     sum = 0;
118     for (int i = 0; i < ROW; i++)     //对反对角线判断是否获胜
119         sum += chessboard[i][2 - i];
120     if (sum == 6)
121     {
122         printf("人获胜!
");
123         return true;
124     }
125     if (sum == 15)
126     {
127         printf("电脑获胜!
");
128         return true;
129     }
130 
131     return false;
132 }
133 
134 bool isFull()
135 {
136     for (int i = 0; i < ROW; i++)
137         for (int j = 0; j < COL; j++)
138             if (chessboard[i][j] == 1)
139                 return false;
140     return true;
141 }
142 
143 void HumanPlay()
144 {
145     int x, y;
146     printf("请输入棋子的横坐标X:");
147     scanf_s("%d", &x);
148     printf("请输入棋子的纵坐标Y:");
149     scanf_s("%d", &y);
150 
151     while (x < 1 || x>3 || y < 1 || y>3)
152     {
153         printf("
请正确输入!
");
154         printf("x,y均属于1~3

");
155 
156         printf("请输入棋子的横坐标X:");
157         scanf_s("%d", &x);
158         printf("请输入棋子的纵坐标Y:");
159         scanf_s("%d", &y);
160     }
161 
162     while (chessboard[3 - y][x - 1] != 1)
163     {
164         printf("

该位置已被占用!
");
165         printf("请选择正确的位置

");
166         Sleep(1000);
167 
168         printf("
请输入棋子的横坐标X:");
169         scanf_s("%d", &x);
170         printf("请输入棋子的纵坐标Y:");
171         scanf_s("%d", &y);
172     }
173 
174     chessboard[3 - y][x - 1] = 2;
175 }
176 
177 void PcPlay()
178 {
179     int sum = 0;
180     for (int i = 0; i < ROW; i++)
181         for (int j = 0; j < COL; j++)
182             score[i][j] = 0;
183 
184     // 对每行进行分数统计
185     for (int i = 0; i < ROW; i++)
186     {
187         for (int j = 0; j < COL; j++)
188             sum += chessboard[i][j];
189 
190         switch (sum)
191         {
192         case 3:                     //1+1+1;重要性:最低;权重:1
193             for (int k = 0; k < COL; k++)
194             {
195                 if (chessboard[i][k] == 1)
196                     score[i][k] += 1;
197             }
198             break;
199         case 4:                     //1+1+2;重要性:次低;权重:10
200             for (int k = 0; k < COL; k++)
201             {
202                 if (chessboard[i][k] == 1)
203                     score[i][k] += 10;
204             }
205             break;
206         case 8:                    //1+2+5;重要性:较低,权值50
207             for (int k = 0; k < COL; k++)
208             {
209                 if (chessboard[i][k] == 1)
210                     score[i][k] += 50;
211             }
212             break;
213         case 7:                     //1+1+5;重要性:较高;权重:200
214             for (int k = 0; k < COL; k++)
215             {
216                 if (chessboard[i][k] == 1)
217                     score[i][k] += 200;     //把行列的重要性比对角线高
218             }
219             break;
220         case 5:                     //1+2+2;重要性:次高;权重:500
221             for (int k = 0; k < COL; k++)
222             {
223                 if (chessboard[i][k] == 1)
224                     score[i][k] += 500;
225             }
226             break;
227         case 11:                     //1+5+5;重要性:最高;权重:1000
228             for (int k = 0; k < COL; k++)
229             {
230                 if (chessboard[i][k] == 1)
231                     score[i][k] += 1000;
232             }
233             break;
234         }
235         sum = 0;
236     }
237 
238     // 对每列进行分数统计
239     for (int j = 0; j < COL; j++)
240     {
241         for (int i = 0; i < ROW; i++)
242             sum += chessboard[i][j];
243 
244         switch (sum)
245         {
246         case 3:                   
247             for (int k = 0; k < COL; k++)
248             {
249                 if (chessboard[k][j] == 1)
250                     score[k][j] += 1;
251             }
252             break;
253         case 4:                    
254             for (int k = 0; k < COL; k++)
255             {
256                 if (chessboard[k][j] == 1)
257                     score[k][j] += 10;
258             }
259             break;
260         case 8:                    
261             for (int k = 0; k <
262                 COL; k++)
263             {
264                 if (chessboard[k][j] == 1)
265                     score[k][j] += 50;
266             }
267             break;
268         case 7:                    
269             for (int k = 0; k < COL; k++)
270             {
271                 if (chessboard[k][j] == 1)     //1+1+5;重要性:较高;权重:200
272                     score[k][j] += 200;  
273             }
274             break;
275         case 5:                    
276             for (int k = 0; k < COL; k++)
277             {
278                 if (chessboard[k][j] == 1)
279                     score[k][j] += 500;
280             }
281             break;
282         case 11:                  
283             for (int k = 0; k < COL; k++)
284             {
285                 if (chessboard[k][j] == 1)
286                     score[k][j] += 1000;
287             }
288             break;
289         }
290         sum = 0;
291     }
292 
293     // 对对角线进行分数统计
294     for (int i = 0; i < ROW; i++)
295         sum += chessboard[i][i];
296     switch (sum)
297     {
298     case 3:                    
299         for (int i = 0; i < COL; i++)
300         {
301             if (chessboard[i][i] == 1)
302                 score[i][i] += 1;
303         }
304         break;
305     case 4:                   
306         for (int i = 0; i < COL; i++)
307         {
308             if (chessboard[i][i] == 1)
309                 score[i][i] += 10;
310         }
311         break;
312     case 8:                
313         for (int i = 0; i < COL; i++)
314         {
315             if (chessboard[i][i] == 1)
316                 score[i][i] += 50;
317         }
318         break;
319     case 7:                     //1+1+5;权重:100
320         for (int i = 0; i < COL; i++)
321         {
322             if (chessboard[i][i] == 1)
323                 score[i][i] += 100;
324         }
325         break;
326     case 5:                
327         for (int i = 0; i < COL; i++)
328         {
329             if (chessboard[i][i] == 1)
330                 score[i][i] += 500;
331         }
332         break;
333     case 11:                    
334         for (int i = 0; i < COL; i++)
335         {
336             if (chessboard[i][i] == 1)
337                 score[i][i] += 1000;
338         }
339         break;
340     }
341 
342     // 对反对角线进行分数统计
343     sum = 0;
344     for (int i = 0; i < ROW; i++)
345         sum += chessboard[i][2 - i];
346     switch (sum)
347     {
348     case 3:                    
349         for (int i = 0; i < COL; i++)
350         {
351             if (chessboard[i][2 - i] == 1)
352                 score[i][2 - i] += 1;
353         }
354         break;
355     case 4:                    
356         for (int i = 0; i < COL; i++)
357         {
358             if (chessboard[i][2 - i] == 1)
359                 score[i][2 - i] += 10;
360         }
361         break;
362     case 8:
363         for (int i = 0; i < COL; i++)
364         {
365             if (chessboard[i][2 - i] == 1)
366                 score[i][2 - i] += 50;
367         }
368         break;
369     case 7:                     
370         for (int i = 0; i < COL; i++)
371         {
372             if (chessboard[i][2 - i] == 1)    //1+1+5;权重:100
373                 score[i][2 - i] += 100;
374         }
375         break;
376     case 5:                   
377         for (int i = 0; i < COL; i++)
378         {
379             if (chessboard[i][2 - i] == 1)
380                 score[i][2 - i] += 500;
381         }
382         break;
383     case 11:                    
384         for (int i = 0; i < COL; i++)
385         {
386             if (chessboard[i][2 - i] == 1)
387                 score[i][2 - i] += 1000;
388         }
389         break;
390     }
391 
392     int maxRow = 0, maxCol = 0;
393     for (int i = 0; i < ROW; i++)
394         for (int j = 0; j < COL; j++)
395         {
396             if (score[i][j] > score[maxRow][maxCol])
397             {
398                 maxRow = i;
399                 maxCol = j;
400             }
401         }
402     chessboard[maxRow][maxCol] = 5;
403 }

 

以上是关于游戏中的人机对战是啥原理?的主要内容,如果未能解决你的问题,请参考以下文章

结队-人机对战象棋游戏-项目进度

井字游戏 人机对战 java实现

C#五子棋小游戏源码(人机对战)

C语言实现五子棋三子棋人机对战,包含电脑人工智能对战(可攻可守)(非标题党)

Java实现中国象棋(人机对战)

Java实现中国象棋(人机对战)