|
|
|
@ -1,345 +0,0 @@
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|