下面就该进入打牌环节了
打牌之前, 首先应该定义牌的类型有哪些.
斗地主里面分成
单牌, 对子, 三不带, 三带一
拖拉机, 顺子, 飞机
王炸
其中, 拖拉机最多10对, 顺子至少5张 最多12张
飞机内容比较多
我们先把所有可能出现的牌型列举出来
// 牌型
const (
cardTypeNIL int = iota // 留空
// 单牌
cardTypeSINGLE
// 对子
cardTypeDUAD
// 三干
cardTypeTRIPLE0
// 三带一
cardTypeTRIPLE1
// 3对拖拉机
cardTypeTRACTOR3
// 4对拖拉机
cardTypeTRACTOR4
// 5对拖拉机
cardTypeTRACTOR5
// 6对拖拉机
cardTypeTRACTOR6
// 7对拖拉机
cardTypeTRACTOR7
// 8对拖拉机
cardTypeTRACTOR8
// 9对拖拉机
cardTypeTRACTOR9
// 10对拖拉机
cardTypeTRACTOR10
// 5张顺子
cardTypeSTRAIGHT5
// 6张顺子
cardTypeSTRAIGHT6
// 7张顺子
cardTypeSTRAIGHT7
// 8张顺子
cardTypeSTRAIGHT8
// 9张顺子
cardTypeSTRAIGHT9
// 10张顺子
cardTypeSTRAIGHT10
// 11张顺子
cardTypeSTRAIGHT11
// 12张顺子
cardTypeSTRAIGHT12
// 飞机不带
cardTypePLANE20
// 3飞机不带
cardTypePLANE30
// 4飞机不带(这里其实可以当做3飞机带3单) cardTypePLANE31
cardTypePLANE40
// 5飞机不带
cardTypePLANE50
// 6飞机不带
cardTypePLANE60
// 飞机带2单
cardTypePLANE21
// 3飞机带3单
cardTypePLANE31
// 4飞机带4单
cardTypePLANE41
// 5飞机带5单
cardTypePLANE51
// 炸弹
cardTypeBOMB
// 王炸火箭
cardTypeROCKET
)
计算牌型前别忘记先洗一次牌
首先分析1~4张牌的牌型
1张肯定是单牌
// 单张
func (self TCards) getCardType1() (int, int) {
return cardTypeSINGLE, self[0].nPoint // 单张的只有单牌
}
2张牌可能是王炸或者对子
// 两张牌
func (self TCards) getCardType2() (int, int) {
if self[0].nPoint == cardPointX && self[1].nPoint == cardPointY {
return cardTypeROCKET, self[0].nPoint // 王炸
}
if self[0].nPoint == self[1].nPoint {
return cardTypeDUAD, self[0].nPoint // 一样的是对子
}
return cardTypeNIL, 0
}
3张牌只能是3不带
// 三张牌, 只可能是三干
func (self TCards) getCardType3() (int, int) {
if self[0].nPoint == self[1].nPoint && self[0].nPoint == self[2].nPoint {
return cardTypeTRIPLE0, self[0].nPoint // 三张一样单牌
}
return cardTypeNIL, 0
}
4张牌只能是三带一或者炸弹
// 四张牌, 可能是三带一 或者
func (self TCards) getCardType4() (int, int) {
if self[1].nPoint != self[2].nPoint {
return cardTypeNIL, 0 // 如果中间两张不相等就没意义了
}
if self[0].nPoint == self[3].nPoint {
return cardTypeBOMB, self[1].nPoint // 如果首位两张也相等(因为是排序的, 通过夹逼准则, 四张牌都相等)
}
if self[0].nPoint == self[1].nPoint || self[1].nPoint == self[3].nPoint {
return cardTypeTRIPLE1, self[1].nPoint // 只要有一个相等就是三带一
}
return cardTypeNIL, 0
}
超过5张牌的情况就比较复杂了..... 顺子, 拖拉机, 飞机等其他情况
我们依次来做判断
首先是比较简单的顺子算法
// 可以检查是否是顺子
func (self TCards) checkCardTypeStraight() (int, int) {
nFirst := self[0].nPoint // 起始的牌
nLen := len(self)
// 顺子最少5张, 最多3 -> A = 12 张
if nLen < 5 || nLen > 12 {
return cardTypeNIL, cardPointNIL
}
// 按顺序计算是否正常
for i := 1; i < nLen; i++ {
if self[i].nPoint-nFirst != i {
return cardTypeNIL, cardPointNIL
}
}
// 到了A就要截止
if self[nLen-1].nPoint > cardPointA {
return cardTypeNIL, cardPointNIL
}
return cardTypeSTRAIGHT5 + nLen - 5, self[0].nPoint
}
再次是同样简单的拖拉机
// 6张牌可以检查是否是拖拉机
func (self TCards) checkCardTypeTractor() (int, int) {
nFirst := self[0].nPoint
nLen := len(self)
// 必须是双数卡组才可能是拖拉机
if nLen%2 == 1 {
return cardTypeNIL, cardPointNIL
}
// 最少3对, 最多10对
if nLen < 6 || nLen > 20 {
return cardTypeNIL, cardPointNIL
}
// 第一张拖拉机对子
if self[1].nPoint != nFirst {
return cardTypeNIL, cardPointNIL
}
// 循环后面的拖拉机对子
for i := 1; i < nLen/2; i++ {
if self[2*i].nPoint-nFirst != i {
return cardTypeNIL, cardPointNIL
}
if self[2*i+1].nPoint-nFirst != i {
return cardTypeNIL, cardPointNIL
}
}
return cardTypeTRACTOR3 + nLen/2 - 3, self[0].nPoint // 6张 3对拖拉机起, 长度+2 就是+1
}
飞机分成3个不带的飞机和3个带1的两种. 有些部分还有3个带一对, 或者不到最后一手牌必须进行三带一 (本公司算法)
其中三个的部分和拖拉机差不多. 由于夹逼原则, 排序过后只需要第一第三张牌符合条件即可
// 飞机全是三不带
func (self TCards) getCardTypePlane3Only() (int, int) {
nLen := len(self)
// 基础数量判断
if nLen < 6 || nLen > 18 {
return cardTypeNIL, cardPointNIL
}
nFirst := self[0].nPoint
// 3张牌做3张牌循环, 先三三检查是否满足
if self[2].nPoint != nFirst {
return cardTypeNIL, cardPointNIL
}
// 再检查是否依次递增
for i := 1; i < nLen/3; i++ {
if self[i*3].nPoint-nFirst != i {
return cardTypeNIL, cardPointNIL
}
if self[i*3+2].nPoint-nFirst != i {
return cardTypeNIL, cardPointNIL
}
}
return cardTypePLANE20 + (nLen / 3) - 2, self[0].nPoint
}
三带一稍微复杂一点. 需要找到所有牌的数量, 然后进行检测
// 飞机是三带一
func (self TCards) getCardTypePlane3And1() (int, int) {
nLen := len(self)
var data [15]int
// 数量
for _, pCard := range self {
data[pCard.nPoint]++
}
// 找到飞机主干
findFun := func(nStart int) int {
for i := nStart; i < 15; i++ {
if data[i] > 3 {
return i
}
}
return 0
}
n1 := findFun(1)
for i := 0; i < nLen/4; i++ {
if n1 == 0 {
return cardTypeNIL, cardPointNIL
}
n2 := findFun(n1)
if n2 != n1+1 {
return cardTypeNIL, cardPointNIL
}
n1 = n2
}
return cardTypePLANE21 + (nLen / 4) - 2, n1
}
到此为止, 牌型的部分暂时告一段落.