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