源码在上一篇文章: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
大家知道,斗地主这个游戏是将一些特有的牌组合成牌组然后来比较牌组的大小,那么,就应该给PokerGroup类定义一个属性type,即牌组的类型,type的值是一个枚举类型
1 public enum PokerGroupType
2 {
3 单张 = 1,
4 对子 = 2,
5 双王 = 3,
6 三张相同 = 4,
7 三带一 = 5,
8 炸弹 = 6,
9 五张顺子 = 7,
10 六张顺子 = 8,
11 三连对 = 9,
12 四带二 = 10,
13 二连飞机 = 11,
14 七张顺子 = 12,
15 四连对 = 13,
16 八张顺子 = 14,
17 飞机带翅膀 = 15,
18 九张顺子 = 16,
19 三连飞机 = 17,
20 五连对 = 18,
21 十张顺子 = 19,
22 十一张顺子 = 20,
23 十二张顺子 = 21,
24 四连飞机 = 22,
25 三连飞机带翅膀 = 23,
26 六连对 = 24,
27 //没有13
28 七连对 = 25,
29 五连飞机 = 26,
30 八连对 = 27,
31 四连飞机带翅膀 = 28,
32 //没有17
33 九连对 = 29,
34 六连飞机 = 30,
35 //没有19
36 十连对 = 31,
37 五连飞机带翅膀 = 32
38
39
40 //下面是各种牌组对应的牌的张数
41 //单张 = 1,
42 //对子 = 2,
43 //双王 = 2,
44 //三张相同 = 3,
45 //三带一 = 4,
46 //炸弹 = 4,
47 //五张顺子 = 5,
48 //六张顺子 = 6,
49 //三连对 = 6,
50 //四带二 = 6,
51 //二连飞机 = 6,
52 //七张顺子 = 7,
53 //四连对 = 8,
54 //八张顺子 = 8,
55 //飞机带翅膀 = 8,
56 //九张顺子 = 9,
57 //三连飞机 = 9,
58 //五连对 = 10,
59 //十张顺子 = 10,
60 //十一张顺子 = 11,
61 //十二张顺子 = 12,
62 //四连飞机 = 12,
63 //三连飞机带翅膀 = 12,
64 //六连对 = 12,
65 ////没有13
66 //七连对 = 14,
67 //五连飞机 = 15,
68 //八连对 = 16,
69 //四连飞机带翅膀 = 16,
70 ////没有17
71 //九连对 = 18,
72 //六连飞机 = 18,
73 ////没有19
74 //十连对 = 20,
75 //五连飞机带翅膀 = 20
76 }
当玩家出牌时,首先应判断玩家的牌组类型。
我判断牌组类型的方法是根据玩家所出牌组张数的不同来做出不同的处理。比如,玩家出的牌只有一张,那么肯定是个子。如果有两张肯定是对子。如果有三张,肯定是三个。如果有6张呢?就有三种情况了:1、顺子。2、连对。、3、飞机。由于顺子,连对,飞机这三种牌可以有很多组合,顺子可以有6张顺子或者7张顺子,连对可以有4连对或者5连对。飞机可以有2连飞机,三连飞机。所以就需要写几个方法分别判断牌组是否为顺子,连对,飞机了。
顺子和对子很好判断,飞机就麻烦点了,由于飞机可以随便带一张或几张牌,如果带的牌的点数比飞机本身的点数大,那么大的那张牌就被排序到飞机前面了,这样对比较牌组的大小很不方便。所以还要有一个对飞机带翅膀这样的牌组进行排序的方法。
判断牌组类型的代码如下:
/// <summary>
/// 验证所出牌组是否符合游戏规则
/// </summary>
public static bool IsRules(PokerGroup leadPokers) //判断所出牌组类型以及其是否符合规则
{
bool isRule = false;
Player.sort(leadPokers);
switch (leadPokers.Count)
{
case 0:
isRule = false;
break;
case 1:
isRule = true;
leadPokers.type = PokerGroupType.单张;
break;
case 2:
if (IsSame(leadPokers,2))
{
isRule = true;
leadPokers.type = PokerGroupType.对子;
}
else
{
if (leadPokers[0] == PokerNum.大王 && leadPokers[1] == PokerNum.小王)
{
leadPokers.type = PokerGroupType.双王;
isRule = true;
}
else
{
isRule = false;
}
}
break;
case 3:
if (IsSame(leadPokers,3))
{
leadPokers.type = PokerGroupType.三张相同;
isRule = true;
}
else
{
isRule = false;
}
break;
case 4:
if (IsSame(leadPokers, 4))
{
leadPokers.type = PokerGroupType.炸弹;
isRule = true;
}
else
{
if (IsThreeLinkPokers(leadPokers))
{
leadPokers.type = PokerGroupType.三带一;
isRule = true;
}
else
{
isRule = false;
}
}
break;
case 5:
if (IsStraight(leadPokers))
{
leadPokers.type = PokerGroupType.五张顺子;
isRule = true;
}
else
{
isRule = false;
}
break;
case 6:
if (IsStraight(leadPokers))
{
leadPokers.type = PokerGroupType.六张顺子;
isRule = true;
}
else
{
if (IsLinkPair(leadPokers))
{
leadPokers.type = PokerGroupType.三连对;
isRule = true;
}
else
{
if (IsSame(leadPokers, 4))
{
leadPokers.type = PokerGroupType.四带二;
isRule = true;
}
else
{
if (IsThreeLinkPokers(leadPokers))
{
leadPokers.type = PokerGroupType.二连飞机;
isRule = true;
}
else
{
isRule = false;
}
}
}
}
break;
case 7:
if (IsStraight(leadPokers))
{
leadPokers.type = PokerGroupType.七张顺子;
isRule = true;
}
else
{
isRule = false;
}
break;
case 8:
if (IsStraight(leadPokers))
{
leadPokers.type = PokerGroupType.八张顺子;
isRule = true;
}
else
{
if (IsLinkPair(leadPokers))
{
leadPokers.type = PokerGroupType.四连对;
isRule = true;
}
else
{
if (IsThreeLinkPokers(leadPokers))
{
leadPokers.type = PokerGroupType.飞机带翅膀;
isRule = true;
}
else
{
isRule = false;
}
}
}
break;
case 9:
if (IsStraight(leadPokers))
{
leadPokers.type = PokerGroupType.九张顺子;
isRule = true;
}
else
{
if (IsThreeLinkPokers(leadPokers))
{
leadPokers.type = PokerGroupType.三连飞机;
}
else
{
isRule = false;
}
}
break;
case 10:
if (IsStraight(leadPokers))
{
leadPokers.type = PokerGroupType.十张顺子;
isRule = true;
}
else
{
if (IsLinkPair(leadPokers))
{
leadPokers.type = PokerGroupType.五连对;
isRule = true;
}
else
{
isRule = false;
}
}
break;
case 11:
if (IsStraight(leadPokers))
{
leadPokers.type = PokerGroupType.十一张顺子;
isRule = true;
}
else
{
isRule = false;
}
break;
case 12:
if (IsStraight(leadPokers))
{
leadPokers.type = PokerGroupType.十二张顺子;
isRule = true;
}
else
{
if (IsLinkPair(leadPokers))
{
leadPokers.type = PokerGroupType.六连对;
isRule = true;
}
else
{
if (IsThreeLinkPokers(leadPokers))
{
//12有三连飞机带翅膀和四连飞机两种情况,所以在IsThreeLinkPokers中做了特殊处理,此处不用给type赋值.
isRule = true;
}
else
{
isRule = false;
}
}
}
break;
case 13:
isRule = false;
break;
case 14:
if (IsLinkPair(leadPokers))
{
leadPokers.type = PokerGroupType.七连对;
isRule = true;
}
else
{
isRule = false;
}
break;
case 15:
if (IsThreeLinkPokers(leadPokers))
{
leadPokers.type = PokerGroupType.五连飞机;
isRule = true;
}
else
{
isRule = false;
}
break;
case 16:
if (IsLinkPair(leadPokers))
{
leadPokers.type = PokerGroupType.八连对;
isRule = true;
}
else
{
if (IsThreeLinkPokers(leadPokers))
{
leadPokers.type = PokerGroupType.四连飞机带翅膀;
isRule = true;
}
else
{
isRule = false;
}
}
break;
case 17:
isRule = false;
break;
case 18:
if (IsLinkPair(leadPokers))
{
leadPokers.type = PokerGroupType.六连对;
isRule = true;
}
else
{
if (IsThreeLinkPokers(leadPokers))
{
leadPokers.type = PokerGroupType.六连飞机;
isRule = true;
}
else
{
isRule = false;
}
}
break;
case 19:
isRule = false;
break;
case 20:
if (IsLinkPair(leadPokers))
{
leadPokers.type = PokerGroupType.十连对;
isRule = true;
}
else
{
if (IsThreeLinkPokers(leadPokers))
{
leadPokers.type = PokerGroupType.五连飞机带翅膀;
isRule = true;
}
else
{
isRule = false;
}
}
break;
}
return isRule;
}
/// <summary>
/// 判断一个牌组指定数量相邻的牌是否两两相同
/// </summary>
/// <param name="PG">牌组对象</param>
/// <param name="amount">指定数量的相邻牌组</param>
/// <returns>指定数量的相邻牌是否两两相同</returns>
public static bool IsSame(PokerGroup PG, int amount)
{
bool IsSame1 = false;
bool IsSame2 = false;
for (int i = 0; i < amount - 1; i++) //从大到小比较相邻牌是否相同
{
if (PG[i] == PG[i+1])
{
IsSame1 = true;
}
else
{
IsSame1 = false;
break;
}
}
for (int i = PG.Count - 1; i > PG.Count - amount; i--) //从小到大比较相邻牌是否相同
{
if (PG[i] == PG[i - 1])
{
IsSame2 = true;
}
else
{
IsSame2 = false;
break;
}
}
if (IsSame1 || IsSame2)
{
return true;
}
else
{
return false;
}
}
/// <summary>
/// 判断牌组是否为顺子
/// </summary>
/// <param name="PG">牌组</param>
/// <returns>是否为顺子</returns>
public static bool IsStraight(PokerGroup PG)
{
bool IsStraight = false;
foreach (Poker poker in PG)//不能包含2、小王、大王
{
if (poker == PokerNum.P2 || poker == PokerNum.小王 || poker == PokerNum.大王)
{
IsStraight = false;
return IsStraight;
}
}
for (int i = 0; i < PG.Count - 1; i++)
{
if (PG[i].pokerNum - 1 == PG[i + 1].pokerNum)
{
IsStraight = true;
}
else
{
IsStraight = false;
break;
}
}
return IsStraight;
}
/// <summary>
/// 判断牌组是否为连对
/// </summary>
/// <param name="PG">牌组</param>
/// <returns>是否为连对</returns>
public static bool IsLinkPair(PokerGroup PG)
{
bool IsLinkPair = false;
foreach (Poker poker in PG) //不能包含2、小王、大王
{
if (poker == PokerNum.P2 || poker == PokerNum.小王 || poker == PokerNum.大王)
{
IsLinkPair = false;
return IsLinkPair;
}
}
for (int i = 0; i < PG.Count - 2; i += 2) //首先比较是否都为对子,再比较第一个对子的点数-1是否等于第二个对子,最后检察最小的两个是否为对子(这里的for循环无法检测到最小的两个,所以需要拿出来单独检查)
{
if (PG[i] == PG[i + 1] && PG[i].pokerNum - 1 == PG[i + 2].pokerNum && PG[i + 2] == PG[i + 3])
{
IsLinkPair = true;
}
else
{
IsLinkPair = false;
break;
}
}
return IsLinkPair;
}
/// <summary>
/// 判断牌组是否为连续三张牌,飞机,飞机带翅膀
/// </summary>
/// <param name="PG">牌组</param>
/// <returns>是否为连续三张牌</returns>
public static bool IsThreeLinkPokers(PokerGroup PG) //判断三张牌方法为判断两两相邻的牌,如果两两相邻的牌相同,则count自加1.最后根据count的值判断牌的类型为多少个连续三张
{
bool IsThreeLinkPokers = false;
int HowMuchLinkThree = 0; //飞机的数量
PG = SameThreeSort(PG); //排序,把飞机放在前面
for (int i = 2; i < PG.Count; i++) //得到牌组中有几个飞机
{
if (PG[i] == PG[i - 1] && PG[i] == PG[i - 2])
{
HowMuchLinkThree++;
}
}
if (HowMuchLinkThree > 0) //当牌组里面有三个时
{
if (HowMuchLinkThree > 1) //当牌组为飞机时
{
for (int i = 0; i < HowMuchLinkThree * 3 - 3; i += 3) //判断飞机之间的点数是否相差1
{
if (PG[i] != PokerNum.P2 && PG[i].pokerNum - 1 == PG[i + 3].pokerNum) //2点不能当飞机出
{
IsThreeLinkPokers = true;
}
else
{
IsThreeLinkPokers = false;
break;
}
}
}
else
{
IsThreeLinkPokers = true; //牌组为普通三个,直接返回true
}
}
else
{
IsThreeLinkPokers = false;
}
if (HowMuchLinkThree == 4)
{
PG.type = PokerGroupType.四连飞机;
}
if (HowMuchLinkThree == 3 && PG.Count == 12)
{
PG.type = PokerGroupType.三连飞机带翅膀;
}
return IsThreeLinkPokers;
}
/// <summary>
/// 对飞机和飞机带翅膀进行排序,把飞机放在前面,翅膀放在后面.
/// </summary>
/// <param name="PG">牌组</param>
/// <returns>是否为连续三张牌</returns>
public static PokerGroup SameThreeSort(PokerGroup PG)
{
Poker FourPoker = null; //如果把4张当三张出并且带4张的另外一张,就需要特殊处理,这里记录出现这种情况的牌的点数.
bool FindedThree = false; //已找到三张相同的牌
PokerGroup tempPokerGroup = new PokerGroup(); //记录三张相同的牌
int count = 0; //记录在连续三张牌前面的翅膀的张数
int Four = 0; // 记录是否连续出现三三相同,如果出现这种情况则表明出现把4张牌(炸弹)当中的三张和其他牌配成飞机带翅膀,并且翅膀中有炸弹牌的点数.
// 比如有如下牌组: 998887777666 玩家要出的牌实际上应该为 888777666带997,但是经过从大到小的排序后变成了998887777666 一不美观,二不容易比较.
for (int i = 2; i < PG.Count; i++) //直接从2开始循环,因为PG[0],PG[1]的引用已经存储在其他变量中,直接比较即可
{
if (PG[i] == PG[i - 2] && PG[i] == PG[i - 1])// 比较PG[i]与PG[i-1],PG[i]与PG[i-2]是否同时相等,如果相等则说明这是三张相同牌
{
if (Four >= 1) //默认的Four为0,所以第一次运行时这里为false,直接执行else
//一旦连续出现两个三三相等,就会执行这里的if
{
FourPoker = PG[i]; //当找到四张牌时,记录下4张牌的点数
Poker changePoker;
for (int k = i; k > 0; k--) //把四张牌中的一张移动到最前面.
{
changePoker = PG[k];
PG[k] = PG[k - 1];
PG[k - 1] = changePoker;
}
count++; //由于此时已经找到三张牌,下面为count赋值的程序不会执行,所以这里要手动+1
}
else
{
Four++; //记录本次循环,因为本次循环找到了三三相等的牌,如果连续两次找到三三相等的牌则说明找到四张牌(炸弹)
tempPokerGroup.Add(PG[i]); //把本次循环的PG[i]记录下来,即记录下三张牌的点数
}
FindedThree = true; //标记已找到三张牌
}
else
{
Four = 0; //没有找到时,连续找到三张牌的标志Four归零
if (!FindedThree) //只有没有找到三张牌时才让count增加.如果已经找到三张牌,则不再为count赋值.
{
count = i - 1;
}
}
}
foreach (Poker tempPoker in tempPokerGroup) //迭代所有的三张牌点数
{
Poker changePoker; //临时交换Poker
for (int i = 0; i < PG.Count; i++) //把所有的三张牌往前移动
{
if (PG[i] == tempPoker) //当PG[i]等于三张牌的点数时
{
if (PG[i] == FourPoker) //由于上面已经把4张牌中的一张放到的最前面,这张牌也会与tempPoker相匹配所以这里进行处理
// 当第一次遇到四张牌的点数时,把记录四张牌的FourPoker赋值为null,并中断本次循环.由于FourPoker已经为Null,所以下次再次遇到四张牌的点数时会按照正常情况执行.
{
FourPoker = null;
continue;
}
changePoker = PG[i - count];
PG[i - count] = PG[i];
PG[i] = changePoker;
}
}
}
return PG;
}
无序的牌组通过以上代码的洗礼,已经变成了非常容易比较的牌组了。
比较牌组的大小就非常简单了。首先排除特殊牌组炸弹,双王。
然后再比较普通牌组的第一张牌就可以了。下面是牌组比较的代码,重写了PokerGroup的大于号运算符
public static bool operator >(PokerGroup LP, PokerGroup RP)
{
bool IsGreater = false;
if (LP.type != RP.type && LP.type != PokerGroupType.炸弹 && LP.type != PokerGroupType.双王)
{
IsGreater = false;
}
else
{
if (LP.type == PokerGroupType.炸弹 && RP.type == PokerGroupType.炸弹) //LPRP都为炸弹
{
if (LP[0] > RP[0]) //比较大小
{
IsGreater = true;
}
else
{
IsGreater = false;
}
}
else
{
if (LP.type == PokerGroupType.炸弹) //只有LP为炸弹
{
IsGreater = true;
}
else
{
if (LP.type == PokerGroupType.双王) //LP为双王
{
IsGreater = true;
}
else
{
if (LP[0] > RP[0]) //LP为普通牌组
{
IsGreater = true;
}
else
{
IsGreater = false;
}
}
}
}
}
return IsGreater;
}
然后在接收其他玩家牌组的时候调用IsRule方法给牌组定义一个类型,自己出牌的时候也定义一个类型,再在出牌的时候比较俩牌组的大小。