import socket import this import requests import sys import json from threading import Thread from queue import Queue #multithreading? class Move: def __init__(self,start_loc,end_loc,board): self.start_row = start_loc[0] self.start_col = start_loc[1] self.end_row = end_loc[0] self.end_col = end_loc[1] self.nxt_piece = board[self.end_row][self.end_col] self.cur_piece = board[self.start_row][self.start_col] self.attack = self.nxt_piece != '00' self.moveID = self.start_row + self.start_col*10 + self.end_row *100 +self.end_col * 1000 #Hash def __eq__(self, __o: object) -> bool: 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 GameState: def __init__(self): ''' 有关信息: 1. 棋盘尺寸为7*9(横向) 2. 按照以下命名格式对棋盘中的棋子进行标注: (b|r)(1|2|3|4|5|6|7) 3. 左方为蓝方,对应的网络服务器中的side项目编号为0 右方为红方,对应的网络服务器中的side项目编号为1 4. 网络版需要额外的类变量:type, game_id, side, chessman(piece), src, dst ''' self.board = [ ['00','00','b7','00','00','00','r1','00','00'], ['00','b2','00','00','00','00','00','r3','00'], ['00','00','b4','00','00','00','r5','00','00'], ['00','00','b6','00','00','00','r6','00','00'], ['00','00','b5','00','00','00','r4','00','00'], ['00','b3','00','00','00','00','00','r2','00'], ['00','00','b1','00','00','00','r7','00','00'], ] #用数字1-7代替棋子的强弱关系 self.moveFunctions = { "1": self.getMseMoves, "2": self.getEagMoves, "3": self.getFoxMoves, "4": self.getStdMoves, "5": self.getStdMoves, "6": self.getLionMoves, "7": self.getStdMoves, } self.blue_trap_loc=[(2,0),(3,1),(4,0)] self.red_trap_loc=[(3,7),(2,8),(4,8)] self.blue_home=(3,0) self.red_home=(3,8) self.blue_pieces=[7,6,5,4,3,2,1] self.red_pieces=[7,6,5,4,3,2,1] #红方(右)先行 self.red_to_move=True self.conquered=False 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 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, [move.get_goal() for move in past7Moves]) else: return False else: return True except: return True def seventeen_five_violation(self, goal, color, showTrace = False): # 输入:goal为三元组(格坐标x,格坐标y,棋子) # color为颜色 # showTrace为是否查看轨迹 #获取近17步操作 RECENT_COUNT = 17 PERMIT_RANGE = 5 # print("using params: {}, {}, {}".format(goal, color, showTrace)) 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) > RECENT_COUNT: break if len(past17Moves) >= RECENT_COUNT: past17Moves = past17Moves[-RECENT_COUNT:] else: return True #print("past17Movesloc: {}".format([move.get_goal() for move in past17Moves])) #判断是否为同一棋子的移动 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 this_loc = move.get_goal() if this_loc not in visit_locs: visit_locs.append(this_loc) try: if showTrace and len(visit_locs) <= PERMIT_RANGE: if goal in visit_locs: return (goal,visit_locs) else: return True elif len(visit_locs)<=PERMIT_RANGE: if goal in visit_locs: return False else: return True else: return True except: return True # 判断特殊位置 def inHome(self,row,col,color): if color=="b": if (row,col)==self.blue_home: return True else: if (row,col)==self.red_home: return True return False def inWater(self,row,col): if row in [1,2,4,5]: if col in [3,4,5]: return True return False def inTrap(self,row,col,color): #是否在color方的陷阱中 if color=="b": if (row,col) in self.blue_trap_loc: return True else: if (row,col) in self.red_trap_loc: return True return False def Eliminate(self,row,col,nxt_row,nxt_col):#下一步可吃对手的棋 next_blank = self.board[nxt_row][nxt_col] == '00' attack = self.board[nxt_row][nxt_col][0] != self.board[row][col][0] and (eval(self.board[row][col][1]) >= eval(self.board[nxt_row][nxt_col][1]) and not (eval(self.board[row][col][1]) == 7 and eval(self.board[nxt_row][nxt_col][1]) == 1 ) or eval(self.board[row][col][1])==1 and eval(self.board[nxt_row][nxt_col][1])==7) other_in_trap = self.board[row][col][0] != self.board[nxt_row][nxt_col][0] and (self.board[nxt_row][nxt_col][0] == 'r' and self.inTrap(nxt_row,nxt_col,'b') or self.board[nxt_row][nxt_col][0] == 'b' and self.inTrap(nxt_row,nxt_col,'r')) return next_blank or attack or other_in_trap # 定义移动方式 #---------------------------------- # 以下为移动方式的相关规定: # 1.下一步的可行位置以二维数组的格式进行记录。 # 2.getValidMoves返回值为下一步可行位置构成的集合。 #---------------------------------- def getAllMoves(self): #全部合法移动的集合 moves=[] for row in range(len(self.board)): for col in range(len(self.board[row])): player = self.board[row][col][0] 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) 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 directions = [(1,0),(0,1),(-1,0),(0,-1)] enemy_color = 'b' if self.red_to_move else 'r' for direction in directions: new_row = row + direction[0]*1 new_col = col + direction[1]*1 if 0<=new_row<=6 and 0<=new_col<=8 : nxt_piece = self.board[new_row][new_col] if nxt_piece == '00' and not self.inWater(new_row,new_col) and not self.inHome(new_row,new_col,self.color()):#如果下一个位置是空的,则可以移动 moves.append(Move((row,col),(new_row,new_col),self.board)) elif nxt_piece[0]==enemy_color and not self.inWater(new_row,new_col) and not self.inHome(new_row,new_col,self.color()) and self.Eliminate(row,col,new_row,new_col):#如果是敌方棋子,且不在水里,且可以消除,则添加到可行路径中 moves.append(Move((row,col),(new_row,new_col),self.board)) return moves def getMseMoves(self,row,col,moves): directions = [(1,0),(0,1),(-1,0),(0,-1)] enemy_color = 'b' if self.red_to_move else 'r' for direction in directions: new_row = row + direction[0]*1 new_col = col + direction[1]*1 if 0<=new_row<=6 and 0<=new_col<=8 : nxt_piece = self.board[new_row][new_col] if self.inHome(new_row,new_col,self.color()): continue if nxt_piece == '00': moves.append(Move((row,col),(new_row,new_col),self.board)) elif nxt_piece[0]==enemy_color and self.Eliminate(row,col,new_row,new_col) and not self.inWater(row,col): moves.append(Move((row,col),(new_row,new_col),self.board)) return moves def getEagMoves(self,row,col,moves): #可能存在一些问题,主要是移动方式的判断以及在陷阱的判断 enemy_color = 'b' if self.red_to_move else 'r' new_row = row new_col = col #U&D direction while new_row >= 0: nxt_piece = self.board[new_row][col] 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) 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 while new_row <= 6: nxt_piece = self.board[new_row][col] 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) 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 while new_col >= 0: nxt_piece = self.board[row][new_col] 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) 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 while new_col <= 8: nxt_piece = self.board[row][new_col] 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) 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 def getFoxMoves(self,row,col,moves): directions = [(1,0),(0,1),(-1,0),(0,-1),(1,1),(1,-1),(-1,1),(-1,-1)] enemy_color = 'b' if self.red_to_move else 'r' for direction in directions: new_row = row + direction[0]*1 new_col = col + direction[1]*1 if 0<=new_row<=6 and 0<=new_col<=8 : nxt_piece = self.board[new_row][new_col] if nxt_piece == '00' and not self.inWater(new_row,new_col) and not self.inHome(new_row,new_col,self.color()):#如果下一个位置是空的,则可以移动 moves.append(Move((row,col),(new_row,new_col),self.board)) elif nxt_piece[0]==enemy_color and not self.inWater(new_row,new_col) and not self.inHome(new_row,new_col,self.color()) and self.Eliminate(row,col,new_row,new_col):#如果是敌方棋子,且不在水里,且可以消除,则添加到可行路径中 moves.append(Move((row,col),(new_row,new_col),self.board)) return moves def getLionMoves(self,row,col,moves): directions = [(1,0),(0,1),(-1,0),(0,-1)] enemy_color = 'b' if self.red_to_move else 'r' for direction in directions: new_row = row + direction[0]*1 new_col = col + direction[1]*1 if 0<=new_row<=6 and 0<=new_col<=8 : nxt_piece = self.board[new_row][new_col] if nxt_piece == '00' and not self.inWater(new_row,new_col) and not self.inHome(new_row,new_col,self.color()):#如果下一个位置是空的,则可以移动 moves.append(Move((row,col),(new_row,new_col),self.board)) elif nxt_piece[0]==enemy_color and not self.inWater(new_row,new_col) and not self.inHome(new_row,new_col,self.color()) and self.Eliminate(row,col,new_row,new_col):#如果是敌方棋子,且不在水里,且可以消除,则添加到可行路径中 moves.append(Move((row,col),(new_row,new_col),self.board)) jump_vert_loc=[(0,3),(0,4),(0,5),(3,3),(3,4),(3,5),(6,3),(6,4),(6,5)] jump_hori_loc=[(1,2),(1,6),(2,2),(2,6),(4,2),(4,6),(5,2),(5,6)] enemy_mouse = enemy_color + '1' if (row,col) in jump_vert_loc: if row == 0: if self.board[1][col] != enemy_mouse and self.board[2][col] != enemy_mouse: if self.Eliminate(row,col,3,col): moves.append(Move((row,col),(3,col),self.board)) elif row == 3: if self.board[1][col] != enemy_mouse and self.board[2][col] != enemy_mouse: if self.Eliminate(row,col,0,col): moves.append(Move((row,col),(0,col),self.board)) if self.board[4][col] != enemy_mouse and self.board[5][col] != enemy_mouse: if self.Eliminate(row,col,6,col): moves.append(Move((row,col),(6,col),self.board)) elif row == 6: if self.board[4][col] != enemy_mouse and self.board[5][col] != enemy_mouse: if self.Eliminate(row,col,3,col): moves.append(Move((row,col),(3,col),self.board)) elif (row,col) in jump_hori_loc: if col == 2: lea = True for i in range(3,6): if self.board[row][i] == enemy_mouse: lea = False if lea and self.Eliminate(row,col,row,6): moves.append(Move((row,col),(row,6),self.board)) elif col == 6: lea = True for i in range(3,6): if self.board[row][i] == enemy_mouse: lea = False if lea and self.Eliminate(row,col,row,2): moves.append(Move((row,col),(row,2),self.board)) return moves # 判断是否胜利 def conquer(self): if self.board[3][0][0] == 'r' or self.board[3][8][0] == 'b': self.conquered = True if self.board[3][0][0] == 'r': self.win_person = 'r' else: self.win_person = 'b' elif len(self.blue_pieces) == 0: self.conquered = True self.win_person = 'r' elif len(self.red_pieces) == 0: self.conquered = True self.win_person = 'b' elif len(self.getAllMoves()) == 0: self.conquered = True self.win_person = 'r' if self.color() == 'b' else 'b' return self.conquered #移动操作 def makeMove(self,move):#cur是当前位置,nxt是下一个位置,参数传入为元组 # makeMove假设这个move一定是合法的 # 为什么添加toUpload?防止使用makeMove更新己方棋盘时,把敌方棋盘错误上传,导致“棋子消失”。 if self.board[move.end_row][move.end_col] != '00': nxt_piece = self.board[move.end_row][move.end_col] if nxt_piece[0] == 'r': self.red_pieces.remove(int(nxt_piece[1])) else: self.blue_pieces.remove(int(nxt_piece[1])) 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