游戏规则
交互式游戏设计(RemoteBet) (基于TCP)
通过在远端主机上搭建一个远程骰宝服务器,其它主机可以通过客户端程序RemoteBet与远程的骰宝服务器联系,进行交互式游戏设计。命令行格式如下:
RemoteBet <ServerIP>
如: RemoteBet 127.0.0.1
规则如下:
ya tc <数量> <coin|silver|gold> 押头彩(两数顺序及点数均正确) 一赔三十五
ya dc <数量> <coin|silver|gold> 押大彩(两数点数正确) 一赔十七
ya kp <数量> <coin|silver|gold> 押空盘(两数不同且均为偶数) 一赔五
ya qx <数量> <coin|silver|gold> 押七星(两数之和为七) 一赔五
ya dd <数量> <coin|silver|gold> 押单对(两数均为奇数) 一赔三
ya sx <数量> <coin|silver|gold> 押散星(两数之和为三、五、九、十一) 一赔二
每盘按从上到下的顺序只出现一种点型(头彩和大彩可同时出现),其他情况都算庄家赢。
庄家唱道:新开盘!预叫头彩!
庄家将两枚玉骰往银盘中一撒。
┌───┐ ┌───┐
│● ● │ │ │
│● ● │ │ ● │
│● ● │ │ │
└───┘ └───┘
庄家唱道:头彩骰号是六、一!
输入你压的值:
ya tc 10 gold
庄家将两枚玉骰扔进两个金盅,一手持一盅摇将起来。
庄家将左手的金盅倒扣在银盘上,玉骰滚了出来。
┌───┐
│● ●│
│ ● │
│● ●│
└───┘
庄家将右手的金盅倒扣在银盘上,玉骰滚了出来。
┌───┐
│ ● │
│ │
│ ● │
└───┘
庄家叫道:五、二……七星。
你赢了多少?or 你输了多少?
假设服务器的IP地址为127.0.0.1,客户端程序连接到服务器进行远程骰宝游戏,然后按照服务器发回的游戏规则和提示进行游戏。
程序设计思路
客户端:
- 用户运行程序后,客户端在CMD中输出程序的规则
- 当用户点击开始后,程序首先输出头彩(这个头彩由客户端输出,然后开始等待用户输入)
- 当用户输入自己想要的选择后,发送给服务器,服务器处理,然后将用户的信息存储起来(需要发送他的地址),对用户发出博彩信息,先是第一个(存储),然后第二个(存储),然后根据与用户发过来的信息进行对比,然后再次发送给用户结果
- 客户端界面显示结果
服务端:
- 处于不断接收用户传来的信息的状态
- 将用户发来的信息存储,然后进行处理(因为用户是使用空格分离,所以取出对应的信息)然后发送数字(1~6,让客户端对应数字输出对应的图案,这里一次发送两个数字避免出现问题)并存储这两个数字并与客户端进行对比
- 然后发送给客户端结果
应用层协议设计
1、 先使用TCP协议将客户端同服务端连接
2、 然后服务端在服务器中将客户信息记录下来
3、 然后客户端开始传输信息
4、 服务器接收信息并处理
5、 处理结束后反馈给客户端
所选用的Python库介绍
一共选了以下几个库:
1、 Socket:这个就是套接字库,进行通讯
2、 Threading:这个库的作用是在服务器进行多线程的时候使用的
3、 Json:这个库是为了在信息传输加密的时候使用的
4、 Random:这个库的作用是选取随机数
5、 Datetime:这个库的作用是输出当前的时间
测试流程
1、 首先是客户端的登入界面:
2、 然后用户输入自己的选择:
3、 然后用户界面会显示用户的结果
4、 如果用户选择退出的话:
5、 服务端的显示界面:
6、 程序支持多线程连入:
分析总结及心得
1、 我认识到了多线程的重要性和便携性,上次的UDP实验我记得当时只能一方面,如果当时用上了多线程的话,就可以同时进行了
2、 TCP相对于UDP来说方便多了,而且个人也感觉更容易实现
3、 而且这个对于实现远程服务器来说,难度不大,亲测
源代码
client.py:
# 这个为客户端代码,大部分功能是在客户端代码上实现的
import socket
import random
import json
# 配置基础信息
HOST = '127.0.0.1' # 服务器IP
PORT = 8022 # 服务器端口IP
BUFSIZE = 65535 # 缓冲区大小(1K)
ADDR = (HOST, PORT) # 这是一个双元组
# rule 这个函数的作用是向用户输出这个游戏的规则
def rule():
print("ya tc <数量> <coin|silver|gold> 押头彩(两数顺序及点数均正确) 一赔三十五\n"
"ya dc <数量> <coin|silver|gold> 押大彩(两数点数正确) 一赔十七\n"
"ya kp <数量> <coin|silver|gold> 押空盘(两数不同且均为偶数) 一赔五\n"
"ya qx <数量> <coin|silver|gold> 押七星(两数之和为七) 一赔五\n"
"ya dd <数量> <coin|silver|gold> 押单对(两数均为奇数) 一赔三\n"
"ya sx <数量> <coin|silver|gold> 押散星(两数之和为三、五、九、十一) 一赔二\n"
"每盘按从上到下的顺序只出现一种点型(头彩和大彩可同时出现),其他情况都算庄家赢\n")
# judge函数是用来根据服务发送过来的数字输出对应的图案
def judge(number):
if number == 1:
print(" ┌───────┐ \n"
" │ │ \n"
" │ ● │ \n"
" │ │ \n"
" └───────┘ \n")
elif number == 2:
print(" ┌───────┐ \n"
" │ │ \n"
" │ ● ●│ \n"
" │ │ \n"
" └───────┘ \n")
elif number == 3:
print(" ┌───────┐ \n"
" │ ● │ \n"
" │ ● │ \n"
" │ ●│ \n"
" └───────┘ \n")
elif number == 4:
print(" ┌───────┐ \n"
" │ ● ●│ \n"
" │ │ \n"
" │ ● ●│ \n"
" └───────┘ \n")
elif number == 5:
print(" ┌───────┐ \n"
" │ ● ●│ \n"
" │ ● │ \n"
" │ ● ●│ \n"
" └───────┘ \n")
elif number == 6:
print(" ┌───────┐ \n"
" │ ● ●│ \n"
" │ ● ●│ \n"
" │ ● ●│ \n"
" └───────┘ \n")
# result 这个函数的作用是判断服务发送过来的结果参数,然后输出对应的结果 1 表示胜利, 0 表示失败
def result(parameter, grade):
if parameter == 1:
print("Congratulation! You are Winner!")
print("You got the grade is {}".format(grade))
else:
print("Sorry!You lose the game...")
print("You lose the grade is {}".format(grade))
# theFirstPrice 这个头彩函数是用来在客户端输出两个随机数,减轻服务端的负担
def thefirstprice():
# 首先获得两个随机数
theFirstRandom = random.randint(1, 6)
theSecondRandom = random.randint(1, 6)
# 然后庄家开始预叫头彩
print("新开盘,预叫头彩!")
judge(theFirstRandom)
judge(theSecondRandom)
# encodeoperate 这个函数的作用是将消息加密和json化统一操作
def encodeoperate(msg):
msg = json.dumps(msg)
msg = msg.encode('utf-8')
return msg
# decodeoperate 这个函数的作用是将消息解码和json化统一操作
def decodeoperate(msg):
msg = msg.decode('utf-8')
msg = json.loads(msg)
return msg
# inputoperate 这个函数的作用是将用户的操作集中
def inputoperate():
# 开启一个无限循环如果用户想要一直玩的话
while True:
# 输入用户的押注
choice = input("Please input your choice!//If you want to quit Please input quit!\n")
# 判断是否要退出
if choice == "quit":
print("thank you for playing......")
break
# 对消息进行加密编码
data = encodeoperate(choice)
# 将消息发送给服务器
tcpCliSock.sendall(data)
# 然后等待服务的回应
information = tcpCliSock.recv(BUFSIZE)
msgFromSever = decodeoperate(information)
# 从服务器接收来的是一个含有四个元素的列表
# 然后客户端开始一个一个输出骰子
print("The first one is :")
judge(msgFromSever[0])
print("The second one is :")
judge(msgFromSever[1])
# 输出用户的结果
result(msgFromSever[2], msgFromSever[3])
if __name__ == '__main__':
# 下面这个是创建tcp连接
tcpCliSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpCliSock.connect(ADDR)
# 下面开始了程序部分
# 首先先向客户输出规则
rule()
# 利用input函数的中断,当用户明白规则后按回车继续
input("Please input Enter to continue!")
# 输出头彩
thefirstprice()
# 用户操作集合
inputoperate()
server.py:
# 这段代码表示服务器
import socket
import threading
import json
import random
import datetime
# 配置基础信息
HOST = '127.0.0.1' # 服务器IP
PORT = 8022 # 服务器端口IP
BUFSIZE = 65535 # 缓冲区大小(1K)
ADDR = (HOST, PORT) # 这是一个双元组
socketList = [] # 这里用存储
# encodeoperate 这个函数的作用是将消息加密和json化统一操作
def encodeoperate(msg):
msg = json.dumps(msg)
msg = msg.encode('utf-8')
return msg
# decodeoperate 这个函数的作用是将消息解码和json化统一操作
def decodeoperate(msg):
msg = msg.decode('utf-8')
msg = json.loads(msg)
return msg
# targetoperate 这个函数的作用不断接收来自客户端的消息并处理
def targetoperate(target, address):
try:
# 采用循环不断地从socket中读取客户端发送过来的数据
while True:
# 接收客户端的请求
content = readfromclient(target)
# 首先先随机两个随机数
theFirstRandom = random.randint(1, 6)
theSecondRandom = random.randint(1, 6)
# 然后对客户端的请求进行处理
data = solve(content, theFirstRandom, theSecondRandom, address)
# 对得到的data送至客户端
target.sendall(data)
except Exception:
print("The client has error")
return
# readfromclient 这个函数的作用是不断处于接受某个客户端的状态,如果客户端退出,就删除这个线程
def readfromclient(target):
try:
return decodeoperate(target.recv(BUFSIZE))
# 如果捕获到异常,则表明该socket对应的客户端已经关闭
except Exception:
# 删除该socket
target.close()
# solve 这个函数是对客户端发送过来的信息进行处理
def solve(content, first, second, address):
# 因为客户端发送过来的格式是以空格来分开的如:XX XX XX XX,将这个格式变成列表
content = content.split()
# 得到用户压的数量
count = content[2]
# 首先得到用户选择的类型
operate = content[1]
# 初始化一个result
result = 0
# 初始化当前的时间
now = datetime.datetime.now()
# 下面开始对用户的选择进行判断
if operate == 'tc':
# 下面这个表示中了头彩
if content[3] == first & content[4] == second:
result = 1
count = count * 35
if operate == 'dc':
if content[4] == first & content[4] == second:
result = 1
if content[4] == first & content[3] == second:
result = 1
count = count * 17
if operate == 'kp':
if first != second:
if (first + second) % 2 == 0:
result = 1
count = count * 5
if operate == 'qx':
if first + second == 7:
result = 1
count = count * 5
if operate == 'dd':
if first % 2 == 1:
if second % 2 == 1:
result = 1
count = count * 3
if operate == 'sx':
sumofrandom = first + second
if sumofrandom % 2 == 1:
result = 1
count = count * 2
if result == 1:
print("{} has win the game at {}.".format(address, now.strftime("%Y-%m-%d %H:%M:%S")))
else:
print("{} has lose the game at {}".format(address, now.strftime("%Y-%m-%d %H:%M:%S")))
# 将结果发送回客户端
return encodeoperate([first, second, result, count])
if __name__ == '__main__':
# 下面这个是创建tcp连接
tcpCliSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpCliSock.bind(ADDR)
tcpCliSock.listen(16)
# 服务开始运行
print("The sever is beginning")
while True:
# 此行代码会阻塞,将一直等待别人的连接
clientTarget, addr = tcpCliSock.accept()
socketList.append(clientTarget)
print("{} has connected".format(addr))
# 每当客户端连接后启动一个线程为该客户端服务
threading.Thread(target=targetoperate, args=(clientTarget, addr)).start()