python利用C/S實現簡單的小遊戲

遊戲規則

交互式遊戲設計(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,客戶端程序連接到服務器進行遠程骰寶遊戲,然後按照服務器發回的遊戲規則和提示進行遊戲。

程序設計思路

客戶端:

  1. 用戶運行程序後,客戶端在CMD中輸出程序的規則
  2. 當用戶點擊開始後,程序首先輸出頭彩(這個頭彩由客戶端輸出,然後開始等待用戶輸入)
  3. 當用戶輸入自己想要的選擇後,發送給服務器,服務器處理,然後將用戶的信息存儲起來(需要發送他的地址),對用戶發出博彩信息,先是第一個(存儲),然後第二個(存儲),然後根據與用戶發過來的信息進行對比,然後再次發送給用戶結果
  4. 客戶端界面顯示結果

服務端:

  1. 處於不斷接收用戶傳來的信息的狀態
  2. 將用戶發來的信息存儲,然後進行處理(因爲用戶是使用空格分離,所以取出對應的信息)然後發送數字(1~6,讓客戶端對應數字輸出對應的圖案,這裏一次發送兩個數字避免出現問題)並存儲這兩個數字並與客戶端進行對比
  3. 然後發送給客戶端結果

應用層協議設計

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()
發佈了41 篇原創文章 · 獲贊 7 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章