Merge branch 'qq_branch'

master
tzzzzzzzx 3 years ago
commit 0e05e4f0c5

@ -12,6 +12,24 @@
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"justMyCode": true
},
{
"name": "run single server",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/network/server.py",
"cwd": "${fileDirname}",
"console": "integratedTerminal",
"justMyCode": true
},
{
"name": "current file",
"type": "python",
"request": "launch",
"program": "${file}",
"cwd": "${fileDirname}",
"console": "integratedTerminal",
"justMyCode": true
}
]
}

@ -124,5 +124,12 @@ ex.大致图像
#### 二、开发流程
UI设计
-----增加相关按钮,增加提示,增加每一步的提示
(二)功能实现
-----与服务器数据交换

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

@ -4,18 +4,15 @@
"""
class Button:
def _init_(self, image, position, callback=None):
def __init__(self, image, position, callback=None):
self.image = image
self.rect = image.get_rect(topleft=position)
self.callback = callback
def on_click(self, mouse_pos):
if self.rect.collidepoint(mouse_pos):
if self.callback:
self.callback()
return True
return False
def on_click(self, event):
if event.button == 1:
if self.rect.collidepoint(event.pos):
self.callback(self)
#class DropDown():
#下拉选择框

@ -10,21 +10,21 @@ it handle user input and GUI
"""
import colorsys
from json import load
import json
import pygame as pg
import sys
from time import process_time
import socket
import SafariChess_backend as backend
import SafariChess_Classes as classes
from SafariChess_Classes import Button
from threading import Thread, Lock
#设置棋盘的参数
WIDTH = 800
HEIGHT = 1000
BOARD_WIDTH = 600
BOARD_HEIGHT = 800
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 800
WIDTH = 1000
HEIGHT = 800
BOARD_WIDTH = 800
BOARD_HEIGHT = 600
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
MOVE_LOG_PANEL_WIDTH = 0
MOVE_LOG_PANEL_HEIGHT = BOARD_HEIGHT
DIMENSION = 8
@ -32,8 +32,11 @@ DIMENSION_ROWS = 7
DIMENSION_COLUMNS = 9
SIZE = 64
IMAGES = {}
bias_top = 200 #棋盘的上边距
bias_left = 10 #棋盘的左边距
bias_top = 100 #棋盘的上边距
bias_left = 100 #棋盘的左边距
#multithreading?
mutex = Lock()
mutex_playing = Lock()
def loadImages():#加载图片,a,b双方分别有象狮豹狼狐鹰鼠七个角色
pieces = ["r7", "r6", "r5", "r4", "r3", "r2", "r1",
@ -81,6 +84,7 @@ def drawPieces(screen,board):
screen.blit(IMAGES[piece], pg.Rect((column * SIZE) + bias_left + 5, (row * SIZE) + bias_top + 5, SIZE - 10, SIZE - 10))
# square_selected 是当前选中的可以移动的棋子的位置
def protrudeSquares(screen,game_state,square_selected,valid_moves):
#高亮选中的棋子接下来可行的位置
@ -112,8 +116,8 @@ def drawMovelog(screen):#绘制移动日志
pass
def startGamePage():#开始游戏界面Human/AI
startpage = '''
def startGamePage(mode = 1):#开始游戏界面Human/AI
startpage = ('''
WELCOME TO
@ -129,13 +133,13 @@ def startGamePage():#开始游戏界面Human/AI
################################################################
Please type one of the numbers below to choose a playing mode:
( 1 ) - Human vs Human
( 2 ) - Human vs AI
( 3 ) - AI vs AI
( 4 ) - Quit
( 1 ) - 单机游戏
( 2 ) - 网络对战
( 3 ) - 人机对战
( 4 ) - 退出游戏
################################################################
'''
Current Mode is: %s
'''%['单机游戏','网络对战','人机对战','退出游戏'][mode-1])
print(startpage)
# 选择游戏模式
not_selected = True
@ -143,7 +147,7 @@ Please type one of the numbers below to choose a playing mode:
while not_selected:
try:
#mode = int(input())
mode = 1
#mode = 1
if mode in [1,2,3,4]:
if mode == 1:
p1 = 1
@ -152,10 +156,10 @@ Please type one of the numbers below to choose a playing mode:
not_selected = False
else:
print("Please type one of the numbers below to choose a playing mode:")
print(" ( 1 ) - Human vs Human")
print(" ( 2 ) - Human vs AI")
print(" ( 3 ) - AI vs AI")
print(" ( 4 ) - Quit")
print(" ( 1 ) - 单机游戏")
print(" ( 2 ) - 网络对战")
print(" ( 3 ) - 人机对战")
print(" ( 4 ) - 退出游戏")
except ValueError:
print("Wrong Input")
return p1, p2, mode
@ -178,16 +182,76 @@ def MainMenu():
pg.init()
mainClock = pg.time.Clock()
#ui
screen = pg.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pg.display.set_caption("SafariChess by ZY&&DQ")
bg = pg.image.load("images/MenuBg.jpg")
bg = pg.transform.scale(pg.image.load("Image/MenuBg.jpg"), (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))
#按钮设置
return 1
#主菜单包含如下按钮:
#单机游戏,双人游戏,人机对战,退出游戏
button_1 = Button(bt1,(350,350))
button_2 = Button(bt2,(350,400))
button_3 = Button(bt3,(350,450))
button_4 = Button(bt4,(350,500))
mode = -1
p1,p2 = 0,0
run = True
while run:
mainClock.tick(60)
mode = 0
events = pg.event.get()
for event in events:
if event.type == pg.QUIT:
pg.quit()
sys.exit()
if event.type == pg.KEYDOWN:
if event.key == pg.K_ESCAPE:
pg.quit()
sys.exit()
if event.type == pg.MOUSEBUTTONDOWN:
if event.button == 1: #左键
if button_1.rect.collidepoint(event.pos):
mode = 1
run = False
if button_2.rect.collidepoint(event.pos):
mode = 2
run = False
if button_3.rect.collidepoint(event.pos):
mode = 3
run = False
if button_4.rect.collidepoint(event.pos):
pg.quit()
sys.exit()
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)
pg.display.flip()
return mode
def main():
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']
pg.init()
screen = pg.display.set_mode((BOARD_WIDTH + MOVE_LOG_PANEL_WIDTH, BOARD_HEIGHT))
pg.display.set_caption("Safafi Chess Game")
@ -195,7 +259,8 @@ def main():
screen.fill(pg.Color("white"))
loadImages()
drawBoard(screen)
game_state=backend.GameState()
isOnline = bool(network != None)
game_state=backend.GameState(isNet=isOnline,MySide=True if not isOnline else bool(NewPlayerMessage['side']))
valid_moves=game_state.getAllMoves()
running = True
mademove = False
@ -203,56 +268,105 @@ def main():
square_selected = ()#刚开始没有选择任何一个棋子
click_queue = []#点击队列,记录第一次点击和第二次点击位置,方便移动棋子
pg.display.update()
startGamePage()
while running:
for e in pg.event.get():
#接下来处理游戏中的事件
if e.type == pg.QUIT:
pg.quit()
sys.exit()
startGamePage(mode)
if mode == 1:
while running:
for e in pg.event.get():
#接下来处理游戏中的事件
if e.type == pg.QUIT:
pg.quit()
sys.exit()
elif e.type == pg.MOUSEBUTTONDOWN:
#鼠标点击事件:用于选择棋子,移动棋子
if not game_over:
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
if square_selected == (row,col) or col >=DIMENSION_COLUMNS or row >= DIMENSION_ROWS:
square_selected = ()
click_queue = []
else:
square_selected = (row,col)
click_queue.append(square_selected)
if(len(click_queue) == 2):
cur_piece_loc = click_queue[0]
nxt_piece_loc = click_queue[1]
move = backend.Move(cur_piece_loc,nxt_piece_loc,game_state.board)
if move in valid_moves:
game_state.makeMove(move)
mademove = True
square_selected = ()
click_queue = []
else:
click_queue = [square_selected]
elif e.type == pg.KEYDOWN:
#设置某些按键用于悔棋,重新开始游戏,机器提示,退出游戏等功能
pass
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)
pg.display.flip()
elif mode == 2:
while running:
elif e.type == pg.MOUSEBUTTONDOWN:
#鼠标点击事件:用于选择棋子,移动棋子
if not game_over:
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
if square_selected == (row,col) or col >=DIMENSION_COLUMNS or row >= DIMENSION_ROWS:
square_selected = ()
click_queue = []
else:
square_selected = (row,col)
click_queue.append(square_selected)
if(len(click_queue) == 2):
cur_piece_loc = click_queue[0]
nxt_piece_loc = click_queue[1]
move = backend.Move(cur_piece_loc,nxt_piece_loc,game_state.board)
if move in valid_moves:
game_state.makeMove(move)
mademove = True
for e in pg.event.get():
#接下来处理游戏中的事件
if e.type == pg.QUIT:
pg.quit()
sys.exit()
elif e.type == pg.MOUSEBUTTONDOWN:
#鼠标点击事件:用于选择棋子,移动棋子
if not game_over:
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
if square_selected == (row,col) or col >=DIMENSION_COLUMNS or row >= DIMENSION_ROWS:
square_selected = ()
click_queue = []
else:
click_queue = [square_selected]
square_selected = (row,col)
click_queue.append(square_selected)
if(len(click_queue) == 2):
cur_piece_loc = click_queue[0]
nxt_piece_loc = click_queue[1]
move = backend.Move(cur_piece_loc,nxt_piece_loc,game_state.board)
if move in valid_moves:
game_state.makeMove(move)
mademove = True
square_selected = ()
click_queue = []
else:
click_queue = [square_selected]
elif e.type == pg.KEYDOWN:
#设置某些按键用于悔棋,重新开始游戏,机器提示,退出游戏等功能
pass
elif e.type == pg.KEYDOWN:
#设置某些按键用于悔棋,重新开始游戏,机器提示,退出游戏等功能
pass
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)
pg.display.flip()
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)
pg.display.flip()
if __name__ == '__main__':
print("Loading...")
print("Initialing game...")
main()
mode = MainMenu()
player1='player1'
network = None #前后端通信接口
player2='player2'
main(mode,player1,player2,network)

@ -1,11 +1,46 @@
import socket
import requests
import sys
import json
class GameState:
def __init__(self):
'''
def uploadtoServer(self,move):
#将move转换为json格式
#将json格式的move上传到服务器
pass
def getEnemyMove(self):
#从服务器获取json信息
#将json信息转化成move
#返回move
pass
def updatefromServer(self,move):
move=getEnemyMove()
self.makeMove(move)
pass
def getLoginInfo(self):
#从服务器获取登录信息
#返回登录信息
pass
'''
def __init__(self, isNet = False, MySide = True):
'''
有关信息
1. 棋盘尺寸为7*9横向
2. 按照以下命名格式对棋盘中的棋子进行标注
(b|r)(1|2|3|4|5|6|7)
3.
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'],
@ -32,15 +67,18 @@ class GameState:
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=False
#红方(右)先行
self.isNet = isNet
self.red_to_move=MySide
self.conquered=False
self.win_person=''
self.MASSACRE=False
def color(self):
return 'r' if self.red_to_move else 'b'
#网络版相关组件
def upld2server(self,move):
pass
# 判断特殊位置
def inHome(self,row,col,color):
@ -247,7 +285,52 @@ 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'
self.red_to_move = not self.red_to_move
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.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):

@ -0,0 +1,5 @@
SOCKET_HOST=127.0.0.1
SOCKET_PORT=50005
MAX_WAITING_TIME=600
MAX_THNIKING_TIME=15
MAX_TOTAL_TIME=1000

@ -0,0 +1,247 @@
# coding:utf-8
import socket
import sys
import json
import uuid
import time
from threading import Thread, Lock
if(sys.version[:1] == "3"):
import queue as Queue
from _thread import *
else:
import Queue
from thread import *
class Config:
SOCKET_HOST = '127.0.0.1' # Symbolic name meaning all available interfaces
SOCKET_PORT = 50005 # Arbitrary non-privileged port
MAX_WAITING_TIME = 180
MAX_THNIKING_TIME = 60
MAX_TOTAL_TIME = 600
class Client:
def __init__(self, conn, addr, name, side, time, total):
self.conn = conn
self.addr = addr
self.name = name
self.side = side
self.time = time
self.total = total
mutex = Lock()
mutex_playing = Lock()
playing_ones = {}
waiting_players = Queue.Queue()
#init queues
#for games in range(1, 10):
# waiting_players[games] = Queue.Queue()
def load_config():
with open('config.txt', 'r') as f:
for line in f.readlines():
line = line.strip()
if line.find('SOCKET_HOST=') >= 0:
Config.SOCKET_HOST = line[line.index('=') + 1 : ]
elif line.find('SOCKET_PORT=') >= 0:
Config.SOCKET_PORT = int(line[line.index('=') + 1 : ])
elif line.find('MAX_WAITING_TIME=') >= 0:
Config.MAX_WAITING_TIME = int(line[line.index('=') + 1 : ])
elif line.find('MAX_THNIKING_TIME=') >= 0:
Config.MAX_THNIKING_TIME = int(line[line.index('=') + 1 : ])
elif line.find('MAX_TOTAL_TIME=') >= 0:
Config.MAX_TOTAL_TIME = int(line[line.index('=') + 1 : ])
else:
pass
def get_counterpart_from(waiting_ones):
counterpart = None
mutex.acquire()
if not waiting_ones.empty():
counterpart = waiting_ones.get()
mutex.release()
return counterpart
def to_wait_in_queue(client, the_queue):
mutex.acquire()
the_queue.put(client)
mutex.release()
def remove_one_from_queue(the_queue):
mutex.acquire()
if (the_queue.qsize() == 1):
the_queue.get()
mutex.release()
def send_msg_to(client, msg):
packet = json.dumps(msg)
if (sys.version[:1] == "3"):
packet = packet.encode('utf-8')
#print(client.addr[0] + ":" + str(client.addr[1]) + "\t" + str(msg))
client.conn.send(packet)
def __start_match_between(client0, client1):
match_uuid = str(uuid.uuid4())
mutex_playing.acquire()
playing_ones[match_uuid] = (client0, client1)
mutex_playing.release()
client0.side = 0
client0.time = Config.MAX_THNIKING_TIME
client0.total = Config.MAX_TOTAL_TIME
client1.side = 1
client1.time = -1
client1.total = Config.MAX_TOTAL_TIME
msg0 = {
"status": 1,
"counterpart_name": client1.name,
"game_id": match_uuid,
"side": client0.side,
"think_time": Config.MAX_THNIKING_TIME,
"total_time": Config.MAX_TOTAL_TIME,
}
send_msg_to(client0, msg0)
msg1 = {
"status": 1,
"counterpart_name": client0.name,
"game_id": match_uuid,
"side": client1.side,
"think_time": Config.MAX_THNIKING_TIME,
"total_time": Config.MAX_TOTAL_TIME,
}
send_msg_to(client1, msg1)
def join_game_handler(msg, addr, conn):
new_client = Client(conn, addr, msg['name'], -1, -1, -1)
#game_type = msg["id"]
#the_queue = waiting_players[game_type]
counterpart = get_counterpart_from(waiting_players)
if not counterpart: #wait
to_wait_in_queue(new_client, waiting_players)
return
else:
#counterpart=get_counterpart_from(waiting_players[game_type])
__start_match_between(new_client, counterpart)
def quit_game_handler(msg):
match_uuid = msg['game_id']
if match_uuid is None:
remove_one_from_queue(waiting_players)
return
pairs = None
mutex_playing.acquire()
if (match_uuid in playing_ones):
pairs = playing_ones[match_uuid]
del playing_ones[match_uuid]
mutex_playing.release()
if pairs is not None:
if(pairs[0].side == msg['side']):
to_notify = pairs[1]
else:
to_notify = pairs[0]
msg = {
"status": 2, #exit
"game_id": match_uuid,
"side": msg['side'],
"request": msg['request'],
}
send_msg_to(to_notify, msg)
def timer_thread():
while True:
time.sleep(1)
mutex_playing.acquire()
for game_id in list(playing_ones.keys()):
(client0, client1) = playing_ones[game_id]
#print("%d - %d" % (client0.time, client1.time))
if (client0.time < 0):
client = client1
else:
client = client0
if (client.time == 0 or client.total == 0):
msg = {
"status": 3, #timeout exit
"game_id": game_id,
"side": client.side,
}
send_msg_to(client0, msg)
send_msg_to(client1, msg)
del playing_ones[game_id]
else:
client.time -= 1
client.total -= 1
mutex_playing.release()
def transfer_message(msg):
match_uuid = msg['game_id']
pairs = playing_ones[match_uuid]
if(pairs[0].side == msg['side']):
to_notify = pairs[1]
pairs[0].time = -1
else:
to_notify = pairs[0]
pairs[1].time = -1
to_notify.time = Config.MAX_THNIKING_TIME
send_msg_to(to_notify, msg)
def client_thread(conn, addr):
while True:
data = conn.recv(1024)
if not data:
break
print(data)
data = json.loads(data)
if not 'type' in data:
transfer_message(data['msg'])
continue
if data['type'] == 0:
join_game_handler(data['msg'], addr, conn)
continue
elif data['type'] == 1:
transfer_message(data['msg'])
continue
elif data['type'] == 2:
quit_game_handler(data['msg'])
break
elif data['type'] == 3:
break
else:
#delivering message between the two clients
transfer_message(data['msg'])
continue
#came out of loop
conn.close()
def main():
load_config()
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('Socket server created')
#try:
server.bind((Config.SOCKET_HOST, Config.SOCKET_PORT))
#except (socket.error, msg):
# print ('Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1])
# sys.exit()
print('Socket bind complete')
server.listen(10)
print('Socket now listening')
#now keep talking with the client
start_new_thread(timer_thread, ())
while True: #! 监听本体
#wait to accept a connection - blocking call
conn, addr = server.accept()
print ('Connected with ' + addr[0] + ':' + str(addr[1]))
#start new thread takes 1st argument as a function name to be run, second is the tuple of arguments to the function.
start_new_thread(client_thread, (conn, addr))
server.close()
if __name__ == '__main__':
main()
Loading…
Cancel
Save