You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

271 lines
9.8 KiB

#人工智障
import time
import pygame
import random
import map_game
import button_event
from map_config import *
from button import *
import copy
import math
import AI_map #AI专用地图
import sound
#导入win32api 用于弹出窗口
import win32api,win32con
from search_result import *
lastTime = int(time.time()*1000)
game_state = 0 #0为手动 1为AI
#0左 1右 2上 3下
def ai_find_direction():
#dir = random.randint(0,3) #人工智障1.0 随机数生成
dir = lanmeng() #人工智障2.0 (贪心算法)
#dir = lanmeng2() #人工智障3.0 (minimax算法 但经过试验 效果比2.0还要差 而且速度很慢所以放弃)
return dir
#AI继续启动吧
def ai_2048_game_going(speed = 500):
global lastTime
global game_state
if map_game.judge_gameover() == False and map_game.judge_gamewin() == False:
#map_game.sound_flag = 0
for event in pygame.event.get():
#按钮事件检测
button_event.buttonBase.check_event(event)
button_event.buttonReturn.check_event(event)
button_event.buttonAI.check_event(event)
button_event.buttonTips.check_event(event)
button_event.buttonReshow.check_event(event)
if event.type == pygame.KEYDOWN:
if(event.key == pygame.K_z):#Z键加快速度
if map_game.ai_delay_time > 50:
map_game.ai_delay_time = map_game.ai_delay_time - 50
if(event.key == pygame.K_x):#X键减慢速度
if map_game.ai_delay_time < 1000:
map_game.ai_delay_time = map_game.ai_delay_time + 50
thisTime = int(time.time()*1000)
if thisTime - lastTime > speed:
lastTime = int(time.time()*1000)
dir = ai_find_direction()
if dir == 0:
map_game.go_move_left()
elif dir == 1:
map_game.go_move_right()
elif dir == 2:
map_game.go_move_up()
elif dir == 3:
map_game.go_move_down()
else:
game_state = 0 #跑不了了 你爱咋整咋整
else:
game_state = 0
for event in pygame.event.get():
#按钮事件检测
button_event.buttonBase.check_event(event)
button_event.buttonReturn.check_event(event)
button_event.buttonAI.check_event(event)
button_event.buttonTips.check_event(event)
button_event.buttonReshow.check_event(event)
ii = 1
reshow_temp_buf = [ #缓存 记录
[0,0,0,0],
[0,0,0,0],
[0,0,0,0],
[0,0,0,0]
]
lstTime = int(time.time()*1000)
#回放模式
def reshow_mode(delaytime):
global ii
global lstTime
global game_state
tisTime = int(time.time()*1000)
for event in pygame.event.get():
#按钮事件检测
button_event.buttonBase.check_event(event)
button_event.buttonReturn.check_event(event)
button_event.buttonAI.check_event(event)
button_event.buttonTips.check_event(event)
button_event.buttonReshow.check_event(event)
if event.type == pygame.KEYDOWN:
if(event.key == pygame.K_z):#Z键加快速度
if map_game.ai_delay_time > 50:
map_game.ai_delay_time = map_game.ai_delay_time - 50
if(event.key == pygame.K_x):#X键减慢速度
if map_game.ai_delay_time < 1000:
map_game.ai_delay_time = map_game.ai_delay_time + 50
if tisTime - lstTime > delaytime:
lstTime = int(time.time()*1000)
cc = copy.deepcopy(map_game.board_stack)
if ii < len(cc):
map_game.board = copy.deepcopy(cc[ii])
ii = ii + 1
sound.slide_sound()
else:
map_game.board = copy.deepcopy(reshow_temp_buf)
game_state = 0
sound.stop_sound()
sound.background_sound()
#独创AI算法(人工智障2.0)
#贪心算法:
#从四个方向遍历 并获取移动后的格局值 四个方向哪个方向的格局值最大就选哪一个
def lanmeng():
dir_num = [0,0,0,0]
TestAIBoard = AI_map.AIMap(map_game.board)
for direction in range(0,4):#四个方向都遍历一遍
TestAIBoard2 = AI_map.AIMap(TestAIBoard.map)
if TestAIBoard2.ai_go(direction) == False:#走不了就滚蛋吧
dir_num[direction] = -999999
else:
dir_num[direction] = sum(TestAIBoard2.ai_evaluation())#将分析的结果加起来
if max(dir_num) == -999999:
return -1
else:
return dir_num.index(max(dir_num)) #选取得分最高的一个
#独创AI算法(人工智障3.0)
#minimax算法
# 定义搜索结果类,用于方便处理返回值
class searchResult:
def __init__(self, move=-1, score=0, positions=0, cutoffs=0) -> None:
self.move = move
self.positions = positions
self.cutoffs = cutoffs
self.score = score
def search(thisBoard: AI_map.AIMap, depth, alpha, beta, positions, cutoffs, playerTurn: bool):
bestScore = 0
bestMove = -1
result = searchResult()
if playerTurn == True: #玩家回合 倾向于让玩家获得最多的分数
bestScore = alpha # 最高分为alpha
for direction in range(4): # 四个方向分别进行遍历
newBoard = AI_map.AIMap(thisBoard.map) # 新建一个棋盘防止影响到正式游戏
changed = newBoard.ai_go(direction) # 相对应方向移动
if changed == True: # 如果这个方向可以移动
positions += 1 # positions自增
if depth == 0: # 如果已经搜索到最底层了
result.move = direction
result.score = sum(newBoard.ai_evaluation()) # 返回当前局面的评价值
else:
result = search(newBoard, depth-1, bestScore, beta, positions, cutoffs, False) # 进行min轮即让AI下出对局面最不利的一步
if result.score > 9900:
result.score -= 1
positions = result.positions
cutoffs = result.cutoffs # 将返回值进行处理
if result.score > bestScore:
bestScore = result.score
bestMove = direction
if bestScore > beta: # 如果最高值大于beta则已经证明该走法优于前面的最优则本深度下后面不用继续计算。
cutoffs += 1
return searchResult(bestMove, beta, positions, cutoffs)
else: #AI回合 倾向于让玩家获得最少的分数
bestScore = beta
newBoard = AI_map.AIMap(thisBoard.map)
score_2 = []
score_4 = []
worstSituation = []
cells = []
for i in range(4): #找到空格子
for j in range(4):
if newBoard.map[i][j] == 0:
cells.append([i, j])
for value in [2, 4]: #生成可能的所有情况,并进行评估
for i in range(len(cells)):
if newBoard.map[cells[i][0]][cells[i][1]] == 0:
newBoard.map[cells[i][0]][cells[i][1]] = value
if value == 2:
score_2.append(-newBoard.smothness() + newBoard.islands())
if value == 4:
score_4.append(-newBoard.smothness() + newBoard.islands())
newBoard.map[cells[i][0]][cells[i][1]] = 0
maxScore = max(max(score_2), max(score_4)) #找到最差的情况
for i in range(len(score_2)): # 最差的情况可能不止一种,所以遍历一遍防止遗漏
if score_2[i] == maxScore:
worstSituation.append([cells[i], 2])
for i in range(len(score_4)):
if score_4[i] == maxScore:
worstSituation.append([cells[i], 4])
for situation in worstSituation: # 遍历所有最差情况
nnewBoard = AI_map.AIMap(thisBoard.map)
positions += 1
result = search(nnewBoard, depth, alpha, bestScore, positions, cutoffs, True) # 进一步搜索
positions = result.positions
cutoffs = result.cutoffs
if result.score < bestScore:
bestScore = result.score
if bestScore < alpha: # 剪枝同理
cutoffs += 1
return searchResult(-1, alpha, positions, cutoffs)
return searchResult(bestMove, bestScore, positions, cutoffs)
def lanmeng2():
depth = 3
nAIMap = AI_map.AIMap(map_game.board)
newBest = search(nAIMap, depth, -1000000, 1000000, 0, 0, True)
return newBest.move
#以下为回调函数
#
#
#
#
#
#
#
#
#AI按键回调函数
def ai_button_callback():
sound.stop_sound()
global game_state
if game_state == 0:
game_state = 1
sound.ai_background_sound()
else:
game_state = 0
sound.background_sound()
#提示模式按键回调函数
def tips_button_event():
tips_direction = ai_find_direction()
if tips_direction == 0:
win32api.MessageBox(0,"下一步应该:往左","提示",win32con.MB_OK)
elif tips_direction == 1:
win32api.MessageBox(0,"下一步应该:往右","提示",win32con.MB_OK)
elif tips_direction == 2:
win32api.MessageBox(0,"下一步应该:往上","提示",win32con.MB_OK)
elif tips_direction == 3:
win32api.MessageBox(0,"下一步应该:往下","提示",win32con.MB_OK)
else:
win32api.MessageBox(0,"走不了了","提示",win32con.MB_OK)
#回放功能回调函数
def reshow_callback():
sound.stop_sound()
global game_state
global ii
global reshow_temp_buf
if game_state != 2:
sound.reshow_sound()
game_state = 2 #不管什么模式进去就是回放模式
ii = 1
reshow_temp_buf = copy.deepcopy(map_game.board) #缓存下来