#人工智障 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) #缓存下来