继续pygame实现俄罗斯方块游戏(AI篇1)的代码更新
一、消除后才做评价
上一篇我们是对方块落下的位置和落下后出来的空洞进行了评价,但是这些评价都是没有计算消除的,以至于机器人现在不会考虑去进行那些完全不会留下空洞的消除,比如下面这种消除。但我们知道这种消除是不会产生空洞的。
所以我们要在计算评价的时候最好计算消除以后的评价。
我们只要在Matrix的函数里加一个do_clear函数来进行消除
def do_clear(self): for i in range(self.rows-1,-1,-1): if sum(self.cols*i:self.cols*(i+1))==self.cols: self.matrix[self.cols:self.cols*(i+1)]=self.matrix[0:self.cols*i]
然后在clone_matrix.fill_block(center_shape, xdiff=xdiff, ydiff=max_yindex)之后加一行
clone_matrix.do_clear()
现在机器人比以前聪明了一点,但是还有问题,只要有下面两个问题:
1.当有更好的消除方案时,机器人并没有选择更好的方案(比如可以消除两行,但是机器人选择了消除一行)。
2.人玩的时候会避免空的列两边堆叠太高,而是优先在远离空的列附近填。
下面我们进行这些修改。
二、消除时考虑获得更高分
我们在Matrix的do_clear函数里增加一个clear_num来计算消除了多少行
def do_clear(self): clear_num = 0 for i in range(self.rows-1,-1,-1): if sum(self.data[self.cols*i:self.cols*(i+1)])==self.cols: self.data[self.cols:self.cols*(i+1)]=self.data[0:self.cols*i] clear_num+=1 return clear_num
在计算的地方加这样两行
clear_num=clone_matrix.do_clear() score += clear_num * 5
这样每多消除一行会多得到5分,会激励机器人在单次消除中去寻找更好的消除方案。
三、避免空列附近的填塞
首先空列的定义,我们可以认为像下面的图中,1的位置还不能算完全的空列,因为列右侧高起的是两格,拯救的机会比2处大很多,2处两边都已经高起3格,再这样下去只有等长条了。
所以我们在Matrix里加一个空列的获取函数
def get_empty_col(self): miny_arr=[] for x in range(self.cols): miny=19 for y in range(self.rows): miny=y if self.get_val(x,y) == 1:break miny_arr.append(miny) empty_arr=[] if miny_arr[1] - miny_arr[0] > 2: empty_arr.append((self.cols,miny_arr[1] - miny_arr[0])) if miny_arr[self.cols-2] - miny_arr[self.cols-1] > 2: empty_arr.append((miny_arr[self.cols-2] - miny_arr[self.cols-1],self.cols)) for x in range(1,self.cols-1): if miny_arr[x-1]-miny_arr[x]>2 or miny_arr[x+1]-miny_arr[x]>2: empty_arr.append((miny_arr[x-1]-miny_arr[x],miny_arr[x+1]-miny_arr[x])) return empty_arr
在AIPlayer里增加一个get_cost_of_emptycol函数
def get_cost_of_emptycol(self, empty_arr): cost = 0 for l,r in empty_arr: if l>2 and r>2: cost += (l+r)*2 elif l>2: cost += l else: cost += r return cost
在计算分数的地方增加两行程序
empty_arr = clone_matrix.get_empty_col() score -= self.get_cost_of_emptycol(empty_arr)