Golang makes a Doudizhu game server [5]: card type

Now it’s time to enter the card game

Before playing cards, you should first define the types of cards.

Divide into the landlord 

Single hand, pair, three without, three with one

Tractor, straight, airplane

King Fried

Among them, there are at most 10 pairs of tractors, at least 5 straights and at most 12 straights.

The aircraft content is more

Let's first list all the possible card types



// 牌型
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
)

Don't forget to shuffle the cards before calculating the card type

First analyze the card types of 1~4 cards

1 card must be a single card

// 单张
func (self TCards) getCardType1() (int, int) {
	return cardTypeSINGLE, self[0].nPoint // 单张的只有单牌
}

2 cards may be king or pair

// 两张牌
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 cards can only be 3 without

// 三张牌, 只可能是三干
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 cards can only be three with one or a bomb

// 四张牌, 可能是三带一 或者
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
}

The situation with more than 5 cards is more complicated... Straight, tractor, airplane and other situations

Let's make judgments in turn

The first is the simpler straight algorithm


// 可以检查是否是顺子
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
}

Again the same simple tractor


// 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
}

There are 3 planes without planes and 3 planes with 1s. In some parts, there are 3 planes with a pair, or less than the last hand must be three with one (our company's algorithm)

Three of them are similar to tractors. Due to the pinch principle, only the first and third cards are required to meet the conditions after sorting.


// 飞机全是三不带
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
}

Three belts and one is a bit more complicated. You need to find the number of all cards and then check


// 飞机是三带一
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
}

So far, the part of the card pattern has temporarily come to an end.

Guess you like

Origin blog.csdn.net/warrially/article/details/88635058