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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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