上篇我们对python的Socket编程有了一个基本的认识,接下来就可以完成五子棋的网络对战的实现。步骤如下:
1、服务端开始侦听
2、客户端通过tcp连接上服务端,开局
3、判断输赢后,一方提出是否开新局
4、对方同意后,开新局。
接下来就简单了,只要把Socket编程的通信部分弄到以前的代码就可以了。
五子棋人机对战版:(
https://blog.csdn.net/cxhold/article/details/140126002
https://blog.csdn.net/cxhold/article/details/140133224
https://blog.csdn.net/cxhold/article/details/140136176
https://blog.csdn.net/cxhold/article/details/140142940
https://blog.csdn.net/cxhold/article/details/140159258)
三、
代码结构:
服务端和客户端的代码区别就在main.py中
3.1 服务端main.py
# encoding:utf-8
import pygame
from pygame.locals import *
import sys
import os
from socket import *
import select
import piece
from tkinter import *
from params import Params
from utils import *
pygame.init()
pygame.mixer.init()
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
rows = int(Params.get('ROWS'))
blocksize = int(Params.get('blockSize'))
width = int(Params.get('WIDTH'))
height = int(Params.get('HEIGHT'))
game_bgsize = width, height
# 棋盘
x = [] #x轴
y = [] #y轴
for i in range(0, rows): #棋盘的所有交叉点坐标(x,y)
x.append(28 + i * blocksize)
y.append(28 + i * blocksize)
# 记录棋盘每个坐标的属性,没有棋子为0,白棋为1,黑棋为2
chess_map = {} #结构是chess_map[28,28] = 0 ...
# 字体
fontpath = os.path.join(Params.get('resourcePath'), Params.get('fontFolder'), 'simkai.ttf')
myfont = pygame.font.Font(fontpath, 38)
# 起始选项
txtplayerandplayer = myfont.render("玩家与玩家", True, WHITE)
txtplayerandplayer_rect = txtplayerandplayer.get_rect()
txtplayerandplayer_rect.left, txtplayerandplayer_rect.top = (game_bgsize[0] - txtplayerandplayer_rect.width) // 2, \
(game_bgsize[1] - txtplayerandplayer_rect.height) // 2 - 100
txtplayerandcomputer = myfont.render('玩家与电脑', True, WHITE)
txtplayerandcomputer_rect = txtplayerandcomputer.get_rect()
txtplayerandcomputer_rect.left, txtplayerandcomputer_rect.top = (game_bgsize[0] - txtplayerandplayer_rect.width) // 2, \
(game_bgsize[1] - txtplayerandplayer_rect.height) // 2
txtplaysound = myfont.render('音效: 开', True, WHITE)
txtplaysound_rect = txtplaysound.get_rect()
txtplaysound_rect.left, txtplaysound_rect.top = (game_bgsize[0] - txtplaysound_rect.width) // 2, \
(game_bgsize[1] - txtplaysound_rect.height) // 2 + 100
txtclosesound = myfont.render('音效: 关', True, WHITE)
txtclosesound_rect = txtclosesound.get_rect()
txtclosesound_rect.left, txtclosesound_rect.top = (game_bgsize[0] - txtclosesound_rect.width) // 2, \
(game_bgsize[1] - txtclosesound_rect.height) // 2 + 100
# 输赢
successtext = myfont.render("你有点屌哦!!!", True, WHITE)
successtext_rect = successtext.get_rect()
successtext_rect.left, successtext_rect.top = (game_bgsize[0] - successtext_rect.width) // 2, \
(game_bgsize[1] - successtext_rect.height) // 2
failuretext = myfont.render("小趴菜...", True, WHITE)
failuretext_rect = failuretext.get_rect()
failuretext_rect.left, failuretext_rect.top = (game_bgsize[0] - failuretext_rect.width) // 2, \
(game_bgsize[1] - failuretext_rect.height) // 2
playagaintext = myfont.render("再玩一局", True, WHITE)
menutext = myfont.render('主菜单', True, WHITE)
#连接
txtwatting = myfont.render('等待连接', True, WHITE)
txtwatting_rect = txtclosesound.get_rect()
txtwatting_rect.left, txtwatting_rect.top = (game_bgsize[0] - txtwatting_rect.width) // 2, \
(game_bgsize[1] - txtwatting_rect.height) // 2
txtclosed = myfont.render('对方不愿和你玩并断开了连接', True, WHITE)
txtclosed_rect = txtclosed.get_rect()
txtclosed_rect.left, txtclosed_rect.top = (game_bgsize[0] - txtclosed_rect.width) // 2, \
(game_bgsize[1] - txtclosed_rect.height) // 2
txtchallenge = myfont.render('对方再次向你发起挑战', True, WHITE)
txtchallenge_rect = txtchallenge.get_rect()
txtchallenge_rect.left, txtchallenge_rect.top = (game_bgsize[0] - txtchallenge_rect.width) // 2, \
(game_bgsize[1] - txtchallenge_rect.height) // 2
txtrecive = myfont.render('接受挑战 不接受挑战', True, WHITE)
txtrecive_rect = txtrecive.get_rect()
txtrecive_rect.left, txtrecive_rect.top = (game_bgsize[0] - txtrecive_rect.width) // 2, \
(game_bgsize[1] - txtrecive_rect.height) // 2 + 100
# TCP服务
HOST = '' # 地址
POST = 23338 # 端口
BUFSIZE = 2048 #缓冲区
HOSTADDR = (HOST, POST)
tcpserversocket = socket(AF_INET, SOCK_STREAM) #创建套接字
tcpserversocket.bind(HOSTADDR)
tcpserversocket.listen(1) #listen(n)的n值表示socket的“排队个数”,表示的是服务器拒绝(超过限制数量的)连接之前,操作系统可以挂起的最大连接数量。
#一般情况下,一个进程只有一个主线程(也就是单线程),那么socket允许的最大连接数为: n + 1 \
# 如果服务器是多线程,比如开了2个线程,那么socket允许的最大连接数就是: n + 2 \
# 换句话说:排队的人数(就是那个n) + 正在就餐的人数(服务器正在处理的socket连接数) = 允许接待的总人数(socket允许的最大连接数)\
# 因此listen(1),最大连接数是2,就是1个处理,1个“排队”
inputs = [tcpserversocket]
# 判断棋盘某位置上是否有棋子
def isempty(theposition):
global chess_map
existpiece = False
if chess_map[str(theposition[0]) + ',' + str(theposition[1])]:
existpiece = True
return existpiece
# 电脑选取落子的位置
def computerdecision():
value = max1 = max2 = 0
pos1 = pos2 = ()
# 进攻
for i in range(0, rows):
row = 28 + i * blocksize
for j in range(0, rows):
col = 28 + j * blocksize
pos = (row, col)
if isempty(pos):
continue
value = pointvalue(chess_map,pos, 1, 2)
if value > max1:
max1 = value
pos1 = (row, col)
# 防守
for i in range(0, rows):
for j in range(0, rows):
row = 28 + i * blocksize
col = 28 + j * blocksize
if isempty((row, col)):
continue
value = pointvalue(chess_map,(row, col), 2, 1)
if value > max2:
max2 = value
pos2 = (row, col)
if max1 > max2:
return pos1
else:
return pos2
# 初始化棋盘
def init():
global chess_map
for i in x:
for j in y:
chess_map[str(i) + ',' + str(j)] = 0 #清空
def main():
os.environ['SDL_VIDEO_CENTERED'] = '1' #居中
screen = pygame.display.set_mode(game_bgsize)
pygame.display.set_caption('五子棋服务端')
bgimagepath = os.path.join(Params.get('resourcePath'), Params.get('imgFolder'), 'bg.png')
bg_image = pygame.image.load(bgimagepath).convert_alpha() # 背景图片加载
zzimagepath = os.path.join(Params.get('resourcePath'), Params.get('imgFolder'), 'zz.png') #遮罩图片
zz_image = pygame.image.load(zzimagepath).convert_alpha()
# 背景音乐
bgsoundpath = os.path.join(Params.get('resourcePath'), Params.get('soundFolder'), '齐豫 - 莲花处处开.mp3')
bg_sound = pygame.mixer.music.load(bgsoundpath) # 背景音乐加载
pygame.mixer.music.set_volume(0.08)
pygame.mixer.music.play(-1)
clicksoundpath = os.path.join(Params.get('resourcePath'), Params.get('soundFolder'), 'drop.wav')
piece_sound = pygame.mixer.Sound(clicksoundpath)
clock = pygame.time.Clock()
# 棋子
white_chesses = [] #白棋子对象
black_chesses = [] #黑棋子对象
white_positions = [] #白棋子位置集合
black_positions = [] #黑棋子位置集合
chesses = [] #所有棋子集合,主要是显示用
is_player = False # 轮到哪方下棋,
is_finish = False # 是否结束游戏
# 赢方
black_win = False
white_win = False
people2people = False # 人与人,网络版
people2computer = False # 人与电脑
is_choise = False # 是否做出选择对战方式,是people2people 还是 people2computer , 通过菜单选择对战方式
is_play_sound = True # 是否播放声音
is_playagain = False # 是否再来一局
# 是否连接
is_link = False
# 对方是否发来重新开始的消息
is_againmsg = False
# 对面拒绝了重新开始
is_reject = False
# 初始化
is_playagain = False
running = True
init()
while running:
screen.blit(bg_image, (0, 0))
# 绘制游戏菜单
if not is_choise:
screen.blit(zz_image, (0, 0)) #遮罩层
screen.blit(txtplayerandplayer, txtplayerandplayer_rect)
screen.blit(txtplayerandcomputer, txtplayerandcomputer_rect)
if not is_play_sound:
screen.blit(txtclosesound, txtclosesound_rect)
else:
screen.blit(txtplaysound, txtplaysound_rect)
else: #
if people2people:
if not is_link and not is_reject:
screen.blit(txtwatting, txtwatting_rect)
# 绘制棋盘
if is_choise:
if chesses:
for i in chesses:
screen.blit(i.image, i.image_rect())
for event in pygame.event.get():
if event.type == QUIT:
if is_link:
tcpclientsocket.close()
if people2people:
tcpserversocket.close()
pygame.quit()
sys.exit()
if event.type == MOUSEBUTTONDOWN: #server下棋
if event.button == 1 :
if is_finish :
if not is_againmsg and not is_reject:
pos = event.pos
if successtext_rect.left < pos[0] < successtext_rect.right and \
successtext_rect.top < pos[1] < successtext_rect.top + 30:
if people2people:
tcpclientsocket.send('again'.encode('utf8'))
if people2computer:
is_playagain = True
is_player = True
is_finish = False
init()
if successtext_rect.left < pos[0] < successtext_rect.right - 50 and \
successtext_rect.top + 50 < pos[1] < successtext_rect.top + 120:
people2people = False
is_choise = False
if is_link:
is_link = False
tcpclientsocket.send('no'.encode('utf8'))
main()
if is_reject:
pos = event.pos
if txtclosed_rect.left + 150 < pos[0] < txtclosed_rect.left + 250 and \
txtclosed_rect.top + 70 < pos[1] < txtclosed_rect.top + 190:
main()
is_choise = False
if is_againmsg:
pos = event.pos
if txtrecive_rect.left < pos[0] < txtrecive_rect.left + 150 and \
txtrecive_rect.top < pos[1] < txtrecive_rect.top + 120:
tcpclientsocket.send('yes'.encode('utf8'))
is_againmsg = False
is_playagain = True
is_player = False
is_finish = False
if txtrecive_rect.left + 330 < pos[0] < txtrecive_rect.left + 480 and \
txtrecive_rect.top < pos[1] < txtrecive_rect.top + 120:
tcpclientsocket.send('no'.encode('utf8'))
main()
if is_choise:
# 判断是否轮到server下棋
if is_player and not is_finish and not is_againmsg:
pos = event.pos
pblack = piece.Piece(pos,'pieces_black.png')
if not isempty(pblack.pointtrans()):
black_chesses.append(pblack)
black_positions.append(pblack.pointtrans())
chesses.append(pblack)
chess_map[str(pblack.pointtrans()[0]) + ',' + str(pblack.pointtrans()[1])] = 2
if people2people: #
tcpclientsocket.send(str(pos).encode('utf8'))
is_player = False
piece_sound.play()
# 判断输赢
if len(black_chesses)>=5 and not is_finish and checkwin(black_positions,pblack.pointtrans()[0],pblack.pointtrans()[1]) :
is_finish = True
black_win = True
else:
del (pblack)
else:
pos = event.pos
if txtplayerandplayer_rect.left <= pos[0] <= txtplayerandplayer_rect.left + 170 and \
txtplayerandplayer_rect.top <= pos[1] <= txtplayerandplayer_rect.top + 30:
is_choise = True
people2people = True
if txtplayerandplayer_rect.left <= pos[0] <= txtplayerandplayer_rect.left + 170 and \
txtplayerandplayer_rect.top + 100 <= pos[1] <= txtplayerandplayer_rect.top + 130:
is_choise = True
people2computer = True
is_player = True
if txtplayerandplayer_rect.left <= pos[0] <= txtplayerandplayer_rect.left + 160 and \
txtplayerandplayer_rect.top + 200 <= pos[1] <= txtplayerandplayer_rect.top + 230:
is_play_sound = not is_play_sound
if not is_play_sound:
pygame.mixer.stop()
pygame.mixer.music.stop()
else:
pygame.mixer.music.play()
'''
select 模块在 Python 中不是标准库的一部分,而是一个提供底层 socket 接口的系统级模块。它通常用于编写跨平台的非阻塞 socket 服务器。
select 模块中最常用的函数是 select(),它接受三个参数:
读取标准输入的文件描述符集合 inputs
写入标准输出的文件描述符集合 outputs
异常处理的文件描述符集合
'''
if people2people:
readable, writable, exceptional = select.select(inputs, [], [], 0) # 使用 select 模块的 select 函数进行非阻塞地等待连接,标准写法
for readline in readable:
if readline is tcpserversocket: # 处理新的连接
tcpclientsocket, HOSTADDR = tcpserversocket.accept()
inputs.append(tcpclientsocket)
is_link = True
# print('connenct')
else:
try: # 处理已连接的套接字数据
data = readline.recv(BUFSIZE) #获取数据
# print(data.decode('utf8'))
if data.decode('utf8') == 'again':
is_againmsg = True
if data.decode('utf8') == 'yes':
is_playagain = True
is_player = False
if data.decode('utf8') == 'no':
is_reject = True
is_link = False
disconnected = not data #如果没有数据,则关闭连接,disconnected为True
except error: #异常或错误时,则关闭连接,disconnected为True,is_link为False
disconnected = True
is_link = False
if disconnected: #断开后,移除接收的消息
inputs.remove(readline)
else:
if not is_player and not is_finish:
pwhite = piece.Piece(eval(data),'pieces_white.png') #接收客户端的下棋位置,画白棋
white_chesses.append(pwhite)
white_positions.append(pwhite.pointtrans())
chesses.append(pwhite)
is_player = True
# 判断输赢
if len(white_chesses)>=5 and not is_finish and checkwin(white_positions,pwhite.pointtrans()[0],pwhite.pointtrans()[1]) :
is_finish = True
white_win = True
# 电脑落子
if people2computer and not is_player:
pwhite = piece.Piece(computerdecision(),'pieces_white.png')
white_chesses.append(pwhite)
white_positions.append(pwhite.pointtrans())
chesses.append(pwhite)
chess_map[str(pwhite.pointtrans()[0]) + ',' + str(pwhite.pointtrans()[1])] = 1
is_player = True
piece_sound.play()
if len(white_chesses)>=5 and not is_finish and checkwin(white_positions,pwhite.pointtrans()[0],pwhite.pointtrans()[1]) :
is_finish = True
white_win = True
if black_win and is_finish and not is_againmsg and not is_reject:
screen.blit(zz_image, (0, 0)) #遮罩层
screen.blit(successtext, (successtext_rect.left, successtext_rect.top - 80))
screen.blit(playagaintext, successtext_rect)
screen.blit(menutext, (successtext_rect.left, successtext_rect.top + 80))
if white_win and is_finish and not is_againmsg and not is_reject:
screen.blit(zz_image, (0, 0)) #遮罩层
screen.blit(failuretext, (successtext_rect.left, successtext_rect.top - 80))
screen.blit(playagaintext, successtext_rect)
screen.blit(menutext, (successtext_rect.left, successtext_rect.top + 80))
if is_againmsg:
screen.blit(txtchallenge, txtchallenge_rect)
screen.blit(txtrecive, txtrecive_rect)
if is_reject:
screen.blit(txtclosed, txtclosed_rect)
screen.blit(menutext, (txtclosed_rect.left + 150, txtwatting_rect.top + 70))
if is_playagain:
init()
white_chesses.clear()
black_chesses.clear()
white_positions.clear()
black_positions.clear()
chesses.clear()
is_finish = False
black_win = False
white_win = False
is_playagain = False
pygame.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()
3.2 客户端main.py
# encoding:utf-8
import pygame
from pygame.locals import *
import sys
import os
from socket import *
import select
import piece
from tkinter import *
from params import Params
from utils import *
pygame.init()
pygame.mixer.init()
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
rows = int(Params.get('ROWS'))
blocksize = int(Params.get('blockSize'))
width = int(Params.get('WIDTH'))
height = int(Params.get('HEIGHT'))
# 棋盘
x = [] #x轴
y = [] #y轴
for i in range(0, rows): #棋盘的所有交叉点坐标(x,y)
x.append(28 + i * blocksize)
y.append(28 + i * blocksize)
# 记录棋盘每个坐标的属性,没有棋子为0,白棋为1,黑棋为2
chess_map = {} #结构是chess_map[28,28] = 0 ...
# 判断棋盘某位置上是否有棋子
def isempty(theposition):
global chess_map
existpiece = False
if chess_map[str(theposition[0]) + ',' + str(theposition[1])]:
existpiece = True
return existpiece
# 电脑选取落子的位置
def computerdecision():
value = max1 = max2 = 0
pos1 = pos2 = ()
# 进攻
for i in range(0, rows):
row = 28 + i * blocksize
for j in range(0, rows):
col = 28 + j * blocksize
pos = (row, col)
if isempty(pos):
continue
value = pointvalue(chess_map,pos, 1, 2)
if value > max1:
max1 = value
pos1 = (row, col)
# 防守
for i in range(0, rows):
for j in range(0, rows):
row = 28 + i * blocksize
col = 28 + j * blocksize
if isempty((row, col)):
continue
value = pointvalue(chess_map,(row, col), 2, 1)
if value > max2:
max2 = value
pos2 = (row, col)
if max1 > max2:
return pos1
else:
return pos2
# 初始化棋盘
def init():
global chess_map
for i in x:
for j in y:
chess_map[str(i) + ',' + str(j)] = 0 #清空
def main():
# TCP服务
BUFSIZE = 2048
tcpclientsocket = socket(AF_INET, SOCK_STREAM)
# 输入IP地址
def screenConnect():
top = Tk()
top.title('服务器IP')
top.geometry('%dx%d+%d+%d' % (300, 200, 418, 338))
HOST = ''
POST = 23338
nonlocal tcpclientsocket
def fun():
nonlocal HOST
nonlocal POST
nonlocal tcpclientsocket
HOST = txtIP.get()
HOSTADDR = (HOST, POST)
try:
tcpclientsocket.connect(HOSTADDR)
lbl_msg = Label(top, text='')
lbl_msg = Label(top, text='已连接')
lbl_msg.grid(row=2, column=1)
except error:
lbl_msg = Label(top, text='连接失败')
lbl_msg.grid(row=2, column=1)
lblIP = Label(top, text=' IP 地址:', padx=5, pady=30)
lblIP.grid(row=1, column=0)
txtIP = Entry(top)
txtIP.grid(row=1, column=1)
btnConn = Button(top, text='连接', padx=1, command=fun)
btnConn.grid(row=2, column=0)
mainloop()
game_bgsize = width, height
os.environ['SDL_VIDEO_CENTERED'] = '1'
screen = pygame.display.set_mode(game_bgsize)
pygame.display.set_caption('五子棋客户端')
bgimagepath = os.path.join(Params.get('resourcePath'), Params.get('imgFolder'), 'bg.png')
bg_image = pygame.image.load(bgimagepath).convert_alpha() # 背景图片加载
zzimagepath = os.path.join(Params.get('resourcePath'), Params.get('imgFolder'), 'zz.png') #遮罩图片
zz_image = pygame.image.load(zzimagepath).convert_alpha()
# 背景音乐
bgsoundpath = os.path.join(Params.get('resourcePath'), Params.get('soundFolder'), '齐豫 - 莲花处处开.mp3')
bg_sound = pygame.mixer.music.load(bgsoundpath) # 背景音乐加载
pygame.mixer.music.set_volume(0.08)
pygame.mixer.music.play(-1)
clicksoundpath = os.path.join(Params.get('resourcePath'), Params.get('soundFolder'), 'drop.wav')
piece_sound = pygame.mixer.Sound(clicksoundpath)
running = True
clock = pygame.time.Clock()
inputs = [tcpclientsocket]
# 棋子
white_chesses = [] #白棋子对象
black_chesses = [] #黑棋子对象
white_positions = [] #白棋子位置集合
black_positions = [] #黑棋子位置集合
chesses = [] #所有棋子集合,主要是显示用
is_player = True # 轮到哪方下棋
is_finish = False # 是否结束游戏
# 赢方
black_win = False
white_win = False
people2people = False # 人人对战,网络版
people2computer = False # 人与电脑对战
is_choise = False # 是否做出选择对战方式,是people2people 还是 people2computer , 通过菜单选择对战方式
is_play_sound = True # 是否播放声音
is_playagain = False # 是否再来一局
# 是否连接
is_link = False
# 对方是否发来重新开始的消息
is_againmsg = False
# 对面拒绝了重新开始
is_reject = False
# 字体
fontpath = os.path.join(Params.get('resourcePath'), Params.get('fontFolder'), 'simkai.ttf')
myfont = pygame.font.Font(fontpath, 38)
# 起始选项
txtplayerandplayer = myfont.render("玩家与玩家", True, WHITE)
txtplayerandplayer_rect = txtplayerandplayer.get_rect()
txtplayerandplayer_rect.left, txtplayerandplayer_rect.top = (game_bgsize[0] - txtplayerandplayer_rect.width) // 2, \
(game_bgsize[1] - txtplayerandplayer_rect.height) // 2 - 100
txtplayerandcomputer = myfont.render('玩家与电脑', True, WHITE)
txtplayerandcomputer_rect = txtplayerandcomputer.get_rect()
txtplayerandcomputer_rect.left, txtplayerandcomputer_rect.top = (game_bgsize[0] - txtplayerandplayer_rect.width) // 2, \
(game_bgsize[1] - txtplayerandplayer_rect.height) // 2
txtplaysound = myfont.render('音效: 开', True, WHITE)
txtplaysound_rect = txtplaysound.get_rect()
txtplaysound_rect.left, txtplaysound_rect.top = (game_bgsize[0] - txtplaysound_rect.width) // 2, \
(game_bgsize[1] - txtplaysound_rect.height) // 2 + 100
txtclosesound = myfont.render('音效: 关', True, WHITE)
txtclosesound_rect = txtclosesound.get_rect()
txtclosesound_rect.left, txtclosesound_rect.top = (game_bgsize[0] - txtclosesound_rect.width) // 2, \
(game_bgsize[1] - txtclosesound_rect.height) // 2 + 100
# 输赢
successtext = myfont.render("你有点屌哦!!!", True, WHITE)
successtext_rect = successtext.get_rect()
successtext_rect.left, successtext_rect.top = (game_bgsize[0] - successtext_rect.width) // 2, \
(game_bgsize[1] - successtext_rect.height) // 2
failuretext = myfont.render("小趴菜...", True, WHITE)
failuretext_rect = failuretext.get_rect()
failuretext_rect.left, failuretext_rect.top = (game_bgsize[0] - failuretext_rect.width) // 2, \
(game_bgsize[1] - failuretext_rect.height) // 2
playagaintext = myfont.render("再玩一局", True, WHITE)
menutext = myfont.render('主菜单', True, WHITE)
#连接
txtclosed = myfont.render("对方不愿和你玩并断开了连接", True, WHITE)
txtclosed_rect = txtclosed.get_rect()
txtclosed_rect.left, txtclosed_rect.top = (game_bgsize[0] - txtclosed_rect.width) // 2, \
(game_bgsize[1] - txtclosed_rect.height) // 2
txtchallenge = myfont.render('对方再次向你发起挑战', True, WHITE)
txtchallenge_rect = txtchallenge.get_rect()
txtchallenge_rect.left, txtchallenge_rect.top = (game_bgsize[0] - txtchallenge_rect.width) // 2, \
(game_bgsize[1] - txtchallenge_rect.height) // 2
txtrecive = myfont.render('接受挑战 返回主菜单', True, WHITE)
txtrecive_rect = txtrecive.get_rect()
txtrecive_rect.left, txtrecive_rect.top = (game_bgsize[0] - txtrecive_rect.width) // 2, \
(game_bgsize[1] - txtrecive_rect.height) // 2 + 100
# 初始化
init()
while running:
screen.blit(bg_image, (0, 0))
# 绘制游戏菜单
if not is_choise:
screen.blit(zz_image, (0, 0)) #遮罩层
screen.blit(txtplayerandplayer, txtplayerandplayer_rect)
screen.blit(txtplayerandcomputer, txtplayerandcomputer_rect)
if not is_play_sound:
screen.blit(txtclosesound, txtclosesound_rect)
else:
screen.blit(txtplaysound, txtplaysound_rect)
# 绘制棋盘
if is_choise:
if chesses:
for i in chesses:
screen.blit(i.image, i.image_rect())
for event in pygame.event.get():
if event.type == QUIT:
if people2people:
tcpclientsocket.close()
pygame.quit()
sys.exit()
if event.type == MOUSEBUTTONDOWN: #client下棋
if event.button == 1:
if is_finish :
if not is_againmsg and not is_reject:
pos = event.pos
if successtext_rect.left < pos[0] < successtext_rect.right - 50 and \
successtext_rect.top < pos[1] < successtext_rect.top + 30:
if people2people:
tcpclientsocket.send('again'.encode('utf8'))
if people2computer:
is_playagain = True
is_player = True
is_finish = False
init()
if successtext_rect.left < pos[0] < successtext_rect.right - 50 and \
successtext_rect.top + 50 < pos[1] < successtext_rect.top + 120:
people2people = False
if is_link:
is_link = False
tcpclientsocket.send('no'.encode('utf8'))
tcpclientsocket.close()
main()
if is_reject :
pos = event.pos
if txtclosed_rect.left + 150 < pos[0] < txtclosed_rect.left + 250 and \
txtclosed_rect.top + 70 < pos[1] < txtclosed_rect.top + 190:
main()
if is_againmsg :
pos = event.pos
if txtrecive_rect.left < pos[0] < txtrecive_rect.left + 150 and \
txtrecive_rect.top < pos[1] < txtrecive_rect.top + 120:
tcpclientsocket.send('yes'.encode('utf8'))
is_againmsg = False
is_playagain = True
is_player = True
is_finish = False
white_win = False
black_win = False
if txtrecive_rect.left + 330 < pos[0] < txtrecive_rect.left + 480 and \
txtrecive_rect.top < pos[1] < txtrecive_rect.top + 120:
tcpclientsocket.send('no'.encode('utf8'))
main()
if is_choise:
pos = event.pos
# 判断是否是client下棋时间
if is_player and not is_finish and not is_againmsg:
pwhite = piece.Piece(pos,'pieces_white.png')
if not isempty(pwhite.pointtrans()):
white_chesses.append(pwhite)
white_positions.append(pwhite.pointtrans())
chesses.append(pwhite)
chess_map[str(pwhite.pointtrans()[0]) + ',' + str(pwhite.pointtrans()[1])] = 1
if people2people:
tcpclientsocket.send(str(pos).encode('utf8'))
is_player = False
piece_sound.play()
if len(white_chesses)>=5 and not is_finish and checkwin(white_positions,pwhite.pointtrans()[0],pwhite.pointtrans()[1]) :
is_finish = True
white_win = True
else:
del (pwhite)
else:
pos = event.pos
if txtplayerandplayer_rect.left <= pos[0] <= txtplayerandplayer_rect.left + 170 and \
txtplayerandplayer_rect.top <= pos[1] <= txtplayerandplayer_rect.top + 30:
is_choise = True
people2people = True
screenConnect()
if txtplayerandplayer_rect.left <= pos[0] <= txtplayerandplayer_rect.left + 170 and \
txtplayerandplayer_rect.top + 100 <= pos[1] <= txtplayerandplayer_rect.top + 130:
is_choise = True
people2computer = True
if txtplayerandplayer_rect.left <= pos[0] <= txtplayerandplayer_rect.left + 160 and \
txtplayerandplayer_rect.top + 200 <= pos[1] <= txtplayerandplayer_rect.top + 230:
is_play_sound = not is_play_sound
if not is_play_sound:
pygame.mixer.stop()
pygame.mixer.music.stop()
else:
pygame.mixer.music.play()
# 电脑落子
if people2computer and not is_player:
pblack = piece.Piece(computerdecision(),'pieces_black.png')
black_chesses.append(pblack)
black_positions.append(pblack.pointtrans())
chesses.append(pblack)
chess_map[str(pblack.pointtrans()[0]) + ',' + str(pblack.pointtrans()[1])] = 2
is_player = True
piece_sound.play()
# 判断输赢
if len(black_chesses)>=5 and not is_finish and checkwin(black_positions,pblack.pointtrans()[0],pblack.pointtrans()[1]) :
is_finish = True
black_win = True
#网络消息,注释略,见gobang_server
if people2people:
readable, writable, exceptional = select.select(inputs, [], [], 0)
for readline in readable:
if readline is tcpclientsocket:
try:
data = readline.recv(BUFSIZE)
# print(data.decode('utf8'))
is_link = True
disconnected = not data
if data.decode('utf8') == 'again':
is_againmsg = True
if data.decode('utf8') == 'yes':
is_playagain = True
is_player = True
if data.decode('utf8') == 'no':
is_reject = True
is_link = False
if not is_player and not is_finish:
pblack = piece.Piece(eval(data),'pieces_black.png')
black_chesses.append(pblack)
black_positions.append(pblack.pointtrans())
chesses.append(pblack)
is_player = True
except error:
disconnected = True
is_link = False
# 判断输赢
if len(black_chesses)>=5 and not is_finish and checkwin(black_positions,pblack.pointtrans()[0],pblack.pointtrans()[1]) :
is_finish = True
black_win = True
if black_win and is_finish and not is_againmsg and not is_reject:
screen.blit(zz_image, (0, 0)) #遮罩层
screen.blit(failuretext, (successtext_rect.left, successtext_rect.top - 80))
screen.blit(playagaintext, successtext_rect)
screen.blit(menutext, (successtext_rect.left, successtext_rect.top + 80))
if white_win and is_finish and not is_againmsg and not is_reject:
screen.blit(zz_image, (0, 0)) #遮罩层
screen.blit(successtext, (successtext_rect.left, successtext_rect.top - 80))
screen.blit(playagaintext, successtext_rect)
screen.blit(menutext, (successtext_rect.left, successtext_rect.top + 80))
if is_againmsg:
screen.blit(txtchallenge, txtchallenge_rect)
screen.blit(txtrecive, txtrecive_rect)
if is_reject:
screen.blit(txtclosed, txtclosed_rect)
screen.blit(menutext, (txtclosed_rect.left + 150, txtclosed_rect.top + 70))
if is_playagain:
init()
white_chesses.clear()
black_chesses.clear()
white_positions.clear()
black_positions.clear()
chesses.clear()
is_finish = False
black_win = False
white_win = False
is_playagain = False
pygame.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()
3.3 先执行server的main.py,再执行client端的main.py
执行效果如下:
20240708_142557