C#网络版斗地主——地主权限的传递

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

首先服务器使用一个随机数来随即选出默认地主。然后发送信息给选出来的玩家。玩家接收到信息后显示两个按钮“叫地主”,“不叫”。如果选择不叫,则把可以叫地主的权限发送给另外一个玩家,如果另外两个玩家都不要的话,就执行Restart()方法重新发牌。

叫地主权限的传递顺序如下图所示:

具体实现方法:

服务器得到一个1-3的随机数,1代表服务器是默认地主(默认地主就是随机选择的第一个有权限叫地主的玩家),2代表client1是默认地主,3代表client2是默认地主。只有服务器端能够选择地主,所以该方法在server类中

        public void SendOrder(int Num)
        {
            
switch (Num)
            {
                
case 1:
                    DConsole.player1.areYouLandLord 
= true//把叫地主权限给自己
                    break;
                
case 2:
                    
this.SendDataForClient("AreYouLandLord"1);  //传递叫地主权限给client1
                    break;
                
case 3:
                    
this.SendDataForClient("AreYouLandLord"2); //传递叫地主权限给client2
                    break;
            }
        }

客户端的循环接收数据程序会分析服务端发送过来的数据,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("AreYouLandLord")) //如果服务器向客户端发送该消息,则客户端获取叫地主权限
                {
                    DConsole.player1.areYouLandLord 
= true//timer控件检测到该属性值为true时显示出叫地主和不叫按钮
                    continue;
                }
                
if (str.StartsWith("LandLordPokers")) //获取服务器发送给客户端的地主的3张牌,收到这三张牌后地主权限的传递就结束了
                {
                    PokerGroup pokers 
= new PokerGroup();
                    str 
= str.Replace("LandLordPokers""");
                    
byte[] bytePg = Encoding.Default.GetBytes(str);
                    pokers.GetPokerGroup(bytePg);
                    DConsole.LandLordPokers 
= pokers;//把接收到的地主牌保存起来
                    DConsole.player1.SelectLandLordEnd();//该方法在窗口中央显示出地主牌,然后判断自己是不是地主,如果是地主就将地主牌添加到自己的牌组.该方法的具体代码请看下文
                    continue;
                }
                
if (str.StartsWith("ClientIsLandLord")) //另外一个客户端是地主
                {
                    DConsole.lblClient2Name.Text 
+= "(地主)";
                    DConsole.lblClient2Name.ForeColor 
= System.Drawing.Color.Red;
                    DConsole.PaintClient(
20);
                    
continue;
                }
                
if (str.StartsWith("ServerIsLandLord")) //服务器是地主
                {
                    DConsole.lblClient1Name.Text 
+= "(地主)";
                    DConsole.lblClient1Name.ForeColor 
= System.Drawing.Color.Red;
                    DConsole.PaintServer(
20);
                    
continue;
                }
                (后面省略)
            }
        }

player1.areYouLandLordtrue,timer控件会检测到,然后把叫地主和不叫按钮显示出来。

叫地主按钮的click事件:

            this.player1.isLandLord = true//本地玩家为地主
            this.player1.haveOrder = true//获得出牌权限,下篇文章讲到出牌权限的传递
            this.player1.isBiggest = true//出的牌是否为最大的,主要用于当你出的牌其他两家都不要时,你自己不能不要,只能出牌,下篇文章会讲到的
            this.player1.areYouLandLord = false;//设置该值为false
            this.btnNeedLandLord.Visible = false
            
this.btnNotLandLord.Visible = false//隐藏叫地主和不叫按钮

            
if (this.server != null//当玩家为服务器时
            {
                
this.player1.SelectLandLordEnd();//该方法在窗口中央显示出地主牌,然后判断自己是不是地主,如果是地主就将地主牌添加到自己的牌组.该方法的具体代码请看下文
                this.server.SendDataForClient("LandLordPokers", DConsole.LandLordPokers, 1); //把地主的三张牌发送给client1,因为不管谁是地主,客户端都需要获得地主的牌并且显示出来
                Thread.Sleep(100);
                
this.server.SendDataForClient("LandLordPokers", DConsole.LandLordPokers, 2);//同上,把数据发送个client2
                Thread.Sleep(100);
                
this.server.SendDataForClient("ServerIsLandLord"1);//通知client1,服务器是地主
                Thread.Sleep(100);
                
this.server.SendDataForClient("ServerIsLandLord"2);//通知client2,服务器是地主
                Thread.Sleep(100);
            }
            
if (this.client != null//当玩家为客户端时
            {
                
this.client.SendDataForServer("IamLandLord"); //发送信息给服务器,服务器可以识别是哪个客户端叫了地主,服务器如何处理请看下文的server类代码
                Thread.Sleep(300);
            }

当玩家单击“不叫”按钮时。如果玩家是服务器,如第一张图所示,程序会向他的下家发送选择地主的权限,当LandLordNum3时,服务器就是最后一个玩家,如果他也不叫地主的话,就只能重新发牌了。

如果玩家是客户端的话,直接向server端发送"AreYouLandLord"来表明自己不要地主。

Server端会判断是client1还是client2发送的消息,然后做出不同的响应

下面是"不叫"按钮的click事件处理程序

Player类中,player1.SelectLandLordEnd的具体代码如下:

        public void SelectLandLordEnd()
        {
            DConsole.PaintLandLord(
true); //传递true给该方法,在窗口中央显示地主三张牌的具体点数
            if (this.isLandLord)  //如果自己是地主的话
            {
                
foreach (Poker poker in DConsole.LandLordPokers)  //把这三张牌添加到自己的牌组中
                {
                    
this.pokers.Add(poker);
                }
                
this.sort();  //重新排序
                this.Paint();  //重新显示自己的牌
            }
        }

地主的权限传递就这么多了,可能写的比较乱,但是并不复杂,相信大家仔细多看几遍应该能够明白的.。如果那里有错误的话欢迎在下面留言栏反馈。谢谢!

下面是server类里面的监听客户端消息的程序:

(由于篇幅所限,这里只贴出与地主权限传递有关的代码)

 

 

        public void AccpetClient1Data() //监听客户端1的消息
        {
            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);
(省略部分)
                
if (str1.StartsWith("AreYouLandLord"))
                {
                    
if (DConsole.LandLordNum == 1//如果默认地主为服务器,那么根据文章开头的权限传递顺序图,server-client2-client1,client1为最后一个玩家,所以需要和牌重新来过
                    {
                        DConsole.Restart();
                        
continue;
                    }
                    DConsole.player1.areYouLandLord 
= true//当默认地主不是服务器时,设置服务器的叫地主权限为true,当timer控件读取到该值时,服务器的叫地主和不叫按钮马上就会显示出来.
                    continue;
                }
                
if (str1.StartsWith("IamLandLord")) //客户端1为地主
                {
                    DConsole.lblClient1Name.Text 
+= "(地主)";
                    DConsole.lblClient1Name.ForeColor 
= System.Drawing.Color.Red;
                    SendDataForClient(
"ClientIsLandLord"2); //通知客户端2,客户端1为地主
                    Thread.Sleep(sleep);
                    DConsole.PaintClient(
201);
                    SendDataForClient(
"LandLordPokers", DConsole.LandLordPokers, 1); //地主已选出,把牌发送给所有玩家
                    Thread.Sleep(sleep);
                    SendDataForClient(
"LandLordPokers", DConsole.LandLordPokers, 2);//地主已选出,把牌发送给所有玩家
                    DConsole.player1.SelectLandLordEnd(); //该方法的具体代码请看下文
                    continue;
                }
            }
        }
        
/// <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);
(省略部分)
                
if (str1.StartsWith("AreYouLandLord")) //客户端2不要地主
                {
                    
if (DConsole.LandLordNum == 2//如果默认地主为客户端1,那么根据文章开头的权限传递顺序图,client1-server-client2,client2为最后一个玩家,所以需要和牌重新来过
                    {
                        DConsole.Restart();
                        
continue;
                    }
                    SendDataForClient(
"AreYouLandLord"1);  //如果默认地主不是客户端1的话,按照顺序把叫地主权限传递给client1,client1的处理程序上文已经列出
                    continue;
                }
                
if (str1.StartsWith("IamLandLord") ) //客户端2为地主
                {
                    DConsole.lblClient2Name.Text 
+= "(地主)";
                    DConsole.lblClient2Name.ForeColor 
= System.Drawing.Color.Red;
                    SendDataForClient(
"LandLordPokers", DConsole.LandLordPokers, 1);
                    SendDataForClient(
"LandLordPokers", DConsole.LandLordPokers, 2);
                    SendDataForClient(
"ClientIsLandLord"1);
                    DConsole.PaintClient(
202);
                    DConsole.player1.SelectLandLordEnd();
                    
continue;
                }
            }
        }

 

        private void btnNotLandLord_Click(object sender, EventArgs e)  
        {
            
this.player1.areYouLandLord = false;
            
this.player1.isLandLord = false;
            
this.btnNeedLandLord.Visible = false;
            
this.btnNotLandLord.Visible = false;
            
if (this.server != null)  //玩家是服务端
            {
                
if (DConsole.LandLordNum == 3) 如果client2是默认地主,根据权限传递顺序client2-client1-server,server为最后玩家,如果server不叫地主,只能和牌重来
                {
                    DConsole.Restart();
                    
return;
                }
                
this.server.SendDataForClient("AreYouLandLord"2);  //如果client2不是默认地主,就把权限传递给client2
            }
            
if (this.client != null//如果玩家是客户端
            {
                
this.client.SendDataForServer("AreYouLandLord");//告诉服务器自己不叫
            }
        }

 

原文地址:https://www.cnblogs.com/DreamCreator/p/1498097.html