Merge branch 'qq_branch'

master
tzzzzzzzx 2 years ago
commit 413be11470

8
.idea/.gitignore vendored

@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9" project-jdk-type="Python SDK" />
</project>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/SafariChess.iml" filepath="$PROJECT_DIR$/.idea/SafariChess.iml" />
</modules>
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

@ -18,7 +18,7 @@
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/network/server.py",
"cwd": "${fileDirname}",
"cwd": "${workspaceFolder}/network/",
"console": "integratedTerminal",
"justMyCode": true
},

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

@ -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

@ -2,7 +2,7 @@
SafariChess_Classes.py
Classes for button and keyboard events
"""
import pygame as pg
class Button:
def __init__(self, image, position, callback=None):
self.image = image
@ -14,6 +14,56 @@ class Button:
if self.rect.collidepoint(event.pos):
self.callback(self)
#class DropDown():
#下拉选择框
#下拉框
class DropDown():
def __init__(self, color_menu, color_option, x, y, w, h, font, main, options):
self.color_menu = color_menu
self.color_option = color_option
self.rect = pg.Rect(x, y, w, h)
self.font = font
self.main = main
self.options = options
self.draw_menu = False
self.menu_active = False
self.active_option = -1
def draw(self, surf):
pg.draw.rect(surf, self.color_menu[self.menu_active], self.rect, 0)
msg = self.font.render(self.main, 1, (0, 0, 0))
surf.blit(msg, msg.get_rect(center = self.rect.center))
if self.draw_menu:
for i, text in enumerate(self.options):
rect = self.rect.copy()
rect.y += (i+1) * self.rect.height
pg.draw.rect(surf, self.color_option[1 if i == self.active_option else 0], rect, 0)
msg = self.font.render(text, 1, (0, 0, 0))
surf.blit(msg, msg.get_rect(center = rect.center))
def update(self, event_list):
mpos = pg.mouse.get_pos()
self.menu_active = self.rect.collidepoint(mpos)
self.active_option = -1
for i in range(len(self.options)):
rect = self.rect.copy()
rect.y += (i+1) * self.rect.height
if rect.collidepoint(mpos):
self.active_option = i
break
if not self.menu_active and self.active_option == -1:
self.draw_menu = False
for event in event_list:
if event.type == pg.MOUSEBUTTONDOWN and event.button == 1:
if self.menu_active:
self.draw_menu = not self.draw_menu
elif self.draw_menu and self.active_option >= 0:
self.draw_menu = False
return self.active_option
return -1

@ -11,12 +11,17 @@ it handle user input and GUI
import colorsys
import json
from multiprocessing import connection
import pygame as pg
import sys
import socket
import SafariChess_backend as backend
from SafariChess_Classes import Button
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
@ -33,10 +38,45 @@ DIMENSION_COLUMNS = 9
SIZE = 64
IMAGES = {}
bias_top = 100 #棋盘的上边距
bias_left = 100 #棋盘的左边距
#multithreading?
mutex = Lock()
mutex_playing = Lock()
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'
#尝试写一个函数分配一个新线程供监听
def startNewThread(target):
thread = Thread(target=target)
thread.daemon =True
thread.start()
def listenFromServer():
global networkMsg
try:
while True:
recvMsg = client.recv(1024).decode('utf-8')
if len(recvMsg) != 0:
networkMsg = json.loads(recvMsg)
print('receive thread catch: ',networkMsg)
except socket.error as e:
#print('Error encountered in connection. Quit.')
print(e)
return False
def startNetworkServices():
global client,server,port,addr,connection
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server = '192.168.43.183'
port = 50005
addr = (server,port)
connection = client.connect(addr)
startNewThread(target=listenFromServer)
#等待敌人移动
def loadImages():#加载图片,a,b双方分别有象狮豹狼狐鹰鼠七个角色
pieces = ["r7", "r6", "r5", "r4", "r3", "r2", "r1",
@ -46,7 +86,7 @@ def loadImages():#加载图片,a,b双方分别有象狮豹狼狐鹰鼠七个角
IMAGES[piece] = pg.transform.scale(pg.image.load("./Image/pieces/pieces_rb/" + piece + ".png"), (SIZE - 10, SIZE - 10))
tools = ["trap", "home1","home2"]
for tool in tools:
for tool in tools:
IMAGES[tool] = pg.transform.scale(pg.image.load("./Image/tools/" + tool + ".jpg"), (SIZE-10, SIZE-10))
#screen = pg.display.set_mode((BOARD_WIDTH + MOVE_LOG_PANEL_WIDTH, BOARD_HEIGHT))#设置窗口大小
#screen.fill(pg.Color("white"))
@ -103,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)
@ -136,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
@ -175,7 +215,7 @@ def showGameOverText(screen, text):
screen.blit(text_object, text_location)
text_object = font.render(text, False, pg.Color('red'))
screen.blit(text_object, text_location.move(-2 , -2))
pg.display.flip()
def MainMenu():
#显示主菜单
@ -185,20 +225,44 @@ def MainMenu():
#ui
screen = pg.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pg.display.set_caption("SafariChess by ZY&&DQ")
bg = pg.transform.scale(pg.image.load("Image/MenuBg.jpg"), (SCREEN_WIDTH, SCREEN_HEIGHT))
bg = pg.transform.scale(pg.image.load("Image/MenuBg.bmp"), (SCREEN_WIDTH, SCREEN_HEIGHT))
bt1 = pg.transform.scale(pg.image.load("Image/button1.jpg"),(150,40))
bt2 = pg.transform.scale(pg.image.load("Image/button2.jpg"),(150,40))
bt3 = pg.transform.scale(pg.image.load("Image/button3.jpg"),(150,40))
bt4 = pg.transform.scale(pg.image.load("Image/button4.jpg"),(150,40))
music_settings = pg.transform.scale(pg.image.load("Image/music.bmp"),(100,40))
#按钮设置
#主菜单包含如下按钮:
#单机游戏,双人游戏,人机对战,退出游戏
button_1 = Button(bt1,(350,350))
button_2 = Button(bt2,(350,400))
button_3 = Button(bt3,(350,450))
button_4 = Button(bt4,(350,500))
button_1 = Button(bt1,(300,350))
button_2 = Button(bt2,(300,400))
button_3 = Button(bt3,(300,450))
button_4 = Button(bt4,(300,500))
music_button = Button(music_settings,(700,0))
#音乐设置
file=r'./Image/music1.mp3' #要播放的歌曲本地地址
pg.mixer.init() #mixer的初始化
music = pg.mixer.music.load(file) #载入一个音乐文件用于播放
pg.mixer.music.play(-1) #播放音乐,-1表示循环播放
COLOR_INACTIVE = (255, 108, 0)
COLOR_ACTIVE = (255, 208, 0)
COLOR_LIST_INACTIVE = (0, 143, 90)
COLOR_LIST_ACTIVE = (3, 252, 140)
# music_ops = DropDown([COLOR_INACTIVE, COLOR_ACTIVE],[COLOR_LIST_INACTIVE, COLOR_LIST_ACTIVE],
# 600,30, 100, 20,
# pg.font.SysFont("Courier", 20),
# "Music",
# music_lists)
mode = -1
p1,p2 = 0,0
run = True
while run:
mainClock.tick(60)
@ -226,51 +290,85 @@ def MainMenu():
if button_4.rect.collidepoint(event.pos):
pg.quit()
sys.exit()
if music_button.rect.collidepoint(event.pos):
if pg.mixer.music.get_volume() == 0:
pg.mixer.music.set_volume(0.5)
else:
pg.mixer.music.set_volume(0)
pg.display.flip()
screen.blit(bg, (0, 0))
screen.blit(button_1.image, button_1.rect)
screen.blit(button_2.image, button_2.rect)
screen.blit(button_3.image, button_3.rect)
screen.blit(button_4.image, button_4.rect)
screen.blit(music_button.image, music_button.rect)
pg.display.flip()
return mode
def main(mode,p1,p2,network = None):
NewPlayerMessage = '' #来自对手的信息
if mode == 2:
network=backend.Network()
player1 = input("Enter your name: ")
myPlayerData = {
'type': 0, # game state type ?
'msg': {
'name': player1
}
}
network.send(myPlayerData)
print("Waiting for other player...")
NewPlayerMessage = network.receive()
print()
player2 = NewPlayerMessage['counterpart_name']
#绘制Text在屏幕上
def showText(screen,fontObj,text,x,y):
textSurfaceObj = fontObj.render(text, True, pg.Color('red'),pg.Color('white'))# 配置要显示的文字
textRectObj = textSurfaceObj.get_rect()# 获得要显示的对象的rect
textRectObj.center = (x, y)# 设置显示对象的坐标
screen.blit(textSurfaceObj, textRectObj)# 绘制字体
def drawButton22(screen):
##一些按钮的实例化
button_stop = Button(pg.transform.scale(pg.image.load("Image/叫停.bmp"),(100,50)),(400,0))
screen.blit(button_stop.image, button_stop.rect)
button_quit = Button(pg.transform.scale(pg.image.load("Image/退出.bmp"),(100,50)),(300,0))
screen.blit(button_quit.image, button_quit.rect)
button_fail = Button(pg.transform.scale(pg.image.load("Image/认输.bmp"),(100,50)),(500,0))
screen.blit(button_fail.image, button_fail.rect)
button_restart = Button(pg.transform.scale(pg.image.load("Image/restart.bmp"),(100,50)),(100,0))
screen.blit(button_restart.image, button_restart.rect)
def main(mode):
global networkMsg
networkMsg = None
pg.init()
screen = pg.display.set_mode((BOARD_WIDTH + MOVE_LOG_PANEL_WIDTH, BOARD_HEIGHT))
pg.display.set_caption("Safafi Chess Game")
pg.display.set_caption("Safari Chess Game")
clock = pg.time.Clock()
screen.fill(pg.Color("white"))
loadImages()
drawBoard(screen)
isOnline = bool(network != None)
game_state=backend.GameState(isNet=isOnline,MySide=True if not isOnline else bool(NewPlayerMessage['side']))
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()
running = True
other_joined = False #network element
other_stage = False #network element
game_id = None #network element
MySide = None #network element
time_out_side = None #network element
foul = None #network element
mademove = False
game_over = False
square_selected = ()#刚开始没有选择任何一个棋子
click_queue = []#点击队列,记录第一次点击和第二次点击位置,方便移动棋子
square_selected = () #刚开始没有选择任何一个棋子
click_queue = [] #点击队列,记录第一次点击和第二次点击位置,方便移动棋子
##音乐按钮,均有
button_music = Button(pg.transform.scale(pg.image.load("Image/music.bmp"),(80,40)),(650,0))
screen.blit(button_music.image, button_music.rect)
pg.display.update()
startGamePage(mode)
if mode == 1:
startGamePage(mode) #游戏进入前,可以进一步优化一些显示细节
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():
#接下来处理游戏中的事件
@ -299,32 +397,257 @@ def main(mode,p1,p2,network = None):
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()
valid_moves = game_state.getAllMoves()
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")
game_over = True
clock.tick(60)
pg.display.flip()
elif mode == 2:
while running:
elif mode == 2 or mode == 4:
counts=general_countdown #双方倒计时
startNetworkServices()
#! start login
myPlayerData = {
'type': 0, # game state type ?
'msg': {
'name': 'myName'
}
}
login_packet = json.dumps(myPlayerData)
if (sys.version[:1] == '3'):
login_packet = login_packet.encode('utf-8')
lastNetworkMsg = networkMsg
client.send(login_packet)
login_font = pg.font.SysFont("comicsansms", 32)
text_object = login_font.render('waiting 4 connection...', True, pg.Color("grey"))
login_text_location = pg.Rect(0, 0, BOARD_WIDTH, BOARD_HEIGHT).move(BOARD_WIDTH / 2 - text_object.get_width() / 2,BOARD_HEIGHT / 2 - text_object.get_height() / 2)
while networkMsg == None:
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
sys.exit()
screen.blit(text_object,login_text_location)
clock.tick(20)
pg.display.update()
pg.display.flip()
#! end login
# 自定义计时事件-----计时器实现
COUNTS = pg.USEREVENT +1
# 每隔1秒发送一次自定义事件
pg.time.set_timer(COUNTS,1000) #以毫秒为单位
bigfont = pg.font.SysFont("Consolas", 20)
minfont = pg.font.SysFont("Courier", 18)
showText(screen,bigfont,"RemainTime:",680,200) #650,250为时间650350为对方轮数
showText(screen,minfont,"Turn:",650,300)
clock = pg.time.Clock()
clock.tick(60)
#drawButton22(screen)
button_stop = Button(pg.transform.scale(pg.image.load("Image/叫停.bmp"), (100, 50)), (400, 0))
screen.blit(button_stop.image, button_stop.rect)
button_quit = Button(pg.transform.scale(pg.image.load("Image/退出.bmp"), (100, 50)), (300, 0))
screen.blit(button_quit.image, button_quit.rect)
button_fail = Button(pg.transform.scale(pg.image.load("Image/认输.bmp"), (100, 50)), (500, 0))
screen.blit(button_fail.image, button_fail.rect)
button_restart = Button(pg.transform.scale(pg.image.load("Image/restart.bmp"), (100, 50)), (100, 0))
screen.blit(button_restart.image, button_restart.rect)
while running:
#! 特别注意红方是0蓝方是1
#print('current moving color: ',game_state.color())
if lastNetworkMsg != networkMsg:#handle
#! 无法解决的问题:判断延迟导致无法同时接收来自服务器的两条转发消息。
#! 尝试让输方发送消息解决上述问题。
print('catch new msg: ',networkMsg)
lastNetworkMsg = networkMsg #networkMsg中保存当前字典
if 'status' in networkMsg.keys():
#Login_handler
if networkMsg['status'] == 1: #Finished Login process
if other_joined == False:
other_joined = True
print('Game start 2 play!')
game_id = networkMsg['game_id']
MySide = networkMsg['side']
other_stage = True if networkMsg['side']==1 else False #一开始如果我是蓝方则other_stage为真
if(other_stage == True):
print('waiting for other player to move...')
#state_game_handler
elif networkMsg['status'] == 2 : # Stopping request
print('other player returned special message: ',networkMsg['request'])
if networkMsg['request']=='quit':
other_joined = False
elif networkMsg['request'] == 'stop':
game_state.win_person = 'b' if networkMsg['side'] == 1 else 'r'
pass
elif networkMsg['request'] == 'report':
foul = networkMsg['side']
otherQuitJson = {
'type': 3,
'side': MySide
}
client.send(json.dumps(otherQuitJson).encode('utf-8'))
game_over = True
#timeout handler
elif networkMsg['status'] == 3 :
time_out_side = networkMsg['side']
otherQuitJson = {
'type': 3,
'side': MySide
}
client.send(json.dumps(otherQuitJson).encode('utf-8'))
game_over = True
#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=general_countdown
thisMove = None
for e in pg.event.get():
#接下来处理游戏中的事件
if e.type == pg.QUIT:
quitJson = {
"type": 2,
"msg": {
"request": "quit",
"game_id": game_id,
"side": MySide
}
}
client.send(json.dumps(quitJson).encode('utf-8'))
pg.quit()
sys.exit()
elif e.type == pg.MOUSEBUTTONDOWN:
#鼠标点击事件:用于选择棋子,移动棋子
if not game_over:
if game_over and other_joined:
if e.button == 1:
if button_quit.rect.collidepoint(e.pos):
quitJson = {
"type": 2,
"msg": {
"request": "quit",
"game_id": game_id,
"side": MySide
}
}
client.send(json.dumps(quitJson).encode('utf-8'))
pg.quit()
sys.exit()
if not game_over and not other_stage and other_joined:
if e.button == 1:
if button_quit.rect.collidepoint(e.pos):
quitJson = {
"type": 2,
"msg": {
"request": "quit",
"game_id": game_id,
"side": MySide
}
}
client.send(json.dumps(quitJson).encode('utf-8'))
pg.quit()
sys.exit()
if button_stop.rect.collidepoint(e.pos):
winJson = {
'type': 2,
'msg': {
'request': 'stop',
'game_id': game_id,
'side': MySide
}
}
client.send(json.dumps(winJson).encode("utf-8"))
if button_fail.rect.collidepoint(e.pos):
quitJson = {
"type": 2,
"msg": {
"request": "quit",
"game_id": game_id,
"side": MySide
}
}
client.send(json.dumps(quitJson).encode('utf-8'))
if button_restart.rect.collidepoint(e.pos):
reportJson = {
"type": 2,
"msg": {
"request": "report",
"game_id": game_id,
"side": MySide
}
}
client.send(json.dumps(reportJson).encode('utf-8'))
mouse_loc = pg.mouse.get_pos()
row = int((mouse_loc[1] - bias_top) / SIZE)
col = int((mouse_loc[0] - bias_left) / SIZE) #* get position of mouse click
@ -338,6 +661,7 @@ def main(mode,p1,p2,network = None):
cur_piece_loc = click_queue[0]
nxt_piece_loc = click_queue[1]
move = backend.Move(cur_piece_loc,nxt_piece_loc,game_state.board)
thisMove = move
if move in valid_moves:
game_state.makeMove(move)
mademove = True
@ -345,28 +669,102 @@ def main(mode,p1,p2,network = None):
click_queue = []
else:
click_queue = [square_selected]
elif e.type == COUNTS:# 判断事件是否为计时事件
if not other_stage and counts > 0 and not game_over: counts -= 1
text = str(counts).rjust(3)
showText(screen,bigfont,text,650,250)
pg.display.update()
elif e.type == pg.KEYDOWN:
#设置某些按键用于悔棋,重新开始游戏,机器提示,退出游戏等功能
pass
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:
valid_moves = game_state.getAllMoves()
ShowGameState(screen,game_state,valid_moves,square_selected)
if game_state.conquer():
showGameOverText(screen,"player "+game_state.win_person+" wins")
game_over = True
clock.tick(60)
#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,
'msg': {
"game_id": game_id,
"side": MySide,
"chessman": int(thisMove.cur_piece[1:]),
"src": {
"y": thisMove.start_row,
"x": thisMove.start_col
},
"dst": {
"y": thisMove.end_row,
"x": thisMove.end_col
}
}
}
client.send(json.dumps(thisMoveJson).encode('utf-8'))
#思路变成:定时对敌方进行扫描,若收到更新相关包则进行局面更新。
ShowGameState(screen,game_state,valid_moves,square_selected)
if game_state.conquer() and not game_over:
print("GAME OVER!")
#
if game_state.win_person == ('r' if MySide == 1 else 'b'): #测试:我输了再发
winJson = {
'type': 2,
'msg': {
'request': 'stop',
'game_id': game_id,
'side': MySide
}
}
client.send(json.dumps(winJson).encode("utf-8"))
print('i lost, and game over message sent.')
game_over = True
#print('game over label confirmed.')
if game_over and other_joined:
if (game_state.win_person == ''): game_state.conquer()
showGameOverText(screen,"player "+game_state.win_person+" wins")
if game_over and not other_joined:
showGameOverText(screen,"player "+ ("b" if MySide==0 else "r") + " quitted the game") #对手退出了
if time_out_side != None:
showGameOverText(screen,"player "+ ("b" if time_out_side==1 else "r")+" timed out") #超时了
showText(screen,bigfont,game_state.color(),700,350)
clock.tick(50)
pg.display.flip()
if __name__ == '__main__':
print("Loading...")
print("Initialing game...")
#print("Loading...")
#print("Initialing game...")
mode = MainMenu()
player1='player1'
network = None #前后端通信接口
player2='player2'
main(mode,player1,player2,network)
#mode = 4
main(mode)

@ -1,38 +1,48 @@
import socket
import socket
import this
import requests
import sys
import json
class GameState:
'''
def uploadtoServer(self,move):
#将move转换为json格式
#将json格式的move上传到服务器
pass
def getEnemyMove(self):
#从服务器获取json信息
#将json信息转化成move
#返回move
pass
from threading import Thread
from queue import Queue
#multithreading?
def updatefromServer(self,move):
move=getEnemyMove()
self.makeMove(move)
pass
def getLoginInfo(self):
#从服务器获取登录信息
#返回登录信息
pass
'''
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 __init__(self, isNet = False, MySide = True):
def startNewThread(target):
thread = Thread(target=target)
thread.daemon = True
thread.start()
class GameState:
def __init__(self):
'''
有关信息
1. 棋盘尺寸为7*9横向
@ -68,18 +78,94 @@ class GameState:
self.blue_pieces=[7,6,5,4,3,2,1]
self.red_pieces=[7,6,5,4,3,2,1]
#红方(右)先行
self.isNet = isNet
self.red_to_move=MySide
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 upld2server(self,move):
pass
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
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":
@ -123,8 +209,15 @@ class GameState:
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
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
@ -165,37 +258,37 @@ class GameState:
#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):
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
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):
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
while new_col >= 0:
nxt_piece = self.board[row][new_col]
if nxt_piece == '00' and not self.inTrap(row,new_col,enemy_color):
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
while new_col <= 8:
nxt_piece = self.board[row][new_col]
if nxt_piece == '00' and not self.inTrap(row,new_col,enemy_color):
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
@ -277,6 +370,7 @@ class GameState:
#移动操作
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':
@ -285,64 +379,17 @@ class GameState:
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'
if not self.isNet: self.red_to_move = not self.red_to_move
else:
class Network:
def __init__(self):
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.red_to_move = not self.red_to_move
self.move_log.append(move)
self.msg = self.connect()
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')
#return self.client.recv(2048).encode()
self.client.send(packet)
except socket.error as e:
print(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:
msg = json.loads(self.client.recv(2048))
print(msg)
return msg
except socket.error as e:
print(e)
return e
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
#由于使用多线程考虑让另一个线程去更新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

@ -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=15
MAX_THNIKING_TIME=10
MAX_TOTAL_TIME=1000

Loading…
Cancel
Save