棋牌聊天室

'''server'''
import socket
import numpy as np
from threading import Thread, Lock
import random
import json
import pickle

sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind(('10.181.22.132', 6000))

'''
=================================================
0,数据库
=================================================
'''
'''记录有多少人登录'''
clientDict = {} #ipTuple: strName

'''记录一个桌子有几个人,凑够三个人开始玩'''
table = []  #[player, player, player]

'''玩家类'''
class player():
    def __init__(self, name, card, landloard=False):
        self.name = name    #ipTuple
        self.card = card
        self.landloard = landloard

'''记录上一次出的牌'''
lastCard = -1

'''所有的牌面'''
totalCard = [f'{i}' for i in list(range(1, 11))+['J', 'Q', 'K'] for j in range(4)]
totalCard += ['小王', '大王']

'''牌的大小'''
cardValue = {key: value for key, value in zip([f'{i}' for i in range(1, 11)], range(1, 11))}
cardValue['J'] = 11
cardValue['Q'] = 12
cardValue['K'] = 13
cardValue['小王'] = 14
cardValue['大王'] = 15

'''
=================================================
1,人齐以后开始游戏
=================================================
'''
def playGame():
    global table
    global lastCard

    '''
    ---------------------------
    1-0,游戏开始
    ---------------------------
    '''
    for client in clientDict:
        sk.sendto(f'\033[34m人数以齐,游戏开始!\033[0m'.encode('utf-8'), client)

    '''
    ---------------------------
    1-1,分配地主
    ---------------------------
    '''
    landlordIndex = np.random.randint(0, 3, 1)
    print(landlordIndex)
    print(table[int(landlordIndex)])
    for client in clientDict:
        sk.sendto(f'\033[34m{clientDict[table[int(landlordIndex)].name]}是地主\033[0m'.encode('utf-8'), client)
    table[int(landlordIndex)].landloard = True

    '''
    ---------------------------
    1-2,发牌
    ---------------------------
    '''
    #将牌分为三份
    middleMemoryCard = totalCard
    card1 = sorted([middleMemoryCard[i] for i in np.random.choice(range(54), 17, replace=False)], key=lambda x: cardValue[x])
    for card in card1:
        middleMemoryCard.remove(card)
    card2 = sorted([middleMemoryCard[i] for i in np.random.choice(range(37), 17, replace=False)], key=lambda x: cardValue[x])
    farmersCard = [card1, card2]
    for card in card2:
        middleMemoryCard.remove(card)
    card3 = sorted(middleMemoryCard, key=lambda x: cardValue[x])
    # 发牌并显示牌
    for i in range(3):
        if table[i].landloard == True:
            table[i].card = card3
            sk.sendto(f'\033[35m你的牌是{str(card3)}\033[0m'.encode('utf-8'), table[i].name)
        else:
            table[i].card = farmersCard[-1]
            sk.sendto(f'\033[35m你的牌是{str(farmersCard[-1])}\033[0m'.encode('utf-8'), table[i].name)
            farmersCard.pop()

    '''
    ---------------------------
    1-3,出牌/说话
    ---------------------------
    '''
    overOrNot = False   #游戏结束标志
    JudgmentBit = False
    farmersOrder = list(range(3))
    farmersOrder.remove(landlordIndex)
    playerCardOrder = [int(landlordIndex)] + farmersOrder    #总的出牌顺序
    passNum = 0 #pass个数
    while True:
        '''1-3-1,一直循环,只到有人出完牌'''
        for i in playerCardOrder:
            passOrNot = False  # 出牌位,换人时一旦出牌passNum就要归零
            '''1-3-2,顺序出牌'''
            while True:
                for client in clientDict:
                    sk.sendto(f'\033[34m轮到{clientDict[table[i].name]}出牌,出牌时请以英文“,”隔开,无牌可出请输入pass\033[0m'.encode('utf-8'), client)

                cardMsg = sk.recvfrom(1024)
                middleMsg = pickle.loads(cardMsg[0])

                '''1-3-2-1,非出牌人说话'''
                if cardMsg[1] != table[i].name:
                    for client in clientDict:
                        if client != cardMsg[1]:
                            sk.sendto(f'{clientDict[cardMsg[1]]}说: {middleMsg}'.encode('utf-8'), client)

                '''1-3-2-2,出牌人无牌可出\出牌错误\所出的牌没有\压不上\出牌成功'''
                if cardMsg[1] == table[i].name:
                    '''1-3-2-2-1,出牌人无牌可出'''
                    if middleMsg[0] == 'pass':
                        passOrNot = True
                        passNum += 1
                        for client in clientDict:
                            sk.sendto(f'\033[36m{clientDict[cardMsg[1]]}竟然跳过了,实在太菜了!!!\033[0m'.encode('utf-8'), client)
                        break

                    elif len(middleMsg) > 2:
                        '''1-3-2-2-1.1,出牌错误,出的超过两张不允许'''
                        for client in clientDict:
                            if client != cardMsg[1]:
                                sk.sendto(f'{clientDict[cardMsg[1]]}说: {middleMsg}'.encode('utf-8'), client)
                            else:
                                sk.sendto(f'\033[36m只允许出单张或者对子\033[0m'.encode('utf-8'), client)

                    elif (lastCard != -1) and (len(lastCard) != len(middleMsg)):
                        '''1-3-2-2-1.2,出牌错误,出牌与上一玩家的数目不一致'''
                        for client in clientDict:
                            if client != cardMsg[1]:
                                sk.sendto(f'{clientDict[cardMsg[1]]}说: {middleMsg}'.encode('utf-8'), client)
                            else:
                                sk.sendto(f'\033[36m出牌需与上一玩家的数目保持一致!!!\033[0m'.encode('utf-8'), client)

                    else:
                        '''1-3-2-2-2,所出的牌没有:检查所出的牌是否都有,如果没有则出牌错误,认为是在说话'''
                        for card in middleMsg:
                            if card not in table[i].card:
                                JudgmentBit = True
                                for client in clientDict:
                                    if client != cardMsg[1]:
                                        sk.sendto(f'{clientDict[cardMsg[1]]}说: {middleMsg}'.encode('utf-8'), client)
                                    else:
                                        sk.sendto(f'\033[36m不要出自己没有的牌!!!\033[0m'.encode('utf-8'), client)
                            break

                        if JudgmentBit:
                            JudgmentBit = False
                            continue

                        if len(middleMsg) == 2:
                            '''1-3-2-2-1.1,出牌错误,出的两张不同不允许'''
                            if middleMsg[0] != middleMsg[1]:
                                for client in clientDict:
                                    if client != cardMsg[1]:
                                        sk.sendto(f'{clientDict[cardMsg[1]]}说: {middleMsg}'.encode('utf-8'), client)
                                    else:
                                        sk.sendto(f'\033[36m对子必须是相同的牌!!!\033[0m'.encode('utf-8'), client)
                                continue

                        '''1-3-2-2-3,所出的牌都有,判断是否可以压上'''
                        if lastCard == -1:
                            '''1-3-2-2-3.1,出牌成功,第一个出牌,总是能压上'''
                            lastCard = middleMsg
                            for card in middleMsg:
                                '''移除牌'''
                                table[i].card.remove(card)
                            for client in clientDict:
                                if client != cardMsg[1]:
                                    sk.sendto(f'\033[31m{clientDict[cardMsg[1]]}出牌: {middleMsg}\033[0m'.encode('utf-8'), client)
                                else:
                                    sk.sendto(f'出牌成功!现在的牌是\033[35m{table[i].card}\033[0m'.encode('utf-8'), client)
                            break

                        elif lastCard[0] >= middleMsg[0]:
                            '''1-3-2-2-3.2,出的牌压不上,重新出牌'''
                            for client in clientDict:
                                if client != cardMsg[1]:
                                    sk.sendto(f'{clientDict[cardMsg[1]]}说: {middleMsg}'.encode('utf-8'), client)
                                else:
                                    sk.sendto(f'\033[36m出的牌太小了!!!\033[0m'.encode('utf-8'), client)
                            continue

                        else:
                            '''1-3-2-2-3.2,出牌成功,出的牌可以压上'''
                            lastCard = middleMsg
                            for card in middleMsg:
                                '''移除牌'''
                                table[i].card.remove(card)
                            for client in clientDict:
                                if client != cardMsg[1]:
                                    sk.sendto(f'\033[31m{clientDict[cardMsg[1]]}出牌: {middleMsg}\033[0m'.encode('utf-8'), client)
                                else:
                                    sk.sendto(f'出牌成功!现在的牌是\033[35m{table[i].card}\033[0m'.encode('utf-8'), client)
                            break

            '''一旦有人出牌,passNum置零'''
            if not passOrNot:
                passNum = 0
            '''如果连续两个人跳过,重置lastCard'''
            if passNum == 2:
                lastCard = -1

            '''1-3-3,如果有人出完了,游戏结束'''
            if len(card3) == 0:
                for client in clientDict:
                    sk.sendto(f'\033[34m**********************************地主获胜**********************************\033[0m'.encode('utf-8'), client)
                overOrNot = True
                break

            elif len(card1) == 0 or len(card2) == 0:
                for client in clientDict:
                    sk.sendto(f'\033[34m**********************************农民获胜**********************************\033[0m'.encode('utf-8'), client)
                overOrNot = True
                break

        if overOrNot:
            break

    '''
    ---------------------------
    1-4,初始化
    ---------------------------
    '''
    table = []


'''主程序'''
if __name__ == '__main__':
    while True:
        msg = sk.recvfrom(1024)

        '''
        =================================================
        2,玩家登录、发送消息、申请玩游戏
        =================================================
        '''
        if msg[1] not in clientDict:
            '''2-1-1:登录'''
            print(msg[1], pickle.loads(msg[0]))
            clientDict[msg[1]] = pickle.loads(msg[0])
            print(clientDict)
            for client in clientDict:
                sk.sendto(f'\033[31m欢迎{clientDict[msg[1]]}接入棋牌聊天室,当前版本1.1,只允许出单张和对子,想要玩牌请输入p/P\033[0m'.encode('utf-8'), client)

        else:
            '''2-1-2:退出'''
            msgRec = pickle.loads(msg[0])
            if msgRec[0].upper() == 'QUTI':
                print(f'\033[32m{msg[1]}退出棋牌聊天室\033[0m')
                quitter = clientDict[msg[1]]
                clientDict.pop(msg[1])
                print(clientDict)
                for client in clientDict:
                    sk.sendto(f'\033[32m{quitter}退出棋牌聊天室\033[0m'.encode('utf-8'), client)

            elif msgRec[0].upper() == 'P':
                '''2-1-3:申请游戏,初始化玩家'''
                if len(table) < 3:
                    print(f'\033[33m{msg[1]}申请参战\033[0m')
                    table.append(player(msg[1], []))
                    print(f'-->{table[-1].name}')
                    for client in clientDict:
                        sk.sendto(f'\033[33m{clientDict[msg[1]]}申请参战,还差{3-len(table)}人\033[0m'.encode('utf-8'), client)
                else:
                    for client in clientDict:
                        sk.sendto(f'\033[33m{clientDict[msg[1]]}申请参战,但很可惜人数满了。。。\033[0m'.encode('utf-8'), client)

            else:
                '''2-1-4:发送消息'''
                for client in clientDict:
                    if client != msg[1]:
                        sk.sendto(f'{clientDict[msg[1]]}说: {pickle.loads(msg[0])}'.encode('utf-8'), client)

        '''
        ---------------------------
        2-2,开始游戏
        ---------------------------
        '''
        if len(table) == 3:
            playGame()
'''client'''
import socket
from threading import Thread
import pickle

sk = socket.socket(type=socket.SOCK_DGRAM)
server = ('10.181.22.132', 6000)

def receiveMessage(sk):
    '''接收消息'''
    while True:
        msg = sk.recvfrom(1024)
        print(msg[0].decode('utf-8'))

def sendMessage(sk):
    '''发消息,轮到出牌的时候出牌'''
    while True:
        msg = list(input('>>>').split(','))
        sk.sendto(pickle.dumps(msg), server)
        if msg[0].upper() == 'P':
            print('申请参战!')
        if msg[0].upper() == 'QUTI':
            print('退出棋牌室,再见!')
            break

if __name__ == '__main__':
    name = input('请输入您的名字:')
    sk.sendto(pickle.dumps(name), server)
    th1 = Thread(target=receiveMessage, args=(sk, ))
    th2 = Thread(target=sendMessage, args=(sk,))
    th1.start()
    th2.start()
上一篇:对TCP的三次握手和系统调用深度解析


下一篇:关于TCAX论坛内tcaxPy_Main存在的两种参数命名习惯