作者LaPass (LaPass)
看板GameDesign
标题Re: [请益] 关於一些游戏的AI
时间Thu Dec 6 23:10:18 2012
让我们先看个温馨感人的影片
https://www.youtube.com/watch?feature=player_embedded&v=Q4gTV4r0zRs
演算法真的很重要.....
如果想用随机落子去算完五子棋所有可能的话
回圈总共要跑 (15*15)! 次
其实,只要稍微加上一点方式去计算一下
就可以知道哪些是废步,那些是可能棋步,那些是必要的步数(不下那边就会输)
http://i.imgur.com/NMOWU.jpg
最左上角是相邻判断
判断方式很简单,就是
100010001
021121120
013232310
012444210
1234棋4321
012444210
013232310
021121120
100010001
不论黑白、权重都一样
这样可以把可能的走法压缩到25步之内
右上角是棋型评分判断
简单来讲,就是假设落子到那点後
会生成怎麽样的棋型......
这部分先搁着
来讲一下胜负判断
五子棋因为是「棋子连在一起」才能得胜
也就是说,所有胜负、威胁都只跟落子那一点有关
因此,我判断胜负时
会指定某点(落子点),以那一点向外(上下左右、以及四个斜向)去找看看棋型种类
最後找到的可能棋型,会是这21种之一
落子点 → 向外
O O O O O
O O O O X
O O O O 。
O O O 。 。
O O O X *
O O O 。 X
O O X * *
O O 。 X *
O O 。 。 *
O X * * *
O 。 X * *
O 。 。 * *
O O O 。 O
O O 。 O O
O 。 O O O
O O 。 O 。
O O 。 O X
O 。 O O 。
O 。 O O X
O 。 O X *
O 。 O 。 *
X是异色或是墙壁
。是空格
*是任意,代表是什麽都不会有影响
然後再去找对称的位置,看另外一边的棋型是什麽
就能知道,这一条线上是连成五子,或是单四、跳格四、活三....
***OXX。O* 0
***OXX。。* 21 单二
***OXO*** 0 没有
**O。XXXXX 50 五子
**O。XXXXO 41 单四
**O。XXXX。 42 双四
(略)
两边组合一下,可能性有 21*20/2+21=231种 (两边可以互换,所以不是21*21)
因为才231种而已,就手动判断一下棋型,做成列表
在跑程式时让程式去查表,判断棋型
回到右上角的棋型评分判断
只要能知道落子後会生成什麽棋型
就可以给每种棋型一种分数,然後去计算那个点的分数
这实质上跟判断胜负是一样的
/*
link[0][5]=0; //直接获胜 (五子)
link[0][4]=0; //单四、活四
link[0][3]=0; //活三
link[0][2]=0; //活二、单二
link[0][1]=0; //被完全堵死
link[0][0]=0; //block数 block越多越糟糕
*/
//评价公式
int ans= k[0][4]*50+k[0][3]*30+k[0][2]*2-k[0][1]*3-k[0][0]*2
+k[1][4]*35+k[1][3]*10+k[0][2]*1-k[1][1]*2+k[1][0]*1;
这边就只是调整参数而已
我不期望每次都能算出最佳解答
我写这个只是,想用暴力去找出必胜棋步时,比较有效率一点而已
是期望将正确棋步压缩在十五步之内,最好在十步之内就能找出来。
至於下面那张图是把距离跟相邻判断做一下相加
因为有时候AI会下到远的地方去
目前是想把算过的棋步记录在资料库中
这样可以省下很多重覆计算的步骤
例如,同样的盘面,不论落子顺序为何,都不会影响判断出来的棋步
还有,在存棋步时,其实可以旋转一下、镜射一下
这样马上就能做出其他8张棋谱的数据了。(三次旋转、一次镜射)
是想问.....
算完这些步数後,怎麽抓出必胜棋谱的路径树出来?
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 114.38.75.195
1F:推 s3748679:推前面的想法与插图.. 後面的问题@_@" 交给楼下加油 12/07 00:10
2F:推 cowbaying:这串差不多可以收精华了 XDDD 12/07 01:08
3F:推 cowbaying:暂时收录在z-4-13-7-22 12/07 01:10
4F:→ cowbaying:帮我更正一下 是z-4-13-7 12/07 01:11
5F:推 LayerZ:睡前灵光一闪,如果是找必败棋步呢.. 12/07 01:38
6F:→ LayerZ:感觉有两个问题,计算权重应该只有8个方向有意义吧,再判断 12/07 01:48
7F:→ LayerZ:有没有被挡住或是墙壁,才会归零,另外就是防守,有时候对 12/07 01:49
8F:→ LayerZ:方要连起来会不得不防守,原本预测就会被打乱? 12/07 01:50
9F:→ LayerZ:变成,黑、白要同时计算权重,在胜利的权重减掉对方会胜利 12/07 01:51
10F:→ LayerZ:的权重才会做出更好的预测? 不然就要计算这步下去几步内会 12/07 01:52
11F:→ LayerZ:不会被封死或被胜利,如果必败就跳过,再来选比较好的? 12/07 01:52
12F:→ LayerZ:唔,我又发作了= =我临时想的可能没你考虑的多,如果有乱七 12/07 01:53
13F:→ LayerZ:八糟的地方欢迎打脸(死 12/07 01:53
14F:推 ddavid:如果是要用穷举逆推,你要把所有跑过的盘面都存下来并建立 12/07 04:36
15F:→ ddavid:关联,也就是你要知道从那个盘面走一步可以到哪些盘面。 12/07 04:37
16F:→ ddavid:然後就是做逆推判断了,简单的几点判断: 12/07 04:37
17F:→ ddavid:1.一个轮到X下的盘面只要能通往任何一个被标为胜的盘面,那 12/07 04:38
18F:→ ddavid: 这个盘面就也是该被标为胜的盘面。 12/07 04:38
19F:→ ddavid:2.一个轮到X的盘面只要所有可通往的盘面都被标为败,那这个 12/07 04:39
20F:→ ddavid: 盘面就要标为败。 12/07 04:40
21F:→ ddavid:上面那些胜、败都要改为X胜跟X败XD 12/07 04:40
22F:→ ddavid:然後就用以上原则,从下到结束确定胜负的盘面逆推回去这样 12/07 04:41
23F:推 Grunt:哈哈哈,开头的影片快把我笑死了 12/07 09:40
24F:→ LaPass:等等,那是删除多余节点後的树才会通往全胜。 12/07 09:44
25F:推 LayerZ:"要通往全胜"本身就是个盲点了不是? 12/07 09:51
26F:→ LayerZ:这句话我解释成,"去掉所有不会赢的节点,再加入所有会赢的 12/07 09:53
27F:→ LayerZ:节点"..这东西不管怎麽用演算法包起来,还是穷举法阿 12/07 09:53
28F:→ LaPass:找路径好像还蛮难的.... orz..... 12/07 11:41
29F:推 LayerZ:一个节点找下去就是一个tree 如果找到底是能破解所有组合 12/07 12:45
30F:→ LayerZ:问题应该在怎麽加判断,找到第几层该收手? 12/07 12:45
32F:→ LaPass:那我就来写个网页板的 XD 12/07 12:51
34F:推 s3748679:难道就不能用穷举法把结果存起来.. 对战时再取要的部分? 12/07 20:37
35F:推 cowbaying:这个资料结构要很强... 12/07 20:43
36F:→ LaPass:好像翻到Alpha-Beta 搜索之类的关键字,可是我看不懂 = = 12/07 21:04
37F:→ LaPass:谁来个连半路出家的看的懂的教学啊 囧" 12/07 21:05
39F:推 yoco315:观念好像怪怪的 XD 12/07 21:35
40F:→ LaPass:那边怪怪的? @@ 12/08 02:29
41F:→ ddavid:首先我先澄清一下,当你提到「穷举法」的时候基本上我假设 12/08 02:35
42F:→ ddavid:你是要算到完的,这种情况下就是用我的方法逆推回去就好。 12/08 02:36
43F:→ ddavid:如果你并没有要算到完,那你就必须要写有一个基本规则之外 12/08 02:37
44F:→ ddavid:的评分机制(人为制定的)来算出每个子节点的分数。Alpha- 12/08 02:37
45F:→ ddavid:Beta就是往下算个n层,然後又从那n层逆推回来找出最佳的分 12/08 02:38
46F:→ ddavid:数。那个逆推过程其实很接近穷举逆推,只是把「必胜」跟「 12/08 02:38
47F:→ ddavid:必败」调整为分数的高低。 12/08 02:39
48F:→ ddavid:比如一个轮到我方下A node,其child分别为10 20 30分,因为 12/08 02:40
49F:→ ddavid:是轮我下,所以我一定可以选最高分的,因此A就可计为30分。 12/08 02:40
50F:→ ddavid:反之一个轮对手下的B node,其children分别为10 20 30(都 12/08 02:41
51F:→ ddavid:当做是你的得分,实际写时有可能要考虑分数是我方的或对方 12/08 02:41
52F:→ ddavid:的),那因为你要认为对手一定可以走到对你最不利的下法, 12/08 02:42
53F:→ ddavid:因此B node的分数逆推上来计为10分。就这样一路回推回目前 12/08 02:42
54F:→ ddavid:着手的node,选最高分的走下去这样。 12/08 02:42
55F:→ ddavid:简单原则:我方着手的分数是所有子节点取最高分,对方着手 12/08 02:43
56F:→ ddavid:的分数是所有子节点取最低分。 12/08 02:43
57F:→ ddavid:剩下就看你推的层数及Evaluation function够不够好了这样。 12/08 02:44
58F:→ ddavid:然後因为取最高最低的情况,就会有些东西你发现不用算完就 12/08 02:45
59F:→ ddavid:肯定可以被cut掉,那就是alpha-beta里面做的pruning了 12/08 02:46
60F:推 ddavid:致歉修正一下,上面那个逆推过程其实只是Minimax这样,加入 12/08 02:49
61F:→ ddavid:预测函数做pruning之後才是alpha-beta这样XD 12/08 02:49