zoukankan      html  css  js  c++  java
  • C#网络版斗地主——出牌权限的传递

    源码在上一篇文章:http://www.cnblogs.com/zhubenwuzui/archive/2009/06/06/1497673.html

    本文是对C#网络版斗地主的开发总结。

    系列文章:

    网络部分实现:http://www.cnblogs.com/zhubenwuzui/archive/2009/06/07/1497968.html

    地主权限的传递:http://www.cnblogs.com/zhubenwuzui/archive/2009/06/07/1498097.html

    出牌权限的传递:http://www.cnblogs.com/zhubenwuzui/archive/2009/06/08/1498369.html

    出牌顺序如上图所示。

    出牌权限可以用一个bool值表示

    Player类中,有一个属性:haveOrder表示玩家是否有权限出牌。

    还需要考虑到一点,当一个玩家出牌后,其他玩家都要不起(pass),该玩家不能自己“要不起”自己,所以还需要一个bool类型的属性“IsBiggest”。

    该属性表示自己出的牌最大。怎样保证该值的有效性呢?换句话说,最大的只能有一个。所以,每当自己出牌的时候,只要自己的牌比别人的牌大,就把该值设置为true。当该值为true时,向其他玩家发送信息表明自己的牌比你们的大,其他玩家收到信息后,把自己的IsBiggest属性设置为false;如此一来,就实现了出牌权限的正确传递。

    具体实现方法如下:

    本文需要Player类中的一些代码:

            private bool _haveOrder;
            
    public bool haveOrder
            {
                
    get
                {
                    
    return _haveOrder;
                }
                
    set
                {
                    _haveOrder 
    = value;
                }
            }
            
    private bool _isBiggest;
            
    public bool isBiggest //
            {
                
    get
                {
                    
    return _isBiggest;
                }
                
    set
                {
                    
    if (value)//给IsBiggest赋值true时
                    {
                        
    if (DConsole.client != null//当玩家为客户端时
                        {
                            DConsole.client.SendDataForServer(
    "IamIsBiggest");//服务器这边是怎么处理的呢?请看下文.
                            _isBiggest = value;
                        }
                        
    if (DConsole.server != null)//如果玩家为服务器
                        {
                            DConsole.server.SendDataForClient(
    "NoBiggest"1);
                            DConsole.server.SendDataForClient(
    "NoBiggest"2);//告诉客户端,你不是Biggest,客户端如何处理?请看下文
                            _isBiggest = value;
                        }
                    }
                    
    else
                    {
                        _isBiggest 
    = value;
                    }
                }
            }
            
    public bool lead()//出牌方法
            {
                DConsole.leadPokers 
    = leadPokers;
                
    this.leadPokers.Clear();
                
    foreach (int selectPoker in this.selectPokers)  //迭代循环把已选中的牌添加到leadPokers
                {
                    
    this.leadPokers.Add(this.pokers[selectPoker]);
                }
    //以上代码是将选中的牌构造成一个PokerGroup对象
                if (DConsole.IsRules(this.leadPokers))//验证选中的牌是否符合游戏规则,关于规则在以后的文章中详细讲解
                {
                    
    if (DConsole.player1.isBiggest || DConsole.leadPokers > DConsole.leadedPokerGroups[DConsole.leadedPokerGroups.Count-1]) //玩家能出牌的两种情况是1、自己上轮出的牌是最大的,别人都要不起。2、自己本轮出的牌比别人的大。
                    {
                        
    if (DConsole.leadPokers.type == PokerGroupType.炸弹)//当牌组的类型为炸弹时,翻倍
                        {
                            DConsole.multiple 
    *= 2;
                        }
                        
    if (DConsole.leadPokers.type == PokerGroupType.双王) //当牌组的类型为双王时,翻三倍
                        {
                            DConsole.multiple 
    *= 3;
                        }
                        DConsole.player1.isBiggest 
    = true;//只要自己的牌出出去了,就假设自己是最大的,一旦自己的牌被别人管上,就会被设置为false,具体请看下文
                        this.BakPoker();  //备份现有pokers,下次出牌时需要用到
                        foreach (int selectPoker in this.selectPokers)  //在pokers里移除已经出过的牌
                        {
                            
    this.pokers.Remove(this.bakPokers[selectPoker]);
                        }
                        
    this.selectPokers.Clear();  //清空已选牌
                        return true;
                    }
                    
    else
                    {
                        
    this.leadPokers.Clear();
                        
    return false//牌组比别人小就返回false
                    }
                }
                
    else
                {
                    
    this.leadPokers.Clear();
                    
    return false//不符合规则就返回false
                }
            }

    haveOrder(出牌权限)传递的具体实现:

    在服务器选择地主时,把出牌权限一并传给地主,所以出牌是由地主开始的。这里我先假设地主为服务器。

    服务器在叫地主后,出了本局第一组牌,下面看一下出牌按钮的处理程序:

            private void btnLead_Click(object sender, EventArgs e) //出牌按钮的事件处理程序
            {
                
    if (player1.lead())//尝试出牌,该方法的代码见上文,如果出牌成功,执行以下代码
                {
                    
    this.btnLead.Visible = false;
                    
    this.btnPass.Visible = false;//隐藏出牌和不要按钮
                    if (this.server != null//当玩家为服务器时
                    {
                        server.SendDataForClient(
    "SPokerCount" + Convert.ToString(this.player1.pokers.Count), 1); //发送自己牌的剩余张数给client1
                        Thread.Sleep(100);//延迟100毫秒
                        server.SendDataForClient("SPokerCount" + Convert.ToString(this.player1.pokers.Count), 2);发送自己牌的剩余张数给client2
                        Thread.Sleep(
    100);
                        server.SendDataForClient(
    "server", DConsole.leadPokers, 1);//发送自己出的牌组给client1
                        Thread.Sleep(100);
                        server.SendDataForClient(
    "server", DConsole.leadPokers, 2);//发送自己出的牌组给client2
                        Thread.Sleep(100);
                        
    if (this.player1.pokers.Count == 0 && DConsole.IsStart) //当server端牌的张数为0并且游戏已经开始时
                        {
                            DConsole.Winer 
    = 1//胜利者为1,即server,这里是计分系统,很简单,不赘述
                            DConsole.Restart();//重新开始游戏
                        }
                        
    else
                        {
                            server.SendDataForClient(
    "Order"2); //这里就是传递权限的关键代码,当server端出牌并且牌没有出完时,传递出牌权限给server端的下家,根据权限传递顺序,server-client2-clinet1,所以这里把出牌权限传递给client2
                        }
                        DConsole.player1.haveOrder 
    = false//自己的出牌权限已经消失
                        
                    }
                    
    if (this.client != null//当玩家为客户端时
                    {
                        client.SendDataForServer(
    "PokerCount" + Convert.ToString(this.player1.pokers.Count)); //发送客户端牌的剩余张数给服务器,服务器会处理并转发给另一个客户端
                        Thread.Sleep(500);
                        client.SendDataForServer(
    "client", DConsole.leadPokers);//发送客户端出牌牌组给服务器,服务接收到该消息后,就知道客户端1或者客户端2已出牌,如果该消息是客户端1发出的,根据权限传递顺序client2-clinet1-server,服务器会获得出牌权限,如果该消息是客户端2发出的,服务器会发送消息给客户端1使客户端1拥有出牌权限
                        Thread.Sleep(100);
                        
    this.player1.haveOrder = false//自己的出牌权限消失
                    }
                    player1.g.Clear(
    this.BackColor);
                    player1.Paint();
                    DConsole.PaintPlayer1LeadPoker();
                }
                
    else
                {
                    DConsole.Write(
    "[系统消息]:您出的牌不符合规则!");
                }
            }

    来看看server类中有关出牌权限传递的相关处理程序:

            /// <summary>
            
    /// 循环接收客户端1的请求数据
            
    /// </summary>
            public void AccpetClient1Data()
            {
                NetworkStream Ns1 
    = client1.GetStream();
                
    string str1 = "";
                
    while (true)
                {
                    PokerGroup pg 
    = new PokerGroup();
                    
    byte[] bytes1 = new byte[108];
                    Ns1.Read(bytes1, 
    0108);
                    str1 
    = Encoding.Default.GetString(bytes1);
    //(省略N行)
                    if (str1.StartsWith("client")) //收到客户端1的client消息,该消息表示客户端1出的牌
                    {
                        SendDataForClient(str1, 
    2);
                        Thread.Sleep(sleep);
                        str1 
    = str1.Replace("client""");
                        pg.GetPokerGroup(Encoding.Default.GetBytes(str1));
                        DConsole.leadedPokerGroups.Add(pg); 
    //这里在add之前会对该牌组进行验证和排序
                        DConsole.PaintPlayer2LeadPoker(pg);
                        DConsole.WriteLeadedPokers(); 
                        
    if (!DConsole.IsRestart)
                        {
                            DConsole.player1.haveOrder 
    = true;  //client1出牌后归server出牌,前提是没有Restart,Restart后出牌权限消失,根据权限传递顺序client2-clinet1-server,这里接收到的是client1的出牌,说明轮到server出牌了.
                        }
                        
    else
                        {
                            DConsole.IsRestart 
    = false;//当检测到已经Restart时,复位Restart使它还原为false
                        }
                        
    continue;
                    }
                    
    //Client放弃出牌,权限交给服务器
                    if (str1.StartsWith("Pass"))
                    {
                        DConsole.gPlayer2LeadPoker.Clear(DConsole.backColor);
                        DConsole.gPlayer2LeadPoker.DrawString(
    "不要"new System.Drawing.Font("宋体"20), System.Drawing.Brushes.Red,5,5);
                        DConsole.player1.haveOrder 
    = true;
                        SendDataForClient(
    "ClientPass"2); //告诉客户端2,客户端1pass了
                        continue;
                    }
                    
    if (str1.StartsWith("IamIsBiggest"))//客户端1说他的牌是最大的,所以要把自己的IsBiggest设置为false,因为最大的牌只能有一个
                    {
                        DConsole.player1.isBiggest 
    = false;
                        
    this.SendDataForClient("NoBiggest"2); //同时要转发给client2,让client2把自己的IsBiggest属性设置为false
                        continue;
                    }
    //(省略N行)
                }
            }
            
    /// <summary>
            
    /// 循环接收客户端2的请求数据
            
    /// </summary>
            public void AccpetClient2Data()
            {
                NetworkStream Ns2 
    = client2.GetStream();
                
    string str1 = "";
                
    while (true)
                {
                    PokerGroup pg 
    = new PokerGroup();
                    
    byte[] bytes2 = new byte[108];
                    Ns2.Read(bytes2, 
    0108);
                    str1 
    = Encoding.Default.GetString(bytes2);
    (省略N行)
                    
    if (str1.StartsWith("client"))//收到客户端2的client消息,该消息表示客户端2出的牌

                    {
                        SendDataForClient(str1, 
    1);
                        Thread.Sleep(sleep);
                        str1 
    = str1.Replace("client""");
                        pg.GetPokerGroup(Encoding.Default.GetBytes(str1));
                        DConsole.leadedPokerGroups.Add(pg);
    //这里在add之前会对该牌组进行验证和排序
                        DConsole.PaintPlayer3LeadPoker(pg);
                        DConsole.WriteLeadedPokers();
                        
    if (!DConsole.IsRestart)
                        {
                            SendDataForClient(
    "Order"1);  //client2出牌后归client1出牌,前提是没有Restart,Restart后出牌权限消失,根据权限传递顺序server-client2-clinet1,这里接收到的是client2的出牌,说明轮到clinet1出牌了.
                        }
                        
    else
                        {
                            DConsole.IsRestart 
    = false//当检测到已经Restart时,复位Restart使它还原为false供下次使用
                        }
                        System.Threading.Thread.Sleep(sleep);
                        
    continue;
                    }
                    
    //Client2放弃出牌,权限交给Client1
                    if (str1.StartsWith("Pass"))
                    {
                        DConsole.gPlayer3LeadPoker.Clear(DConsole.backColor);
                        DConsole.gPlayer3LeadPoker.DrawString(
    "不要"new System.Drawing.Font("宋体"20), System.Drawing.Brushes.Red, 55);
                        SendDataForClient(
    "ClientPass"1);//告诉客户端1,客户端2pass了
                        Thread.Sleep(500);
                        SendDataForClient(
    "Order"1);
                        
    continue;
                    }
                    
    if (str1.StartsWith("IamIsBiggest"))//客户端2说他的牌是最大的,所以要把自己的IsBiggest设置为false,因为最大的牌只能有一个
                    {
                        DConsole.player1.isBiggest 
    = false;
                        
    this.SendDataForClient("NoBiggest"1);//同时要转发给client21,让client1把自己的IsBiggest属性设置为false

                        
    continue;
                    }
    (省略N行)
                }
            }
    Client类中有关出牌权限传递的代码:
            
    public void AcceptServerData() 
            {
                NetworkStream Ns 
    = client.GetStream();
                
    string str = "";
                
    while (true)
                {
                    
    byte[] bytes = new byte[108];
                    Ns.Read(bytes, 
    0108);
                    str 
    = Encoding.Default.GetString(bytes);
                    
    if (str.StartsWith("Order")) //收到这条消息即表示自己有出牌权限了
                    {
                        DConsole.player1.haveOrder 
    = true;
                        
    continue;
                    }
                    
    if (str.StartsWith("ClientPass")) //另一个客户端pass后,在窗体中表示出来
                    {
                        DConsole.gPlayer3LeadPoker.Clear(DConsole.backColor);
                        DConsole.gPlayer3LeadPoker.DrawString(
    "不要"new System.Drawing.Font("宋体"20), System.Drawing.Brushes.Red, 55);
                        
    continue;
                    }
                    
    if (str.StartsWith("ServerPass"))//服务器pass后,在窗体中表示出来
                    {
                        DConsole.gPlayer2LeadPoker.Clear(DConsole.backColor);
                        DConsole.gPlayer2LeadPoker.DrawString(
    "不要"new System.Drawing.Font("宋体"20), System.Drawing.Brushes.Red, 55);
                        
    continue;
                    }
                    
    if (str.StartsWith("NoBiggest")) //当自己的牌被别人打了后,别人会发送该消息给自己,这时设置自己的Isbiggest为false
                    {
                        DConsole.player1.isBiggest 
    = false;
                        
    continue;
                    }
            }

    以上就是出牌权限传递的具体实现,这些代码之间是相互关联的,形成一个回路。除非有人的牌出完了,否则就会一直传递下去。代码比较多,如果哪里有错误的话欢迎留言反馈,谢谢!

  • 相关阅读:
    leetcode_268.missing number
    leetcode_41. First Missing Positive_cyclic swapping
    cyclic swapping algorithm
    leetcode_919. Complete Binary Tree Inserter_完全二叉树插入
    前端的图片隐写术
    C#读取串口数据实现无线手柄操作ROV
    通过android传感器控制ROV云台转动
    C#实现的简易多人聊天室
    ARM Cortex M3指令集
    ODbgscript 1.82.x Document
  • 原文地址:https://www.cnblogs.com/DreamCreator/p/1498369.html
Copyright © 2011-2022 走看看