程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C#網絡版斗地主——出牌權限的傳遞

C#網絡版斗地主——出牌權限的傳遞

編輯:關於C#

本文是對C#網絡版斗地主的開發總結。

出牌順序如上圖所示。

出牌權限可以用一個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, 0, 108);
  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, 0, 108);
  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, 5, 5);
    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, 0, 108);
  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, 5, 5);
   continue;
  }
  if (str.StartsWith("ServerPass"))//服務器pass後,在窗體中表示出來
  {
   DConsole.gPlayer2LeadPoker.Clear(DConsole.backColor);
   DConsole.gPlayer2LeadPoker.DrawString("不要", new System.Drawing.Font("宋體", 20), System.Drawing.Brushes.Red, 5, 5);
   continue;
  }
  if (str.StartsWith("NoBiggest")) //當自己的牌被別人打了後,別人會發送該消息給自己,這時設置自己的Isbiggest為false
  {
   DConsole.player1.isBiggest = false;
   continue;
  }
}

以上就是出牌權限傳遞的具體實現,這些代碼之間是相互關聯的,形成一個回路。除非有人的牌出完了,否則就會一直傳遞下去。代碼比較多,如果哪裡有錯誤的話歡迎留言反饋,謝謝!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved