作者 | Ahab,专注与 Python 数据挖掘、数据分析与机器学习
来源 | Ahab杂货铺
编辑 | Jane
【编者按】之前作者用 Python 做了一款俄罗斯方块的小游戏,这次,作者在原来工作的基础上进行了升级,用 AI 算法实现了一款俄罗斯方块。一起来跟作者学一下吧~
人工智能大火的今天,如果还是自己玩俄罗斯方块未免显得太 LOW,为什么不对游戏升级,让机器自己去玩俄罗斯方块呢?有了这个想法之后利用周六周日两天的时间去搜集了大量的资料,在电脑死机好多次之后终于将 AI 俄罗斯方块实现了。
先看成果:
所谓让机器自己去玩俄罗斯方块,就是让机器计算当前方块的所有形态可放置的所有位置,然后根据统一的评价标准,计算出最优的位置进行放置。这个评价的标准简单的来说就是:板块放置的位置越靠下越好,方块之间越紧密越好,自身对消除行的方块贡献数量越多越好,但是这里还要注意的是不可为了追求消除行数,而去造成过多的空洞,这样也是不合理的。
关于 AI 算法主要有两种:一种是经典的 Pierre Dellacherie 算法,一种基于基于深度搜索的算法。深度搜索需要优化的地方很多,假如计算的层数不够、没有高效的剪枝,一不小心容易写成人工智障,时间复杂度也不好。Pierre Dellacherie 算法更加清晰,复杂度更低。但是该算法只考虑当前,不对未来的情况进行计算,注重的是“不死性”,追求方块的“密集”,有时就算可以一次性消除 3 行,却会使全局方块更加“疏”,即过多的空洞。
代码由三部分组成 Tetris.py、AI.py 和 Utils.py 游戏的主要逻辑由 Tetis 控制,Utils 定义了方块的样式,AI 顾名思义实现了主要的 AI 算法。
只考虑当前方块,不对未来的情况进行计算,注重的是“不死性”,算法每次生成一个方块,便穷举该方块所有旋转的所有落点。一种方块最多有 4 种旋转,并且由于游戏界面是 10*20 的,所以对于每个旋转形状,只需要考虑 10 种落点。算法的核心是一个评估函数,对穷举出的每一种下落情况,计算 6 个参数值,用评估函数加权求和得到一个值,该值最大的情况便是目前方块的最优下落位置,六个参数分别是:
当前方块落下去之后,方块中点距底部的方格数 事实上,不求中点也是可以的。
2.消行数(Rows eliminated)
消行层数与当前方块贡献出的方格数乘积。
从左到右(或者反过来)检测一行,当该行中某个方格从有方块到无方块(或无方块到有方块),
视为一次变换。游戏池边界算作有方块。行变换从一定程度上反映出一行的平整程度,越平整值越小
该指标为所有行的变换数之和
如图:■表示有方块,□表示空格(游戏池边界未画出)
■■□□■■□□■■□□ 变换数为6
□□□□□■□■□■□■ 变换数为9
■■■■□□□□□□■■ 变换数为2
■■■■■■■■■■■■ 变换数为0
列变换从一定程度上反映出一列中空洞的集中程度,空洞越集中值越小
5.空洞数(Number of Holes)
暂不解释
6.井的总和(Well Sums):
井指两边皆有方块的空列。该指标为所有井的深度连加到1再求总和 注意一列中可能有多个井,如图:
■□□
■□■
■□■
■■■
■□■
■□■
■□■
中间一列为井,深度连加到一的和为 (2+1)+(3+2+1)=9
评估函数如下 (首字母简写):
关于方块形态
相对于上次文章中的俄罗斯方块,这里对AI俄罗斯方块的形态做一下特别说明,各个方块都是根据中心点的坐标来生成的,以(0,0)为中心点,在x、y轴加减1则是其他方格的坐标,这个好处就是只要确定中心点坐标,其他的方格位置就能随即生成。看图就懂↓
1# 每种块包含的四个小方块相对坐标分布
2 self.shapes_relative_coords = [
3 [[0, 0], [0, 0], [0, 0], [0, 0]],
4 [[0, -1], [0, 0], [0, 1], [0, 2]],
5 [[0, -1], [0, 0], [0, 1], [1, 1]],
6 [[0, -1], [0, 0], [0, 1], [-1, 1]],
7 [[0, -1], [0, 0], [0, 1], [1, 0]],
8 [[0, 0], [0, -1], [1, 0], [1, -1]],
9 [[0, 0], [0, -1], [-1, 0], [1, -1]],
10 [[0, 0], [0, -1], [1, 0], [-1, -1]]
11 ]
(本文为Python大本营投稿文章,转载请联系作者。)
文末彩蛋~
双十一不学习
是想“剁手”吗
(识别图中二维码,预防剁手、沉迷于学海)
????????