import random import map_game import copy import math class AIMap: def __init__(self,boardMap: list = None): self.map = [[0 for i in range(4)] for i in range(4)] #初始化 全部清零 self.map = [[boardMap[i][j]for i in range(4)] for j in range(4)] #复制 #AI:向左转! def ai_go_left(self): isAdd = 0 # 表示是否成功移动 for row in range(0,4): index = 0 for col in range(1,4): if self.map[row][col] > 0: if self.map[row][col] == self.map[row][index]: self.map[row][index] = self.map[row][col] + self.map[row][index] self.map[row][col] = 0 index += 1 isAdd = 1 elif self.map[row][index] == 0: self.map[row][index] = self.map[row][col] self.map[row][col] = 0 isAdd = 1 else: index += 1 if self.map[row][index] == 0: self.map[row][index] = self.map[row][col] self.map[row][col] = 0 isAdd = 1 return isAdd #AI:向右转! def ai_go_right(self): isAdd = 0 # 表示是否成功移动 for row in range(0,4): index = 3 for col in range(2,-1,-1): if self.map[row][col] > 0: if self.map[row][col] == self.map[row][index]: self.map[row][index] = self.map[row][col] + self.map[row][index] self.map[row][col] = 0 index -= 1 isAdd = 1 elif self.map[row][index] == 0: self.map[row][index] = self.map[row][col] self.map[row][col] = 0 isAdd = 1 else: index -= 1 if self.map[row][index] == 0: self.map[row][index] = self.map[row][col] self.map[row][col] = 0 isAdd = 1 return isAdd #AI:向前进 def ai_go_up(self): isAdd = 0 # 表示是否成功移动 for col in range(0,4): index = 0 for row in range(1,4): if self.map[row][col] > 0: if self.map[row][col] == self.map[index][col]: self.map[index][col] = self.map[row][col] + self.map[index][col] self.map[row][col] = 0 index += 1 isAdd = 1 elif self.map[index][col] == 0: self.map[index][col] = self.map[row][col] self.map[row][col] = 0 isAdd = 1 else: index += 1 if self.map[index][col] == 0: self.map[index][col] = self.map[row][col] self.map[row][col] = 0 isAdd = 1 return isAdd #AI:向后退 def ai_go_down(self): isAdd = 0 # 表示是否成功移动 for col in range(0,4): index = 3 for row in range(2,-1,-1): if self.map[row][col] > 0: if self.map[row][col] == self.map[index][col]: self.map[index][col] = self.map[row][col] + self.map[index][col] self.map[row][col] = 0 index -= 1 isAdd = 1 elif self.map[index][col] == 0: self.map[index][col] = self.map[row][col] self.map[row][col] = 0 isAdd = 1 else: index -= 1 if self.map[index][col] == 0: self.map[index][col] = self.map[row][col] self.map[row][col] = 0 isAdd = 1 return isAdd #控制AI走不同的方向 走成功为True 走失败为False def ai_go(self,dir):#0左 1右 2上 3下 if dir == 0:#左 if self.ai_go_left() == 1: return True else: return False elif dir == 1:#右 if self.ai_go_right() == 1: return True else: return False elif dir == 2:#上 if self.ai_go_up() == 1: return True else: return False elif dir == 3:#下 if self.ai_go_down() == 1: return True else: return False #数值分析 #格局评价 #作为算法的核心,如何评价当前格局的价值是重中之重。 #在2048中,除了终局外,中间格局并无非常明显的价值评价指标,因此需要用一些启发式的指标来评价格局。 #那些分数高的好格局是容易引向胜利的格局,而分低的坏格局是容易引向失败的格局。 def ai_evaluation(self): #参数需要进行调试 #否则会变成人工智障 #smoothWeight = 0.5 #monoWeight = 0.03 #emptyWeight = 2.7 #maxWeight = 4 #disWeight = 10 #人工智障2.0参数 smoothWeight = 0.5 monoWeight = 0.03 emptyWeight = 2.7 maxWeight = 4 disWeight = 10 result = [disWeight*math.log2(self.dis_weight()), smoothWeight * self.smothness(), monoWeight * self.monotonicity(), emptyWeight*math.log2(self.empty_num() + 1), maxWeight*self.max_and_submax_num()] #人工智障3.0参数 #smoothWeight = 0.1 # 0.5 #monoWeight = 1.0 # 0.03 #emptyWeight = 2.7 # 2.7 #maxWeight = 1 # 0.01 #disWeight = 0 #smoothWeight = 0.5 #monoWeight = 0.03 #emptyWeight = 2.7 #maxWeight = 4 #disWeight = 10 #result = [disWeight*self.dis_weight(), smoothWeight * self.smothness(), monoWeight * # self.monotonicity(), emptyWeight*math.log(self.empty_num()), maxWeight*self.max_num()] return result #单调性 #单调性指方块从左到右、从上到下均遵从递增或递减。 ##一般来说,越单调的格局越好。 #下面是一个具有良好单调格局的例子 # 8 32 64 512 # 4 8 16 256 # 2 4 8 32 # 0 0 4 8 def monotonicity(self): totals = [0,0,0,0] # 四个方向的单调性评估 左 右 上 下(单调递增) #1.横着 for i in range(4): current = 0 next = current+1 while next < 4: while next < 4 and self.map[i][next] == 0: next += 1 if next >= 4: next -= 1 if self.map[i][current] != 0: currentValue = math.log2(self.map[i][current]) else: currentValue = 0 if self.map[i][next] != 0: nextValue = math.log2(self.map[i][next]) else: nextValue = 0 if currentValue > nextValue: totals[0] += nextValue-currentValue else: totals[1] += currentValue-nextValue current = next next += 1 #2.竖着 for i in range(4): current = 0 next = current+1 while next < 4: while next < 4 and self.map[next][i] == 0: next += 1 if next >= 4: next -= 1 if self.map[current][i] != 0: currentValue = math.log2(self.map[current][i]) else: currentValue = 0 if self.map[next][i] != 0: nextValue = math.log2(self.map[next][i]) else: nextValue = 0 if currentValue > nextValue: totals[2] += nextValue-currentValue else: totals[3] += currentValue-nextValue current = next next += 1 return max(totals[:2])+max(totals[2:]) #平滑度 #平滑性是指每个方块与其直接相邻方块数值的差,其中差越小越平滑。 #例如2旁边是4就比2旁边是128平滑。 #一般认为越平滑的格局越好。 #下面是一个具有极端平滑性的例子 # 1024 1024 1024 # 1024 1024 1024 1024 # 1024 1024 1024 1024 # 1024 1024 1024 1024 def smothness(self): lubricity = 0 for i in range(4): for j in range(4): if self.map[i][j] != 0: if i >= 1: # 左边减去该值 lubricity -= abs(math.log2(self.map[i-1][j]+1) - math.log2(self.map[i][j]+1)) if i < 3: # 右边减去该值 lubricity -= abs(math.log2(self.map[i+1][j]+1) - math.log2(self.map[i][j]+1)) if j > 0: # 上面减去该值 lubricity -= abs(math.log2(self.map[i][j-1]+1) - math.log2(self.map[i][j]+1)) if j < 3: # 下面减去该值 lubricity -= abs(math.log2(self.map[i][j+1]+1) - math.log2(self.map[i][j]+1)) return lubricity #空格数 #因为一般来说,空格子越少对玩家越不利。 #空格越多的格局越好。 def empty_num(self): empty_num = 0 for i in range(4): for j in range(4): if self.map[i][j] == 0: empty_num += 1 return empty_num #单个最大的值 def max_num(self): max_num = 0 for i in range(4): for j in range(4): if max_num < self.map[i][j]: max_num = self.map[i][j] return max_num #这个指标评价棋盘的单个数的最大值和总体和 #值越大格局越好 def max_and_submax_num(self): max_num = 0 subMaxNum = 0 for row in range(4): for col in range(4): if max_num < self.map[row][col]: subMaxNum = max_num + subMaxNum; max_num = self.map[row][col] return math.log2(subMaxNum/3+max_num*2/3) #2.0 #return subMaxNum/3+max_num*2/3 #3.0 #分布位置权重 #整体分布越往下,越往右格局越好 def dis_weight(self): #wei = [[12, 13, 25, 50], # [11, 10, 9, 8], # [4, 5, 6, 7], # [3, 2, 1, 0]] wei = [[3, 2, 1, 0], [4, 5, 6, 7], [16, 10, 9, 8], [32,64,128,256]] dis_sum = 0 for j in range(4): for i in range(4): if self.map[i][j] == 0: #对数取值不能为0 否则会计算错误 continue dis_sum += math.log2(self.map[i][j])*wei[i][j] #对数形式 return dis_sum # 计算分散度,越分散得分越高 def islands(self): islandsMark = 0 self.marked = [[True]*4]*4 for i in range(4): for j in range(4): if self.map[i][j] != 0: self.marked[i][j] = False for i in range(4): for j in range(4): if self.map[i][j] != 0 and not self.marked[i][j]: islandsMark += 1 self.mark(i, j, self.map[i][j]) return islandsMark def mark(self, x, y, value): # 四个方向向量,方便遍历时使用 vectors = [[0, 1], [1, 0], [-1, 0], [0, -1]] if x >= 0 and x <= 3 and y >= 0 and y <= 3 and self.map[x][y] != 0 and self.map[x][y] == value and not self.marked[x][y]: self.marked[x][y] = True for direction in range(4): vector = vectors[direction] self.mark(x+vector[0], y+vector[1], value)