diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/SafariChess.iml b/.idea/SafariChess.iml new file mode 100644 index 0000000..d0876a7 --- /dev/null +++ b/.idea/SafariChess.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..d56657a --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..888e3fb --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/SafariChess_AI.py b/SafariChess_AI.py new file mode 100644 index 0000000..92a6e24 --- /dev/null +++ b/SafariChess_AI.py @@ -0,0 +1,294 @@ +''' + Notice that we are using 2 unique moving functions for: + fox_moves and eagle_moves + varies on the two genres +''' +import random +from math import inf +import collections + +piece_score = {"7": 120, "1": 100, "6": 120, "5": 80, "4": 60,"3": 70,"2": 100} + +mouse_score = [[13, 13, 13, 13, 12, 11, 10, 9, 8], + [25, 20, 15, 13, 12, 12, 10, 9, 8], + [50, 25, 20, 12, 11, 11, 10, 9, 8], + [100000, 50, 20, 11, 9, 9, 9, 9, 0], + [50, 25, 20, 9, 8, 8, 8, 8, 8], + [25, 20, 15, 9, 8, 8, 8, 8, 8], + [11, 11, 10, 8, 8, 8, 8, 8, 8]] + +# eagle_score = [[ 11, 12, 14, 13, 12, 11, 10, 8, +# 8], +# [ 15, 15, 14, 14, 0, 0, 0, 8, +# 8], +# [ 50, 20, 20, 0, 0, 0, 0, 8, +# 8], +# [100000, 50, 20, 13, 12, 11, 10, 8, +# 0], +# [ 50, 20, 20, 14, 0, 0, 0, 8, +# 8], +# [ 15, 12, 15, 14, 0, 0, 0, 8, +# 8], +# [ 11, 12, 14, 13, 12, 11, 10, 8, +# 8]] +eagle_score = [[14,13,10,12,14,13,10,8,7], + [15,15,14,0,0,0,9,8,6], + [50,20,20,0,0,0,7,5,4], + [100000,50,20,13,12,11,10,8,0], + [50,20,20,0,0,0,7,5,4], + [15,12,15,0,0,0,9,8,6], + [14,12,10,13,14,13,10,8,7]] + +fox_score = [[ 11, 12, 14, 13, 12, 11, 10, 8, + 8], + [ 15, 15, 14, 0, 0, 0, 10, 8, + 8], + [ 50, 20, 20, 0, 0, 0, 10, 9, + 10], + [100000, 50, 20, 13, 12, 11, 11, 10, + 0], + [ 50, 20, 20, 0, 0, 0, 10, 9, + 10], + [ 15, 12, 15, 0, 0, 0, 10, 8, + 8], + [ 11, 12, 14, 13, 12, 11, 10, 8, + 8]] + +wolf_score = [[ 11, 12, 14, 13, 12, 11, 10, 8, + 8], + [ 15, 15, 14, 0, 0, 0, 10, 8, + 8], + [ 50, 20, 20, 0, 0, 0, 10, 9, + 10], + [100000, 50, 20, 13, 12, 11, 11, 10, + 0], + [ 50, 20, 20, 0, 0, 0, 10, 9, + 10], + [ 15, 12, 15, 0, 0, 0, 10, 8, + 8], + [ 11, 12, 14, 13, 12, 11, 10, 8, + 8]] + +leopard_score = [[ 11, 12, 14, 13, 12, 11, 10, 8, + 8], + [ 15, 15, 14, 0, 0, 0, 10, 8, + 8], + [ 50, 20, 20, 0, 0, 0, 10, 9, + 10], + [100000, 50, 20, 13, 12, 11, 11, 10, + 0], + [ 50, 20, 20, 0, 0, 0, 10, 9, + 10], + [ 15, 12, 15, 0, 0, 0, 10, 8, + 8], + [ 11, 12, 14, 13, 12, 11, 10, 8, + 8]] + +tiger_score = [[ 20, 20, 18, 15, 12, 11, 14, 12, + 5], + [ 40, 25, 30, 0, 0, 0, 16, 12, + 12], + [ 150, 40, 30, 0, 0, 0, 16, 12, + 12], + [100000, 150, 20, 15, 15, 15, 9, 12, + 0], + [ 150, 40, 30, 0, 0, 0, 16, 12, + 12], + [ 40, 25, 30, 0, 0, 0, 16, 12, + 12], + [ 20, 20, 18, 15, 12, 11, 14, 12, + 5]] +# tiger_score is not used in the game... + +lion_score = [[ 20, 20, 18, 15, 12, 11, 14, 12, + 5], + [ 40, 25, 30, 0, 0, 0, 16, 12, + 12], + [ 50, 40, 30, 0, 0, 0, 16, 12, + 12], + [100000, 50, 20, 15, 15, 15, 9, 12, + 0], + [ 50, 40, 30, 0, 0, 0, 16, 12, + 12], + [ 40, 25, 30, 0, 0, 0, 16, 12, + 12], + [ 20, 20, 18, 15, 12, 11, 14, 12, + 5]] + +elephant_score = [[ 20, 20, 18, 15, 12, 11, 14, 12, + 5], + [ 40, 25, 30, 0, 0, 0, 16, 12, + 12], + [ 50, 40, 30, 0, 0, 0, 16, 12, + 12], + [100000, 50, 20, 15, 15, 15, 9, 12, + 0], + [ 50, 40, 30, 0, 0, 0, 16, 12, + 12], + [ 40, 25, 30, 0, 0, 0, 16, 12, + 12], + [ 20, 20, 18, 15, 12, 11, 14, 12, + 5]] + +piece_position_scores = {"r1": mouse_score, + "b1": [line[::-1] for line in mouse_score[::-1]], + "r2": eagle_score, + "b2": [line[::-1] for line in eagle_score[::-1]], + "r3": fox_score, + "b3": [line[::-1] for line in fox_score[::-1]], + "r4": wolf_score, + "b4": [line[::-1] for line in wolf_score[::-1]], + "r5": leopard_score, + "b5": [line[::-1] for line in leopard_score[::-1]], + "r6": lion_score, + "b6": [line[::-1] for line in lion_score[::-1]], + "r7": elephant_score, + "b7": [line[::-1] for line in elephant_score[::-1]], + } + + + +DEN_CONQUESTED=10000 +DRAW=0 +global DEPTH #=4 + + +def findRandomMove(valid_moves): + return valid_moves[random.randint(0,len(valid_moves)-1)] + +#is greedy_move function used here? +def find_GreadyMove(game_state, valid_moves): + turnMultiplier = 1 if game_state.red_to_move else -1 + maxScore = -DEN_CONQUESTED + bestMove = None + + for playerMove in valid_moves: + game_state.makeMove(playerMove) + score = turnMultiplier * scoreMaterial(game_state) + if score > maxScore: + maxScore = score + bestMove = playerMove + game_state.undoMove() + + return bestMove + + +def scoreMaterial(game_state): # get the score + score = 0 + penalty_for_rep = 0 + + for row in range(len(game_state.board)): + for col in range(len(game_state.board[row])): + piece = game_state.board[row][col] + if piece != "00": + piece_position_score = 0 + piece_position_score = piece_position_scores[piece][row][col] + if piece_position_scores[piece][row][col] in last_moves: + penalty_for_rep += 70 + if piece[0] == 'r': + score += piece_position_score + piece_score[piece[1]] - penalty_for_rep + + elif piece[0] == 'b': + score -= piece_position_score + piece_score[piece[1]] - penalty_for_rep + + return score + +def findMove_NegaMaxAlphaBeta(game_state, valid_moves, depth,DEPTH, alpha, beta, turn_multiplier): + global next_move + if depth == 0: + return turn_multiplier * scoreMaterial(game_state) + + max_score = -inf + for move in valid_moves: + game_state.makeMove(move) + next_moves = game_state.getAllMoves() + score = -findMove_NegaMaxAlphaBeta(game_state, next_moves, depth - 1,DEPTH, -beta, -alpha, -turn_multiplier) + + if score > max_score: # > or >= ?? + max_score = score + if depth == DEPTH: + next_move = move + + game_state.undoMove() + if max_score > alpha: + alpha = max_score + if alpha >= beta: + break + return max_score + + +def findMove_MiniMaxAlphaBeta(game_state, valid_moves, depth, alpha, beta, turn_multiplier): + global next_move + + def max_value(game_state,next_moves, alpha, beta,depth): + if depth == 0: + return turn_multiplier * scoreMaterial(game_state) + v = -inf + for move in valid_moves: + next_moves = game_state.getAllMoves() + v = max(v, min_value(game_state,next_moves, alpha, beta,depth - 1)) + game_state.undoMove() + if v >= beta: + return v + alpha = max(alpha, v) + return v + + def min_value(game_state,next_moves, alpha, beta,depth): + if depth == 0: + return turn_multiplier * scoreMaterial(game_state) + v = -inf + for move in valid_moves: + next_moves = game_state.getAllMoves() + v = min(v, max_value(game_state,next_moves, alpha, beta,depth - 1)) + game_state.undoMove() + if v <= alpha: + return v + beta = min(beta, v) + return v + + # Body of alpha_beta_search: + best_score = -inf + beta = inf + best_action = None + for move in valid_moves: + v = min_value(game_state,valid_moves, best_score, beta,depth) + if v > best_score: + best_score = v + best_action = move + return best_action + +def find_BestMove(game_state, valid_moves,depth_p): + global next_move + DEPTH= depth_p + next_move = None + global last_moves + last_moves = collections.deque(maxlen=12) + + random.shuffle(valid_moves) + ordered_valid_moves=orderby_GreadyMove(game_state, valid_moves) + + # for i in valid_moves: + # print(f"Possible: {i}") + # for i in ordered_valid_moves: + # print(f"New possible: {i}") + findMove_NegaMaxAlphaBeta(game_state, ordered_valid_moves,depth_p,DEPTH, -DEN_CONQUESTED, DEN_CONQUESTED,1 if game_state.red_to_move else -1) + last_moves.append(next_move) + + return next_move + + +def orderby_GreadyMove(game_state, valid_moves): + turnMultiplier = 1 if game_state.red_to_move else -1 + maxScore = -DEN_CONQUESTED + de = collections.deque([]) + + for playerMove in valid_moves: + game_state.makeMove(playerMove) + score = turnMultiplier * scoreMaterial(game_state) + if score > maxScore: + maxScore = score + de.appendleft(playerMove) + else: + de.append(playerMove) + game_state.undoMove() + return de diff --git a/SafariChess_Gamev1.0.py b/SafariChess_Gamev1.0.py index 9e962a9..ad30ad6 100644 --- a/SafariChess_Gamev1.0.py +++ b/SafariChess_Gamev1.0.py @@ -16,10 +16,12 @@ import pygame as pg import sys import socket import SafariChess_backend as backend +import SafariChess_AI as AI from SafariChess_Classes import Button, DropDown from threading import Thread, Lock from itertools import count, cycle import time +import random #设置棋盘的参数 WIDTH = 1000 @@ -38,12 +40,14 @@ IMAGES = {} bias_top = 100 #棋盘的上边距 bias_left = 20 #棋盘的左边距 #网络道具 +general_countdown = 10 client = None networkMsg = None server = None port = None addr = None connection = None +DEPTH = 3 #网络版更新需要注意多线程的问题? server_died_message = 'fucking server died and quit' #尝试写一个函数分配一个新线程供监听 @@ -66,7 +70,7 @@ def listenFromServer(): def startNetworkServices(): global client,server,port,addr,connection client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server = '192.168.64.246' + server = '192.168.43.183' port = 50005 addr = (server,port) connection = client.connect(addr) @@ -139,7 +143,7 @@ def protrudeSquares(screen,game_state,square_selected,valid_moves): if move.start_row == row and move.start_col == column: screen.blit(s, (move.end_col * SIZE + bias_left, move.end_row * SIZE + bias_top)) - + def ShowGameState(screen,game_state,valid_moves,square_selected):#游戏状态 drawBoard(screen) @@ -172,10 +176,10 @@ Please type one of the numbers below to choose a playing mode: ( 1 ) - 单机游戏 ( 2 ) - 网络对战 ( 3 ) - 人机对战 - ( 4 ) - 退出游戏 + ( 4 ) - AI代打 ################################################################ Current Mode is: %s - '''%['单机游戏','网络对战','人机对战','退出游戏'][mode-1]) + '''%['单机游戏','网络对战','人机对战','AI代打'][mode-1]) print(startpage) # 选择游戏模式 not_selected = True @@ -341,7 +345,7 @@ def main(mode): screen.fill(pg.Color("white")) loadImages() drawBoard(screen) - isOnline = bool(mode == 2) + isOnline = bool(mode == 2 or mode == 4) game_state=backend.GameState() #* cancelled args: MySide=True if not isOnline else bool(NewPlayerMessage['side']),game_id=NewPlayerMessage['game_id'] valid_moves=game_state.getAllMoves() @@ -361,7 +365,10 @@ def main(mode): screen.blit(button_music.image, button_music.rect) pg.display.update() startGamePage(mode) #游戏进入前,可以进一步优化一些显示细节 - if mode == 1: + if mode == 1 or mode == 3: + if mode == 3: + AI_side = random.randint(0,1) + print('AI side:{}'.format('b' if AI_side == 1 else 'r')) while running: for e in pg.event.get(): #接下来处理游戏中的事件 @@ -390,17 +397,41 @@ def main(mode): mademove = True square_selected = () click_queue = [] + valid_moves = game_state.getAllMoves() else: click_queue = [square_selected] elif e.type == pg.KEYDOWN: #设置某些按键用于悔棋,重新开始游戏,机器提示,退出游戏等功能 - pass - - + if e.key == pg.K_z: # undo when 'z' is pressed + game_state.undoMove() + mademove = True + game_over = False + if mademove: valid_moves = game_state.getAllMoves() - mademove = False + mademove = False + + if not game_over and mode == 3: + if AI_side == 1 and not game_state.red_to_move: + ai_move = AI.find_BestMove(game_state,valid_moves,DEPTH) + if ai_move is not None: + game_state.makeMove(ai_move) + mademove = True + else: + ai_move = AI.find_GreadyMove(game_state,valid_moves) + game_state.makeMove(ai_move) + mademove = True + elif AI_side == 0 and game_state.red_to_move: + ai_move = AI.find_BestMove(game_state,valid_moves,DEPTH) + if ai_move is not None: + game_state.makeMove(ai_move) + mademove = True + else: + ai_move = AI.find_GreadyMove(game_state,valid_moves) + game_state.makeMove(ai_move) + mademove = True + ShowGameState(screen,game_state,valid_moves,square_selected) if game_state.conquer(): showGameOverText(screen,"player "+game_state.win_person+" wins") @@ -408,8 +439,8 @@ def main(mode): clock.tick(60) pg.display.flip() - elif mode == 2: - counts=20 #双方倒计时 + elif mode == 2 or mode == 4: + counts=general_countdown #双方倒计时 startNetworkServices() #! start login myPlayerData = { @@ -510,12 +541,39 @@ def main(mode): #Move handler elif 'src' and 'dst' in networkMsg.keys(): theMove = backend.Move([networkMsg['src']['y'],networkMsg['src']['x']],[networkMsg['dst']['y'],networkMsg['dst']['x']],game_state.board) + violate_175 = game_state.seventeen_five_violation(goal=theMove.get_goal(),color=theMove.get_turn(), showTrace= True) + violate_73 = game_state.seventy_three_violation(goal=theMove.get_goal(), color = theMove.get_turn(), showTrace= True) + if not type(violate_175) == bool: + print("player {} foul 17-5".format(theMove.get_turn())) + print("Recent 17 Move: {}".format(violate_175)) + reportJson = { + "type": 2, + "msg": { + "request": "report", + "game_id": game_id, + "side": MySide + } + } + client.send(json.dumps(reportJson).encode('utf-8')) + if not type(violate_73) == bool: + print("player {} foul 7-3".format(theMove.get_turn())) + print("Recent 7 Move: {}".format(violate_73)) + reportJson = { + "type": 2, + "msg": { + "request": "report", + "game_id": game_id, + "side": MySide + } + } + client.send(json.dumps(reportJson).encode('utf-8')) game_state.makeMove(theMove) valid_moves = game_state.getAllMoves() other_stage = not other_stage - counts=20 + counts=general_countdown thisMove = None + for e in pg.event.get(): #接下来处理游戏中的事件 if e.type == pg.QUIT: @@ -619,14 +677,35 @@ def main(mode): - + if not game_over and mode == 4: + #! 特别注意:红方是0,蓝方是1 + if MySide == 1 and not game_state.red_to_move: + thisMove = AI.find_BestMove(game_state,valid_moves,DEPTH) + if thisMove is not None: + game_state.makeMove(thisMove) + mademove = True + else: + thisMove = AI.find_GreadyMove(game_state,valid_moves) + game_state.makeMove(thisMove) + mademove = True + elif MySide == 0 and game_state.red_to_move: + thisMove = AI.find_BestMove(game_state,valid_moves,DEPTH) + if thisMove is not None: + game_state.makeMove(thisMove) + mademove = True + else: + thisMove = AI.find_GreadyMove(game_state,valid_moves) + game_state.makeMove(thisMove) + mademove = True + square_selected = () + click_queue = [] if mademove: + #print(thisMove) valid_moves = game_state.getAllMoves() mademove = False if isOnline: print('waiting for the other player to move...') - other_stage = not other_stage thisMoveJson = { 'type': 1, @@ -678,11 +757,13 @@ def main(mode): clock.tick(50) pg.display.flip() + + if __name__ == '__main__': #print("Loading...") #print("Initialing game...") mode = MainMenu() - #mode = 2 + #mode = 4 main(mode) diff --git a/SafariChess_backend.py b/SafariChess_backend.py index 007edcc..4871e36 100644 --- a/SafariChess_backend.py +++ b/SafariChess_backend.py @@ -22,113 +22,24 @@ class Move: if isinstance(__o, Move): return self.moveID == __o.moveID return False + def __str__(self): + return f"{self.start_row=},"+f"{self.start_col=},"+f"{self.end_row=},"+f"{self.end_col=}" + def get_goal(self): + return (self.end_row, self.end_col) + def get_start(self): + return (self.start_row, self.start_col) + def get_goal_chess_comb(self): + return (self.end_row, self.end_col, self.cur_piece) + def get_turn(self): + return self.cur_piece[0] + def get_piece(self): + return self.cur_piece + def startNewThread(target): thread = Thread(target=target) thread.daemon = True thread.start() -# class Network: -# def __init__(self,isNet=False): #注意:这里是否在传引用? -# self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -# self.server = "127.0.0.1" -# self.port = 50005 -# self.addr = (self.server, self.port) -# self.msg = self.connect() -# #self.game_state = game_state #考虑将game_state接入Network以方便修改 -# global msg_from_serv -# thread = Thread(target = self.receive())#开线程始终监听 -# thread.setDaemon(True) -# thread.start() #专用数据接收线程 - - -# def getPos(self): -# return self.pos - -# def connect(self): -# try: -# self.client.connect(self.addr) -# #return self.client.recv(2048).decode() -# except: -# pass - -# def send(self, msg): -# try: -# packet = json.dumps(msg) -# if (sys.version[:1] == '3'): -# packet = packet.encode('utf-8') -# self.client.send(packet) -# print("send complete") -# return self.client.recv(2048).encode() -# except socket.error as e: -# print(e) -# return e - -# def post(self, data): #using requests lib, data is json -# headers = {'Content-Type': 'application/json'} -# response = requests.post(url='http://localhost',data=data) -# return response - -# def receive(self): #写成持续监听模式 -# try: -# while True: -# recvMsg = self.client.recv(2048).decode('utf-8') -# if len(recvMsg) != 0: -# msg_from_serv = json.loads(recvMsg) -# self.dataDealer(msg_from_serv) -# except socket.error as e: -# print(e) -# return e - -# def dataDealer(self, msg_json): #根据相关数据对棋盘状态进行更新 -# if 'status' in msg_json.keys(): -# #处理相关特殊情况 -# if msg_json['status'] == '1': -# print('Waiting 4 the other player...') - - -# elif 'src' and 'dst' in msg_json.keys(): #侦测到移动 -# theMove = Move([msg_json['src']['x'],msg_json['src']['y']],[msg_json['dst']['x'],msg_json['dst']['y']],self.game_state.board) -# self.game_state.makeMove(theMove,toUpload = False) -# self.game_state.exchange() - - -# def dataReceiver(self): -# try: -# while True: -# msg = self.client.recv(2048).decode('utf-8') -# if len(msg) != 0: self.dataDealer(json.loads(msg)) - -# except socket.error as e: -# print(e) -# return e - -# def tell_move(self, move: Move): -# thisMove = { -# 'type': 1, -# 'msg':{ -# "game_id": self.game_id, -# "side": int(self.red_to_move), -# "chessman": move.cur_piece, -# "src": { -# "x": move.start_row, -# "y": move.start_col -# }, -# "dst": { -# "x": move.end_row, -# "y": move.end_col -# } -# } -# } -# self.client.send(thisMove) - -# def login(self,myName): -# myPlayerData = { -# 'type': 0, # game state type ? -# 'msg': { -# 'name': myName -# } -# } -# self.client.send(myPlayerData) class GameState: def __init__(self): @@ -172,12 +83,89 @@ class GameState: self.win_person='' self.MASSACRE=False self.isStarted = False + self.move_log = [] def color(self): return 'r' if self.red_to_move else 'b' def exchange(self): - self.red_to_move = not self.red_to_move - + self.red_to_move = not self.red_to_move + + def seventy_three_violation(self, goal, color, showTrace = False): + #输入:goal为三元组(格坐标x,格坐标y,棋子) + # color为颜色 + # showTrace为是否查看轨迹 + past7Moves = [] + #寻找该动物的移动轨迹 + for i in range(len(self.move_log)-1, -1, -1): + if self.move_log[i].get_turn() == color: + past7Moves.append(self.move_log[i]) + if len(past7Moves) > 7: + break + # print("past7Moves= ",[move.get_goal_chess_comb() for move in past7Moves]) + if len(past7Moves) > 7: + past7Moves = past7Moves[-7:] + visit_counts = dict() + for move in past7Moves: + if move.get_goal() in (self.blue_trap_loc + self.red_trap_loc): + return True + try: + visit_counts[move.get_goal_chess_comb()] += 1 + except KeyError: + visit_counts[move.get_goal_chess_comb()] = 1 + try: + if visit_counts[goal] >= 3: + if showTrace: + return goal + else: + return False + else: + return True + except: + return True + def seventeen_five_violation(self, goal, color, showTrace = False): + # 输入:goal为三元组(格坐标x,格坐标y,棋子) + # color为颜色 + # showTrace为是否查看轨迹 + + #获取近17步操作 + past17Moves = [] + for i in range(len(self.move_log) - 1, -1, -1): + if self.move_log[i].get_turn() == color: + past17Moves.append(self.move_log[i]) + if len(past17Moves) > 17: + break + if len(past17Moves) >= 17: + past17Moves = past17Moves[-17:] + else: + return True + #判断是否为同一棋子的移动 + piece = past17Moves[0].get_piece() + for i in range(len(past17Moves)): + if past17Moves[i].get_piece() != piece: + return True + #当为同一棋子时…… + visit_locs = [] + for move in past17Moves: + if move.get_goal() in (self.blue_trap_loc + self.red_trap_loc): + return True + try: + visit_locs.append(move.get_goal()) + except KeyError: + visit_locs.append(move.get_goal()) + try: + if showTrace and len(visit_locs) <= 5: + if goal in visit_locs: + return (goal,visit_locs) + else: + return True + elif len(visit_locs)<=5: + if goal in visit_locs: + return False + else: + return True + except: + return True + # 判断特殊位置 def inHome(self,row,col,color): if color=="b": @@ -223,7 +211,13 @@ class GameState: if (player == 'r' and self.red_to_move or player == 'b' and not self.red_to_move): #print('what color is the valid move? ',player) self.moveFunctions[self.board[row][col][1]](row,col,moves) - return moves + valid_moves = [] + for move in moves: # 己方躲避17-5和7-3 + if self.seventy_three_violation(goal=move.get_goal_chess_comb(), color=self.color()) and self.seventeen_five_violation(goal=move.get_goal_chess_comb(), color=self.color()): + valid_moves.append(move) + if len(valid_moves) == 0: + print('warning: no available moves at side {}'.format('b' if not self.red_to_move else 'r')) + return valid_moves def getStdMoves(self,row,col,moves):#输入当前的位置,将可行路径输出给moves @@ -267,7 +261,7 @@ class GameState: if nxt_piece == '00' and not self.inTrap(new_row,col,enemy_color) and not self.inTrap(new_row,col,'r' if enemy_color == 'b' else 'b'): if not self.inHome(new_row,col,self.color()) and not self.inWater(new_row,col): moves.append(Move((row,col),(new_row,col),self.board)) else: - if self.Eliminate(row,col,new_row,col): moves.append(Move((row,col),(new_row,col),self.board)) + if self.Eliminate(row,col,new_row,col) and not self.inWater(new_row,col): moves.append(Move((row,col),(new_row,col),self.board)) if new_row != row: break new_row -= 1 new_row = row @@ -276,7 +270,7 @@ class GameState: if nxt_piece == '00' and not self.inTrap(new_row,new_col,enemy_color) and not self.inTrap(new_row,col,'r' if enemy_color == 'b' else 'b'): if not self.inHome(new_row,col,self.color()) and not self.inWater(new_row,col): moves.append(Move((row,col),(new_row,col),self.board)) else: - if self.Eliminate(row,col,new_row,col): moves.append(Move((row,col),(new_row,col),self.board)) + if self.Eliminate(row,col,new_row,col) and not self.inWater(new_row,col): moves.append(Move((row,col),(new_row,col),self.board)) if new_row != row: break new_row += 1 #L&R Direction @@ -285,7 +279,7 @@ class GameState: if nxt_piece == '00' and not self.inTrap(row,new_col,enemy_color) and not self.inTrap(new_row,col,'r' if enemy_color == 'b' else 'b'): if not self.inHome(row,new_col,self.color()) and not self.inWater(row,new_col): moves.append(Move((row,col),(row,new_col),self.board)) else: - if self.Eliminate(row,col,row,new_col): moves.append(Move((row,col),(row,new_col),self.board)) + if self.Eliminate(row,col,row,new_col) and not self.inWater(row,new_col): moves.append(Move((row,col),(row,new_col),self.board)) if new_col != col: break new_col -= 1 new_col = col @@ -294,7 +288,7 @@ class GameState: if nxt_piece == '00' and not self.inTrap(row,new_col,enemy_color) and not self.inTrap(new_row,col,'r' if enemy_color == 'b' else 'b'): if not self.inHome(row,new_col,self.color()) and not self.inWater(row,new_col): moves.append(Move((row,col),(row,new_col),self.board)) else: - if self.Eliminate(row,col,row,new_col): moves.append(Move((row,col),(row,new_col),self.board)) + if self.Eliminate(row,col,row,new_col) and not self.inWater(row,new_col): moves.append(Move((row,col),(row,new_col),self.board)) if new_col != col: break new_col += 1 return moves @@ -386,6 +380,16 @@ class GameState: self.board[move.end_row][move.end_col] = self.board[move.start_row][move.start_col] self.board[move.start_row][move.start_col] = '00' self.red_to_move = not self.red_to_move + self.move_log.append(move) + #由于使用多线程,考虑让另一个线程去更新red_to_move + def undoMove(self): + if len(self.move_log) != 0: + move = self.move_log.pop() + self.board[move.start_row][move.start_col] = move.cur_piece + self.board[move.end_row][move.end_col] = move.nxt_piece + if move.nxt_piece != '00' and move.nxt_piece not in (self.blue_pieces if move.nxt_piece[0]=='b' else self.red_pieces): + (self.blue_pieces if move.nxt_piece[0]=='b' else self.red_pieces).append(int(move.nxt_piece[1])) + self.red_to_move = not self.red_to_move diff --git a/__pycache__/SafariChess_AI.cpython-39.pyc b/__pycache__/SafariChess_AI.cpython-39.pyc new file mode 100644 index 0000000..c51eb7b Binary files /dev/null and b/__pycache__/SafariChess_AI.cpython-39.pyc differ diff --git a/__pycache__/SafariChess_backend.cpython-39.pyc b/__pycache__/SafariChess_backend.cpython-39.pyc index d226807..c22b96f 100644 Binary files a/__pycache__/SafariChess_backend.cpython-39.pyc and b/__pycache__/SafariChess_backend.cpython-39.pyc differ diff --git a/network/config.txt b/network/config.txt index fb5ccb4..d599145 100644 --- a/network/config.txt +++ b/network/config.txt @@ -1,5 +1,5 @@ -SOCKET_HOST=127.0.0.1 +SOCKET_HOST=192.168.43.183 SOCKET_PORT=50005 MAX_WAITING_TIME=600 -MAX_THNIKING_TIME=200 +MAX_THNIKING_TIME=10 MAX_TOTAL_TIME=1000