|
|
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 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):
|
|
|
'''
|
|
|
有关信息:
|
|
|
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
|
|
|
|
|
|
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 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)
|
|
|
return 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): 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): 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): 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): 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
|
|
|
#由于使用多线程,考虑让另一个线程去更新red_to_move
|
|
|
|
|
|
|