设为首页 收藏本站
开启辅助访问 快捷导航
菜单
猿人部落 主页 资讯 查看内容

python棋牌游戏开发之斗地主

2019-8-1 05:12 发布者: 缘染荆行 评论 0 查看 1102
斗田主这个游戏的流程重要有,洗牌,发牌,出牌,而最告急的便是出牌了,出牌里包罗着游戏的牌型,以是这里就先给各

斗田主这个游戏的流程重要有,洗牌,发牌,出牌,而最告急的便是出牌了,出牌里包罗着游戏的牌型,以是这里就先给各人讲讲我举行牌型判断的思绪。

"""
牌型界说:1.单张
         2.对子
         3.三不带
         4.炸
         5.三带一
         6.连对
         7.顺子
         8.飞机不带
         9.飞机带单
         10.飞机带对子/三带二
         11.四带2
         12.四带一对
牌型判断条件:1.输入的列表为已经从上到下分列的列表
						  2.只针对一副牌的环境
						  3.一组列表大概代表着多种牌型,这里没有举行并行判断。
						  4.这里的列表用“0-13”分别对应扑克牌的“3-鬼”,这里临时不判巨细不区分巨细鬼
"""
class doudizhu:
    #单张
    def dan(self):
        return 1
    #对子
    def dui(self, l):
        if l[0] == l[1]:
            return 2
        else:
            return 99
    #三不带
    def san(self, l):
        if l[0] == l[2]:
            return 3
        else:
            return 99
    #炸弹
    def zha(self, l):
        if l[0] == l[3]:
            return 4
        else:
            return 0
    #三带一
    def sanyi(self, l):
        if l[0] == l[2] or l[1] == l[3]:
            return 5
        else:
            return 0
    #三带二(未用,与飞机2归并)
    def saner(self, l):
        if (l[0] == l[2] and l[3] == l[4]) or (l[2] == l[4] and l[0] == l[1]):
            return 6
        else:
            return 0
    #顺子(思绪:后一个数要比当前数1,有一个发生错误直接返回0)
    def shunzi(self,l):
        paixing = 0
        for i in range(len(l)-1):
            if l[i+1]-l[i] == 1:
                paixing = 7
            else:
                return 0
        return paixing
    #连对(思绪:先将长度对半折,同样要判断后2个数比当前数大1,且后一个数与当前数相称)
    def liandui(self,l):
        paixing = 0
        for i in range(int(len(l)/2)-1):
            if l[(i+1)*2]-l[i*2] == 1 and l[i*2] == l[i*2+1]:
                paixing = 6
            else:
                return 0
        return paixing
    #飞机0(思绪:每隔3个数后一个数都要比当前数大1,3个数内,后一个数要相即是当前数,未符合条件直接返回0)
    def feiji0(self,l):
        paixing = 0
        for i in range(len(l)-1):
            if (i+1)%3 == 0 and l[i+1] - l[i] == 1:
                paixing = 8
            elif l[i] == l[i+1]:
                paixing = 8
            else:
                return 0
        return paixing
    #飞机1(思绪:盘算3个数类似的组合有几组,再与其他未到达3个类似的总牌数比力,相称则准确)
    def feiji1(self, l):
        a = 1
        m = []
        for i in range(len(l)-1):
            if l[i] == l[i+1]:
                a += 1
            else:
                a = 1
            if a == 3:
                m.append(l[i])
                a = 1
        if len(l) - len(m) == len(m)*3:
            return 9
        else:
            return 0
    #飞机2(思绪:与飞机1类似,差别的是,此处的对子也须要统计,还须要思量特殊环境(用炸做对子))
    def feiji2(self, l):
        a = 1
        b = 0
        m = []
        for i in range(len(l)-1):
            if l[i] == l[i+1]:
                a += 1
            if a == 3:
                if l[i] != l[i+2]:
                    m.append(l[i])
                    a = 1
            elif a == 2:
                if l[i] != l[i+2]:
                    b += 1
                    a = 1
            elif a == 4:
                b += 2
            else:
                a = 1
        if b == len(m):
            return 10
        else:
            return 0
    #四带2(思绪,四带2就3种环境,我就不多说了)
    def sidaier1(self,l):
        if l[0] == l[3] or l[1] == l[4] or l[2] == l[5]:
            return 11
        else:
            return 0
    #四代两对(思绪:与四带二一样也就3种环境,就是条件还要多加对子判断)
    def sidaier2(self, l):
        if l[0] == l[3] and l[4] == l[5] and l[6] == l[7]:
            return 12
        if l[2] == l[5] and l[0] == l[1] and l[6] == l[7]:
            return 12
        if l[7] == l[4] and l[0] == l[1] and l[2] == l[3]:
            return 12
        return 0
    #这个函数重要就是,对牌型判断前的筛选工作,好比,一张牌就只能是单张,2张牌要先判断是不是王炸等等
    def paixing(self, l):
        m = len(l)
        paixing = 0
        if m == 1:
            paixing = self.dan()
        elif m == 2:
            #判断王炸
            if l[0] == 13:
                paixing = 4
            else:
                paixing = self.dui(l)
        elif m == 3:
            paixing = self.san(l)
        elif m == 4:
            #优先判断炸
            paixing = self.zha(l)
            #再三带一
            if paixing == 0:
                paixing = self.sanyi(l)
        elif m >= 5:
            # 这里的判断根本是并行的,条件是前面的判断没获取到范例
            #大于5张都判断一次顺子
            paixing = self.shunzi(l)
            if paixing == 0:
                #然后就是连对判断
                if m%2 == 0:
                    paixing = self.liandui(l)
            if paixing == 0:
                #飞机不带
                if m%3 == 0:
                    paixing = self.feiji0(l)
            if paixing == 0:
                #飞机带一
                if m%4 == 0:
                    paixing = self.feiji1(l)
            if paixing == 0:
                #飞机带对子
                if m % 5 == 0:
                    paixing = self.feiji2(l)
            if paixing == 0:
                #四带二
                if m == 6:
                    paixing = self.sidaier1(l)
            if paixing == 0:
                #四带一对
                if m == 8:
                    paixing = self.sidaier2(l)
        if paixing == 0:
            paixing = 99
        return paixing

    def chupai(self):
        l = [3,3,3,4,4,4,5,5,5,5]
        paixing = self.paixing(l)
        if paixing == 1:
            print("单张")
        elif paixing == 2:
            print("对子")
        elif paixing == 3:
            print("三不带")
        elif paixing == 4:
            print("炸")
        elif paixing == 5:
            print("三带一")
        elif paixing == 6:
            print("连对")
        elif paixing == 7:
            print("顺子")
        elif paixing == 8:
            print("飞机不带")
        elif paixing == 9:
            print("飞机带一")
        elif paixing == 10:
            if len(l) == 5:
                print("三带二")
            else:
                print("飞机带对子")
        elif paixing == 11:
            print("四带二")
        elif paixing == 12:
            print("四带两对")
        elif paixing == 99:
            print("牌型错误")
        else:
            pass
if __name__ == "__main__":
    dou = doudizhu()
    dou.chupai()

思绪根本都写在代码的解释里了,我想到的牌型根本都验证完毕了,假如有其他牌型却未出如今代码里的,大概你们有更优的想法或思绪,大概是我的代码里会有某些错误,都可以通过博客下面的留言跟我一起探究哦

7.15更新
前次只是根本判断牌型,这次更新弄了个笔墨版的斗田主,通讯协议用的是socket/tcp, 传送数据格式为JSON,这里将牌型判断同一放到服务器上弄,但是假如是为了高效通讯,发起将牌型判断转移到客户端上,我这里就不再转移了。话不多说,上代码。
一、斗田主常用流程模块
1.牌型判断

class doudizhu:
    #单张
    def dan(self):
        return 1

    #对子
    def dui(self, l, paixing):
        if l[0] == l[1]:
            paixing = 2
        return paixing, l[0]

    #三不带
    def san(self, l,paixing):
        if l[0] == l[2]:
            paixing = 3
        return paixing, l[0]

    #炸弹
    def zha(self, l,paixing):
        if l[0] == l[3]:
            paixing = 4
        return paixing, l[0]

    #三带一
    def sanyi(self, l, paixing):
        if l[0] == l[2] or l[1] == l[3]:
            paixing = 5
        return paixing, l[2]

    #三带二(未用,与飞机2归并)
    def saner(self, l, paixing):
        if (l[0] == l[2] and l[3] == l[4]) or (l[2] == l[4] and l[0] == l[1]):
            paixing = 6
        return paixing, l[2]

    #顺子(思绪:后一个数要比当前数大1,有一个发生错误直接返回0)
    def shunzi(self, l, paixing):
        now = 0
        print(l)
        if l[-1] < 12:
            for i in range(len(l)-1):
                if l[i+1]-l[i] == 1:
                    now = 7
                else:
                    return paixing, l[-1]
        paixing = now
        return paixing, l[-1]

    #连对(思绪:先将长度对半折,同样要判断后2个数比当前数大1,且后一个数与当前数相称)
    def liandui(self, l, paixing):
        now = 0
        print(l[-1])
        if l[-1] < 12:
            for i in range(int(len(l)/2)-1):
                if l[(i+1)*2]-l[i*2] == 1 and l[i*2] == l[i*2+1]:
                    now = 6
                else:
                    return paixing, l[-1]
        paixing = now
        return paixing, l[-1]

    #飞机0(思绪:每隔3个数后一个数都要比当前数大1,3个数内,后一个数要相即是当前数,未符合条件直接返回0)
    def feiji0(self, l, paixing):
        now = 0
        for i in range(len(l)-1):
            if (i+1)%3 == 0 and l[i+1] - l[i] == 1:
                now = 8
            elif l[i] == l[i+1]:
                now = 8
            else:
                return paixing, l[-1]
        paixing = now
        return paixing, l[-1]

    #飞机1(思绪:盘算3个数类似的组合有几组,再与其他未到达3个类似的总牌数比力,相称则准确)
    def feiji1(self, l, paixing):
        a = 1
        m = []
        for i in range(len(l)-1):
            if l[i] == l[i+1]:
                a += 1
            else:
                a = 1
            if a == 3:
                m.append(l[i])
                a = 1
        if len(m)*3 == len(l):#特殊环境(4个3张)
            if m[-1] - m[1] == len(m) - 2:
                paixing = 9
                a = m[-1]
            elif m[-2] - m[0] == len(m) - 2:
                paixing = 9
                a = m[-2]
        if len(m) != 0:#扫除无3个杂牌,制止后免的m[0],m[-1]堕落
            if len(l) - len(m) == len(m)*3 and m[-1] - m[0] == len(m) - 1:
                paixing = 9
                a = m[-1]
        return paixing, a

    #飞机2(思绪:与飞机1类似,差别的是,此处的对子也须要统计,还须要思量特殊环境(用炸做对子))
    def feiji2(self, l, paixing):
        a = 1
        b = 0
        m = []
        for i in range(len(l)-1):
            if l[i] == l[i+1]:
                a += 1
            if a == 3:
                if i+2 > len(l) or l[i] != l[i+2]:
                    m.append(l[i])
                    a = 1
            elif a == 2:
                if l[i] != l[i+2]:
                    b += 1
                    a = 1
            elif a == 4:
                b += 2
            else:
                a = 1
            if len(m) != 0:#环境同上
                if b == len(m) and m[-1] - m[0] == len(m) - 1:
                    paixing = 10
                    b = m[-1]
            else:
                b = l[-1]
        return paixing, b

    #四带2(思绪,四带2就3种环境,我就不多说了)
    def sidaier1(self, l, paixing):
        if l[0] == l[3] or l[1] == l[4] or l[2] == l[5]:
            paixing = 11
        return paixing, l[2]

    #四代两对(思绪:与四带二一样也就3种环境,就是条件还要多加对子判断)
    def sidaier2(self, l, paixing):
        m = 0
        if l[0] == l[3] and l[4] == l[5] and l[6] == l[7]:
            paixing = 11
            m = l[0]
            if l[4] == l[7]:
                m = l[4]
        elif l[2] == l[5] and l[0] == l[1] and l[6] == l[7]:
            paixing = 11
            m = l[2]
        elif l[7] == l[4] and l[0] == l[1] and l[2] == l[3]:
            paixing = 11
            m = l[4]
        return paixing, m
    def first(self, l):
        m = len(l)
        print("len m =",m)
        paixing = 0#牌型的中心变量
        n = []#用列表存牌型,用来应对多种牌型环境
        bf_max = []#用列表存比对值,用来应对多种牌型环境
        y = 0#判断同牌型的中心变量
        if m == 2:
            #判断王炸
            if l[0] == 13:
                print("wangzha")
                paixing = 4
                n.append(paixing)
                bf_max.append(13)
            else:
                paixing, y = self.dui(l, paixing)
                if paixing:
                    n.append(paixing)
                    paixing = 0
                    bf_max.append(y)
                    y = 0
        elif m == 3:
            paixing, y = self.san(l, paixing)
            if paixing:
                n.append(paixing)
                paixing = 0
                bf_max.append(y)
                y = 0
        elif m == 4:
            #优先判断炸
            print("zha")
            paixing, y = self.zha(l, paixing)
            if paixing:
                n.append(paixing)
                paixing = 0
                bf_max.append(y)
                y = 0
            #再三带一
            paixing, y = self.sanyi(l, paixing)
            if paixing:
                n.append(paixing)
                paixing = 0
                bf_max.append(y)
                y = 0
            paixing = 0
        elif m >= 5:
            #大于5张都判断一次顺子
            paixing, y = self.shunzi(l, paixing)
            paixing, y = self.saner(l, paixing)
            #然后就是连对判断
            if m%2 == 0:
                paixing, y = self.liandui(l, paixing)
                if paixing:
                    n.append(paixing)
                    paixing = 0
                    bf_max.append(y)
                    y = 0
            #飞机不带
            if m%3 == 0:
                paixing, y = self.feiji0(l, paixing)
                if paixing:
                    n.append(paixing)
                    paixing = 0
                    bf_max.append(y)
                    y = 0
            #飞机带一
            if m%4 == 0:
                paixing, y = self.feiji1(l, paixing)
                if paixing:
                    n.append(paixing)
                    paixing = 0
                    bf_max.append(y)
                    y = 0
            #飞机带对子
            if m % 5 == 0:
                paixing, y = self.feiji2(l, paixing)
                if paixing:
                    n.append(paixing)
                    paixing = 0
                    bf_max.append(y)
                    y = 0
                #四带二
            if m == 6:
                paixing, y = self.sidaier1(l, paixing)
                if paixing:
                    n.append(paixing)
                    paixing = 0
                    bf_max.append(y)
                    y = 0
                #四带两对
            if m == 8:
                paixing, y = self.sidaier2(l, paixing)
                if paixing:
                    n.append(paixing)
                    paixing = 0
                    bf_max.append(y)
                    y = 0
        return n, bf_max

这个部分跟前次的对比更新了一些判断方式,不但使得判断更加正确,而且适配了下面的出牌巨细比力,而first()函数更是险些包罗了全部的牌的判断,除了单张范例。
2、出牌比力

    def comp(self, bf_type, bf_max, bf_lenth,  l, socket):
        m = len(l)#当前出牌的长度
        x = 0#临时吸取客户端信息
        n = []#存放颠末转化分列的出牌
        #转化出牌,使得与之前的操持符合
        for i in l:
            n.append(int(i/4))
        n.sort()#分列,这里有个易错点,sort()函数没有返回值,不须要也不能用其他列表去复制它,直接调用便能将n分列好
        now_type = []#当前出牌牌型
        now_max = []#当前出牌值
        if m == 1:
            if l[0] < 52:#小鬼大鬼单独算
                now_type.append(1)
                now_max.append(n[0])
            else:
                now_type.append(1)
                now_max.append(l[0])
        else:
            now_type, now_max = self.first(n)
        if len(now_type) != 0:#假如长度为0,则代表没有牌型,也就是出牌错误
            if bf_type == 0:#未出牌,不须要与前次牌型比力
                if len(now_type) > 1:#多种牌型判断
                    data = {
                        'type': "select",
                        'paixing': now_type
                    }
                    socket.send(json.dumps(data).encode())#像客户端发起牌型判断哀求
                    x = socket.recv(1024)
                if now_type[x] != 0:#0为无牌型,扫除错误环境
                    return True, now_type[x], now_max[x], m
            else:
                j = 0#盘算公道有用牌型数目
                r = 0#存放第一个公道牌型
                for i in range(len(now_type)):
                    if now_type[i] == 4 and bf_type != 4:#如今出牌牌型为炸弹,前一刻不为炸弹
                        j += 1
                    elif now_type[i] == 4 and bf_type == 4 and now_max[i] > bf_max:
                        j += 1
                    elif now_type[i] == bf_type and now_max[i] > bf_max and m == bf_lenth:
                        j += 1
                    if j == 1:
                        r = i
                if j > 1:#多种牌型,哀求用户决议
                    data = {
                        'type': "select",
                        'paixing': now_type
                    }
                    socket.send(json.dumps(data).encode())
                    x = socket.recv(1024).decode()
                    if now_type[x] != 0:
                        return True, now_type[x], now_max[x], m
                elif j == 1:#一种牌型,直接返回
                    return True, now_type[r], now_max[r], m

        return False, bf_type, bf_max, bf_lenth

这里就是斗田主游戏过程中常常要做的事,将前次出牌与下次出牌举行比力。
3、模拟洗牌、发牌

    def beginer(self):#洗牌函数
        a = [x for x in range(54)]#初始化列表0-53
        random.shuffle(a)#随机打乱列表
        a1 = a[1::3]#切片取数
        a2 = a[2::3]
        a3 = a[3::3]
        a4 = a[-3:]#底牌
        del a1[-1]#删除多余数
        del a2[-1]#删除多余数
        return a1, a2, a3, a4

这部分就比力简单,用0-53代表扑克牌,用随机打乱列表的函数来模拟洗牌。
4、叫田主

    def jdz(self, client, i):#叫田主函数
        a = 0#叫田主次数统计
        b = 0#不叫次数统计
        now = ""#记载当前拥有田主权的玩家
        restart = False#重开标记
        z = random.randint(0, 2)#随机取数,优先叫田主
        n = z#复制此变量
        client_ls = client[i]#临时存放当前房间用户的名字
        while True:
            jdz = "叫田主"
            if a != 0:#模拟抢田主流程,有人叫田主之后便是抢田主
                jdz = "抢田主"
            if a == len(client_ls) and a > 1:#模拟先叫田主的人,有一次我抢的机会
                jdz = "我抢"
            #json格式传送信息
            data = json.dumps({
                "type": "jdz",
                "message": jdz
            })
            client[client_ls[n]].send(data.encode())
            recv = client[client_ls].recv(1024).decode()#吸取抢田主信息
            if recv == 0:
                print("wait for user %s" % client_ls[n])
            else:
                recv = json.loads(recv)
                if recv["message"] == "yes":#用户选择抢田主
                    a += 1
                    now = client[i][n]
                else:
                    b += 1
            data = json.dumps({
                "type": "warning",
                "message": client[i][n]+":"+jdz
            })
            #给其他用户发送抢田主信息
            client[client[i][(n + 1) % 3]].send(data.encode())
            client[client[i][(n + 2) % 3]].send(data.encode())
            #抢田主全部环境
            if a == 0 and b == 3:
                restart = True
                now = client[i][z]
                break
            elif a == 1 and b == 2:
                break
            elif a + b == 4:
                break
            if a == 0:#假如不抢
                del client_ls[n]#去除此人的抢田主机会
            if n > len(client_ls):#顺位改变
                n = n % len(client_ls)
            else:
                n = (n+1) % len(client_ls)
        return now, restart

这部分函数就是模拟寻常高兴斗田主的叫田主、抢田主流程。
二、服务器模块
1、监听用户毗连模块

def connect(s):
    while True:
        print('server socket waiting...')
        obj, addr = s.accept()  # 壅闭等候链接
        client[obj] = 1#开启用户通讯
        t1 = threading.Thread(target=user, args=(obj,))#独立线程处理处罚用户通讯
        t1.start()

简单的壅闭监听,多线程处理处罚,这里可以用线程池取代平凡线程去管理资源,我就不多先容了。
2、用户的平凡通讯

def user(socket):
    while True:
        if client[socket]:
            data = socket.recv(1024).decode()
            if data == 0:#非常断开
                break
            else:
                data = json.loads(data)#json解码
                if data["type"] == "login":#登录信息处理处罚
                    if data["name"] in client:
                        message = json.dumps({
                            "type": "warning",
                            "message": "昵称已存在,请重新输入"
                        })
                        socket.send(message.encode())#重复昵称判断
                    else:
                        client[data["name"]] = socket#字典存通讯地点与用户名
                        print("玩家到场:%s" % data["name"])#表现玩家到场
                elif data["type"] == "ready":#玩家预备才会进入游戏
                    for i in range(33):#遍历房间
                        if i == 32 and len(client[i]) == 3:#预设定房间是否满人判断
                            message = json.dumps({
                                "type": "warnning",
                                "message": "房间已满"
                            })
                            socket.send(message.encode())
                        if len(client[i]) < 3:#自动探求未满房间进入
                            client[i].append(data["name"])#i房间添加用户
                            message = json.dumps({
                                "type": "warning",
                                "message": "已到场房间%s" % i
                            })
                            socket.send(message.encode())
                            break
                    client[socket] = 0#关闭正常通讯
                #退出房间(未使用)
                elif data["type"] == "cancel":
                    i = 0
                    j = 0
                    for i in range(33):
                        for j in range(len(client[i])):
                            if client[i][j] == data["name"]:
                                break
                    message = json.dumps({
                        "type": "warning",
                        "message": "已退出房间%s" % i
                    })
                    socket.send(message.encode())
                    client[i][j].delect()
                    station[i] = 0
                #断开链接(未使用)
                elif data["type"] == "exit":
                    break
                #继承游戏(未使用)
                elif data["type"] == "continue":
                    client[socket] = 2
    socket.close()
#向其他玩家发送出牌的消息

这里就是用来与用户游戏前的通讯逻辑。
3、可复用函数

#向其他玩家发送出牌的消息
def message(l, client, now ,i):
    for j in range(3):
        data = json.dumps({
            "type": "chupai1",
            "name": now,
            "card": l
        })
        if client[i][j] != now:
            client[client[i][j]].send(data.encode())
#更新用户的牌与牌数
def fapai(usercard, client, i):
     for j in range(3):
         data = json.dumps({
             "type": "fapai",
             "player1": client[i][(j + 1) % 3] + ":" + str(len(usercard[client[i][(j + 1) % 3]])),
             "player2": client[i][(j + 2) % 3] + ":" + str(len(usercard[client[i][(j + 2) % 3]])),
             client[i][j]: usercard[client[i][j]]
         })
         client[client[i][j]].send(data.encode())
#删除已出的牌,以及是否竣事游戏判断
def up_card(usercard, now,l):
    i = 0
    j = 0
    for i in l:#遍历出牌的列表
        for j in range(len(usercard[now])):
            if usercard[now][j] == i:#找到类似的牌
                break
        del usercard[now][j]#删除此牌
        j = 0
    fapai(usercard, client, i)#更新用户的牌
    for i in usercard:#遍历用户的牌
        if len(usercard[i]) == 0:#是否有人已经出完牌了
            return True, i
    return False, i
#游戏模式

这里重要是将一些告急的逻辑单独隔离出来写。
4、游戏中的通讯

#游戏模式
def player(i, client):
    restart = True#不抢田主重开
    result = True#结果,用来停止循环
    count = 0#重开计数,模拟3次重开后不能再重开
    buchu = 0#不出计数,模拟其他两个不出后,可以随意出牌型
    now = ""#存放当前通讯玩家
    begin = 0#抢田主流程竣事标记
    usercard = {}#存放用户的牌
    dizhu_name = ""#本次游戏的田主
    nongming1 = ""#本次游戏的农夫1
    nongming2 = ""#本次游戏的农夫2
    doudizhu = chupai.doudizhu()#创建对象
    bf_type = 0#前次出牌范例
    bf_max = 0#前次出牌值
    bf_lenth = 0#前次出牌长度
    a = [[], [], [], []]#初始化a
    a[0], a[1], a[2], a[3] = doudizhu.beginer()#用a列表来存放底牌以及各用户的初始牌
    for j in range(3):
        usercard[client[i][j]] = a[j]#将牌存入usercard中
    fapai(usercard, client, i)#给用户发牌
    while result:
        if restart and count < 3:
            if count > 0:#重开
                for j in [0, 1, 2, 3]:
                    a[j].clear()
                a[0], a[1], a[2], a[3] = doudizhu.beginer()
                for j in range(3):
                    usercard[client[i][j]] = a[j]
                fapai(usercard, client, i)
            now, restart = doudizhu.jdz(client, i)#进入叫田主流程
            count += 1#计数
        else:
            if not begin:
                usercard[now] += a[3]#给田主加底牌
                dizhu_name = now#存田主名字
                fapai(usercard, client, i)
                for j in [0,1,2]:
                    if client[i][j] == now:#存农夫名字
                        nongming1 = client[i][int((j+1)/3)]
                        nongming2 = client[i][int((j + 2) / 3)]
                        break
                begin = 1#进入出牌流程
        if begin:
            data = json.dumps({
                "type": "chupai"
            })
            client[now].send(data.encode())
            recv = json.loads(client[now].recv(1024).decode())
            if recv["type"] == "chupai":#出牌标记
                l = recv["card"]#存放出牌的列表
                res, bf_type, bf_max, bf_lenth = doudizhu.comp(bf_type, bf_max, bf_lenth, l, client[now])#判断出牌是否错误
                if res:#准确牌型
                    buchu = 0
                    data = json.dumps({
                        "type": "chupai2"
                    })#关照出牌用户的打印出牌消息
                    client[now].send(data.encode())
                    message(l, client, now, i)#关照其他用户的打印出牌消息
                    res1, winner = up_card(usercard, now, l)#去牌和胜败判断
                    for j in [0, 1, 2]:
                        if res1:#胜败标记
                            data3 = []
                            if winner == dizhu_name:#赢家是田主
                                data3.append(json.dumps({
                                    "type": "win"
                                }))
                                data3.append((json.dumps({
                                    "type": "false"
                                })))
                            else:#赢家是农夫
                                data3.append(json.dumps({
                                    "type": "false"
                                }))
                                data3.append((json.dumps({
                                    "type": "win"
                                })))
                            client[dizhu_name].send(data3[0].encode())
                            client[nongming1].send(data3[1].encode())
                            client[nongming2].send(data3[1].encode())
                            result = not res1
                            break
                        else:
                            if client[i][j] == now:
                                now = client[i][(j + 1) % 3]
                                break
                else:
                    data = json.dumps({
                        "type": "error"
                    })
                    client[now].send(data.encode())
            elif recv["type"] == "buchu":
                buchu += 1#不出计数
                for j in [0, 1, 2]:
                    if client[i][j] == now:
                        now = client[i][(j + 1) % 3]
                        break
                if buchu == 2:#两个不出,第三个人可以随意
                    bf_type = 0
                    bf_lenth = 0
                    bf_max = 0
                    buchu = 0

这里的通讯重要用壅闭式的,单个房间的通光荣单个线程行止理,对于斗田主这个游戏来说是够的。假如你要多线程,发起先将通讯逻辑与算法逻辑完全隔离封装。
5、启动代码

if __name__ == "__main__":
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)#TCP/IP流
    HostPort = ('127.0.0.1', 6666)#ip与端口
    s.bind(HostPort)  # 绑定地点端口
    s.listen(99)  # 监听毗连数,凌驾次数会拒绝之后的用户

    client = {}#主字典,存放房间信息,登任命的名称与地点
    station = [0 for x in range(33)]#存放房间状态,0代表等候,1代表游戏中
    for i in range(33):
        client[i] = []
    t = threading.Thread(target=connect, args=(s,))#线程开启处理处罚毗连
    t.start()
    while True:
        for i in range(33):
            if station[i] == 1 and client[i][0] == 2 and client[i][1] == 2 and client[i][2] == 2:#暂无用处,预设定
                station[i] = 0
            if len(client[i]) == 3 and station[i] == 0:#房间状态判断
                t2 = threading.Thread(target=player, args=(i, client))#开线程处理处罚游戏
                t2.start()
                print("房间%s启动" % i)
                station[i] = 1

这里包罗了房间的预创建,房间状态的管理等,是服务器的启动代码。
三、客户端

#吸取信息处理处罚函数
def recv(s, d):
    l = []
    name = input("请输入用户名:")#输名字,用于存储地点和辨认
    data2 = json.dumps({
        "type": "login",
        "name": name
    })
    s.send(data2.encode())
    inp = input("开始匹配:")#预设定,可改为可选房间(如今无用)
    data2 = json.dumps({
        "type": "ready",
        "name": name
    })
    s.send(data2.encode())
    while True:
        rec = s.recv(1024).decode()
        if rec == 0:
            break
        else:
            rec = json.loads(rec)
            if rec["type"] == "fapai":#表现自己的牌与其他玩家的牌数
                card = ""
                rec[name].sort()#对牌排序,使得表现的时间更加雅观
                for i in rec[name]:#用空格拼接牌
                    card = card + d[i] + " "
                sys.stdout.write("{}\n{}\n我:{}\n".format(rec["player1"], rec["player2"], card))#表现排序,可用print()取代
                sys.stdout.flush()
            elif rec["type"] == "warning":#服务器关照用户表现关照
                sys.stdout.write("{}\n".format(rec["message"]))#表现关照
                sys.stdout.flush()
            elif rec["type"] == "chupai":#服务器关照用户出牌
                l.clear()#预清空
                data = {
                    "type":"chupai",
                    "card": l
                }
                while True:
                    try:#用try防止使步伐竣事
                        inp = input("请出牌:")
                        if inp == "buchu":
                            data["type"] = "buchu"
                        else:
                            inp = inp.split()#规定每张牌以空格隔开
                            for i in inp:
                                l.append(d[i])
                        data["card"] = l
                        break
                    except KeyError:
                        print("输入错误,请查抄")#堕落关照
                data1 = json.dumps(data)
                s.send(data1.encode())
            elif rec["type"] == "chupai1":#打印别的用户出的牌,这里可以改的更高大上,表现牌时同时表现其牌型
                card = ""
                rec["card"].sort()#排序
                for i in rec["card"]:
                    card = d[i] + ""
                sys.stdout.write("{}出牌:{}\n".format(rec["name"], card))
                sys.stdout.flush()
            elif rec["type"] == "chupai2":#表现自己出的牌
                card = ""
                for i in l:
                    card = d[i] + ""
                sys.stdout.write("我出牌:{}\n".format(card))
                sys.stdout.flush()
            elif rec["type"] == "win":#表现胜利信息
                sys.stdout.write("I'm win")
                sys.stdout.flush()
            elif rec["type"] == "false":#表现失败信息
                sys.stdout.write("You are false")
                sys.stdout.flush()
            elif rec["type"] == "error":#表现出牌错误信息
                l.clear()
                sys.stdout.write("牌型错误,请重新出牌")
                sys.stdout.flush()
            elif rec["type"] == "jdz":#叫田主流程
                s1 = "不叫"
                if not rec["message"] == "叫田主":
                    s1 = "不抢"
                sys.stdout.write("1.{} 2.{}\n".format(rec["message"], s1))
                sys.stdout.flush()
                inp = input("请输入:")
                data = {
                    "type": "jdz",
                    "message": "no"
                }
                try:#与上面的try用处同等
                    inp = int(inp)
                    if inp == 1:
                        data["message"] = "yes"
                except:
                    pass
                data = json.dumps(data)
                s.send(data.encode())
            elif rec["type"] == "select":#表现多牌型选择
                data1 = 0
                while True:
                    try:
                        inp = int(input("请输入0-%s:%s:" % (len(rec["paixing"]), rec["paixing"])))
                        data1 = rec["paixing"][inp]
                        data1 = inp
                        break
                    except:
                        print("输入错误")
                s.send(data1)


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
HostPort = ('127.0.0.1', 6666)
s.connect(HostPort)#毗连
d = show()
recv(s, d)

由于游戏中的通讯是壅闭模式,以是客户端我也只用单线程行止理就可以了,用这套代码应该能跑完一次完备的游戏,固然具体是否能跑完我还没测试完过,另有代码要是含有什么错误大概罅漏渴望你们能留言告诉我哦,互换互换,共同进步。
下面放组结果图:
在这里插入图片形貌
登录环境
抢田主竣事j叫田主流程



路过

雷人

握手

鲜花

鸡蛋
收藏 邀请
上一篇:棋牌游戏开发质量缘何陷入低水平状态下一篇:Unity3D游戏开发笔记-2【优化】

相关阅读

一周热门

头条攻略!

日排行榜

相关分类