├── .gitignore
├── .idea
└── vcs.xml
├── README.md
├── analyzer_landlord.go
├── cardname_recorder.go
├── doc.go
├── factory.go
├── setchecker_landlord_test.go
├── setchecker_lanlord.go
├── setinfo.go
├── sorts.go
└── sorts_test.go
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # pokergame
2 | 多种经典扑克牌游戏的基础规则实现,包括牌型检测,牌型比较,记牌器,牌型分析器等
3 |
--------------------------------------------------------------------------------
/analyzer_landlord.go:
--------------------------------------------------------------------------------
1 | package pokergame
2 |
3 | import (
4 | "github.com/wqtapp/poker"
5 | "sync"
6 | )
7 |
8 | //定义玩家的扑克牌分析器map的索引为poker的value,value为改值得扑克牌在玩家牌中的索引
9 | type landLordAnalyzer struct{
10 | sync.RWMutex
11 | dic map[int]poker.PokerSet
12 | }
13 |
14 | //根据给定的扑克集初始化分析器
15 | func (ana *landLordAnalyzer) InitAnalyzer(){
16 | ana.dic = make(map[int]poker.PokerSet)
17 | ana.dic[poker.CARD_VALUE_THREE] = poker.PokerSet{}
18 | ana.dic[poker.CARD_VALUE_FOUR] = poker.PokerSet{}
19 | ana.dic[poker.CARD_VALUE_FIVE] = poker.PokerSet{}
20 | ana.dic[poker.CARD_VALUE_SIX] = poker.PokerSet{}
21 | ana.dic[poker.CARD_VALUE_SEVEN] = poker.PokerSet{}
22 | ana.dic[poker.CARD_VALUE_EIGHT] = poker.PokerSet{}
23 | ana.dic[poker.CARD_VALUE_NINE] = poker.PokerSet{}
24 | ana.dic[poker.CARD_VALUE_TEN] = poker.PokerSet{}
25 | ana.dic[poker.CARD_VALUE_JACK] = poker.PokerSet{}
26 | ana.dic[poker.CARD_VALUE_QUEEN] = poker.PokerSet{}
27 | ana.dic[poker.CARD_VALUE_KING] = poker.PokerSet{}
28 | ana.dic[poker.CARD_VALUE_ACE] = poker.PokerSet{}
29 | ana.dic[poker.CARD_VALUE_TWO] = poker.PokerSet{}
30 | ana.dic[poker.CARD_VALUE_BLACK_JOKER] = poker.PokerSet{}
31 | ana.dic[poker.CARD_VALUE_RED_JOKER] = poker.PokerSet{}
32 | }
33 | //根据给定的扑克集更新记牌器,出牌时调用
34 | func (ana *landLordAnalyzer) RemovePokerSet(pokers poker.PokerSet){
35 | ana.Lock()
36 | defer ana.Unlock()
37 | pokers.DoOnEachPokerCard(func(index int,card *poker.PokerCard){
38 | ana.dic[card.GetValue()],_ = ana.dic[card.GetValue()].DelPokers(poker.PokerSet{card})
39 | })
40 | }
41 |
42 | func (ana *landLordAnalyzer) AddPokerSet(pokers poker.PokerSet){
43 | ana.Lock()
44 | defer ana.Unlock()
45 | pokers.DoOnEachPokerCard(func(index int,card *poker.PokerCard){
46 | ana.dic[card.GetValue()] = ana.dic[card.GetValue()].AddPokers(poker.PokerSet{card})
47 | })
48 | }
49 |
50 | func (ana *landLordAnalyzer) GetMinPlayableCards() poker.PokerSet{
51 | ana.Lock()
52 | defer ana.Unlock()
53 | for i:= poker.CARD_VALUE_THREE;i<=poker.CARD_VALUE_RED_JOKER;i++{
54 | set,_ := ana.dic[i]
55 | if set.CountCards() > 0{
56 | return set
57 | }
58 | }
59 | return poker.PokerSet{}
60 | }
61 | //根据最后一次出牌的牌型信息,返回可出的扑克集
62 | func (ana *landLordAnalyzer) GetUseableCards(setType *SetInfo) []poker.PokerSet{
63 | ana.Lock()
64 | defer ana.Unlock()
65 |
66 | var useableSets []poker.PokerSet
67 |
68 | switch setType.setType {
69 | case LANDLORD_SET_TYPE_SINGLE:
70 | useableSets = ana.getSingleValueSet(1,setType.GetMinValue())
71 | case LANDLORD_SET_TYPE_DRAGON:
72 | useableSets = ana.getMultiValueSet(1,setType.GetMinValue(),setType.GetMaxValue())
73 | case LANDLORD_SET_TYPE_PAIR:
74 | useableSets = ana.getSingleValueSet(2,setType.GetMinValue())
75 | case LANDLORD_SET_TYPE_MULIT_PAIRS:
76 | useableSets = ana.getMultiValueSet(2,setType.GetMinValue(),setType.GetMaxValue())
77 | case LANDLORD_SET_TYPE_THREE:
78 | useableSets = ana.getSingleValueSet(3,setType.GetMinValue())
79 | case LANDLORD_SET_TYPE_THREE_PLUS_ONE:
80 | useableSets = ana.getSingleValueSet(3,setType.GetMinValue())
81 | for i,tempset := range useableSets{
82 | tempsetPlus := ana.getPlusSet(1,1,tempset)
83 | if tempsetPlus.CountCards() >0 {
84 | useableSets[i] = tempset.AddPokers(tempsetPlus)
85 | }else{//没有牌可以带,将之前的主牌移除可出牌集合
86 | useableSets[i] = nil
87 | }
88 | }
89 | case LANDLORD_SET_TYPE_THREE_PLUS_TWO:
90 | useableSets = ana.getSingleValueSet(3,setType.GetMinValue())
91 | for i,tempset := range useableSets{
92 | tempsetPlus := ana.getPlusSet(2,1,tempset)
93 | if tempsetPlus.CountCards() >0 {
94 | useableSets[i] = tempset.AddPokers(tempsetPlus)
95 | }else{//没有牌可以带,将之前的主牌移除可出牌集合
96 | useableSets[i] = nil
97 | }
98 | }
99 | case LANDLORD_SET_TYPE_MULITY_THREE:
100 | useableSets = ana.getMultiValueSet(3,setType.GetMinValue(),setType.GetMaxValue())
101 | case LANDLORD_SET_TYPE_MULITY_THREE_PLUS_ONE:
102 | useableSets = ana.getMultiValueSet(3,setType.GetMinValue(),setType.GetMaxValue())
103 | for i,tempset := range useableSets{
104 | tempsetPlus := ana.getPlusSet(1,setType.GetRangeWidth(),tempset)
105 | if tempsetPlus.CountCards() >0 {
106 | useableSets[i] = tempset.AddPokers(tempsetPlus)
107 | }else{//没有牌可以带,将之前的主牌移除可出牌集合
108 | useableSets[i] = nil
109 | }
110 | }
111 | case LANDLORD_SET_TYPE_MULITY_THREE_PLUS_TWO:
112 | useableSets = ana.getMultiValueSet(3,setType.GetMinValue(),setType.GetMaxValue())
113 | for i,tempset := range useableSets{
114 | tempsetPlus := ana.getPlusSet(2,setType.GetRangeWidth(),tempset)
115 | if tempsetPlus.CountCards() >0 {
116 | useableSets[i] = tempset.AddPokers(tempsetPlus)
117 | }else{//没有牌可以带,将之前的主牌移除可出牌集合
118 | useableSets[i] = nil
119 | }
120 | }
121 | case LANDLORD_SET_TYPE_FOUR_PLUS_TWO:
122 | useableSets = ana.getSingleValueSet(4,setType.GetMinValue())
123 | for i,tempset := range useableSets{
124 | //带两个单牌
125 | tempsetPlus := ana.getPlusSet(1,2,tempset)
126 | if tempsetPlus.CountCards() >0 {
127 | useableSets[i] = tempset.AddPokers(tempsetPlus)
128 | }else{
129 | //带一对牌,看做两个单牌
130 | tempsetPlus := ana.getPlusSet(2,1,tempset)
131 | if tempsetPlus.CountCards() >0 {
132 | useableSets[i] = tempset.AddPokers(tempsetPlus)
133 | }else{//没有牌可以带,将之前的主牌移除可出牌集合
134 | useableSets[i] = nil
135 | }
136 | }
137 | }
138 | case LANDLORD_SET_TYPE_FOUR_PLUS_FOUR:
139 | useableSets = ana.getSingleValueSet(4,setType.GetMinValue())
140 | for i,tempset := range useableSets{
141 | tempsetPlus := ana.getPlusSet(2,2,tempset)
142 | if tempsetPlus.CountCards() >0 {
143 | useableSets[i] = tempset.AddPokers(tempsetPlus)
144 | }else{//没有牌可以带,将之前的主牌移除可出牌集合
145 | useableSets[i] = nil
146 | }
147 | }
148 | case LANDLORD_SET_TYPE_MULITY_FOUR:
149 | useableSets = ana.getMultiValueSet(4,setType.GetMinValue(),setType.GetMaxValue())
150 | case LANDLORD_SET_TYPE_MULITY_FOUR_PLUS_TWO:
151 | useableSets = ana.getMultiValueSet(4,setType.GetMinValue(),setType.GetMaxValue())
152 | for i,tempset := range useableSets{
153 | //带两个单牌
154 | tempsetPlus := ana.getPlusSet(1,2*setType.GetRangeWidth(),tempset)
155 | if tempsetPlus.CountCards() >0 {
156 | useableSets[i] = tempset.AddPokers(tempsetPlus)
157 | }else{
158 | //带一对牌,看做两个单牌
159 | tempsetPlus := ana.getPlusSet(2,setType.GetRangeWidth(),tempset)
160 | if tempsetPlus.CountCards() >0 {
161 | useableSets[i] = tempset.AddPokers(tempsetPlus)
162 | }else{//没有牌可以带,将之前的主牌移除可出牌集合
163 | useableSets[i] = nil
164 | }
165 | }
166 | }
167 | case LANDLORD_SET_TYPE_MULITY_FOUR_PLUS_FOUR:
168 | useableSets = ana.getMultiValueSet(4,setType.GetMinValue(),setType.GetMaxValue())
169 | for i,tempset := range useableSets{
170 | tempsetPlus := ana.getPlusSet(2,2*setType.GetRangeWidth(),tempset)
171 | if tempsetPlus.CountCards() >0 {
172 | useableSets[i] = tempset.AddPokers(tempsetPlus)
173 | }else{//没有牌可以带,将之前的主牌移除可出牌集合
174 | useableSets[i] = nil
175 | }
176 | }
177 | case LANDLORD_SET_TYPE_COMMON_BOMB:
178 | useableSets = ana.getSingleValueSet(4,setType.GetMinValue())
179 | case LANDLORD_SET_TYPE_JOKER_BOMB:
180 | useableSets = []poker.PokerSet{}
181 | default:
182 | useableSets = []poker.PokerSet{}
183 | }
184 | //去掉nil元素
185 | newUseableSets := []poker.PokerSet{}
186 | for _,sets := range useableSets{
187 | if sets != nil{
188 | newUseableSets = append(newUseableSets,sets)
189 | }
190 | }
191 | //上一次出牌不是炸弹,则直接将炸弹加入可出的排中
192 | if setType.setType != LANDLORD_SET_TYPE_COMMON_BOMB && setType.setType != LANDLORD_SET_TYPE_JOKER_BOMB {
193 | //王炸
194 | jokerBombSet := ana.getJokerBomb()
195 | if jokerBombSet.CountCards() > 0{
196 | newUseableSets = append(newUseableSets,jokerBombSet)
197 | }
198 | //普通炸弹
199 | for _,tempSet := range ana.getSingleValueSet(4,-1){
200 | if tempSet.CountCards() > 0{
201 | newUseableSets = append(newUseableSets,tempSet)
202 | }
203 | }
204 | }
205 | return newUseableSets
206 | }
207 | //获取单值牌组成的扑克集的切片,单排对牌三牌四排等等
208 | //count表示单值牌的张数
209 | //minValue表示上家出牌的最小的牌的大小
210 | func (ana *landLordAnalyzer) getSingleValueSet(count int,minValue int) []poker.PokerSet{
211 | sets := []poker.PokerSet{}
212 | se := poker.NewPokerSet()
213 | //先不拆牌的情况下查找
214 | for i:=minValue+1;i<= poker.CARD_VALUE_RED_JOKER;i++{
215 | if ana.dic[i].CountCards() == count {
216 | se = se.AddPokers(ana.dic[i])
217 | sets = append(sets,se)
218 | se = poker.NewPokerSet()
219 | }
220 | }
221 | //不拆牌的情况下找不到可出的牌,再考虑拆牌的情况
222 | if len(sets) == 0{
223 | for i:=minValue+1;i<= poker.CARD_VALUE_RED_JOKER;i++{
224 | if ana.dic[i].CountCards() > count {
225 | se = se.AddPokers(ana.dic[i][:count])
226 | sets = append(sets,se)
227 | se = poker.NewPokerSet()
228 | }
229 | }
230 | }
231 | return sets
232 | }
233 | //获取多种不同值组成的扑克集的切片,2连3连4连5连等
234 | func (ana *landLordAnalyzer) getMultiValueSet(count int,minValue int,maxValue int) []poker.PokerSet{
235 | sets := []poker.PokerSet{}
236 | se := poker.NewPokerSet()
237 | valueRange := maxValue-minValue+1
238 | //先考虑不拆拍的情况
239 | for i:=minValue+1;i<= poker.CARD_VALUE_TWO-valueRange;i++{
240 | for j:=i;j count {
258 | se = se.AddPokers(ana.dic[j][:count])
259 | }
260 | }
261 | //该范围内连续的牌的张数符合要求
262 | if se.CountCards() == valueRange*count{
263 | sets = append(sets,se)
264 | se = poker.NewPokerSet()
265 | }else{
266 | se = poker.NewPokerSet()
267 | }
268 | }
269 | }
270 |
271 | return sets
272 | }
273 | //获取附牌,比如三带一中的一,四带二中二,只获取一种可能即可
274 | //不拆牌为第一原则,可能会带出去大牌
275 | //num张数count系列数exceptset不能包含在内的扑克集
276 | func (ana *landLordAnalyzer) getPlusSet(num int,count int,exceptSet poker.PokerSet) poker.PokerSet{
277 | resSet := poker.NewPokerSet()
278 | //第一原则不拆牌原则
279 | for i:= poker.CARD_VALUE_THREE;i<= poker.CARD_VALUE_RED_JOKER;i++{
280 | if ana.dic[i].CountCards() == num{
281 | if !ana.dic[i][:num].HasSameValueCard(exceptSet) {
282 | resSet = resSet.AddPokers(ana.dic[i])
283 | }
284 | }
285 | if resSet.CountCards() == num*count{
286 | return resSet
287 | }
288 | }
289 | //不拆牌找不到则,考虑拆牌
290 | if resSet.CountCards() == 0{
291 | for i:= poker.CARD_VALUE_THREE;i<= poker.CARD_VALUE_RED_JOKER;i++{
292 | if ana.dic[i].CountCards() > num{
293 | if !ana.dic[i][:num].HasSameValueCard(exceptSet) {
294 | resSet = resSet.AddPokers(ana.dic[i][:num])
295 | }
296 | }
297 | if resSet.CountCards() == num*count{
298 | return resSet
299 | }
300 | }
301 | }
302 |
303 | return poker.PokerSet{}
304 | }
305 | func (ana *landLordAnalyzer) getJokerBomb() poker.PokerSet{
306 | resSet := poker.NewPokerSet()
307 | for i:= poker.CARD_VALUE_BLACK_JOKER;i<= poker.CARD_VALUE_RED_JOKER;i++ {
308 | if ana.dic[i].CountCards() > 0 {
309 | resSet = resSet.AddPokers(ana.dic[i])
310 | }
311 | }
312 | if resSet.CountCards() > 1{
313 | return resSet
314 | }else{
315 | return poker.NewPokerSet()
316 | }
317 | }
318 |
319 |
320 |
--------------------------------------------------------------------------------
/cardname_recorder.go:
--------------------------------------------------------------------------------
1 | package pokergame
2 |
3 | import (
4 | "strconv"
5 | "github.com/wqtapp/poker"
6 | "sync"
7 | )
8 |
9 |
10 | //记牌器,记录玩家之外带各牌待出的数量
11 | type cardNameRecorder struct {
12 | sync.RWMutex
13 | dic map[string]int
14 | }
15 |
16 | //初始化玩家记牌器,发牌后调用
17 | func (re *cardNameRecorder)InitRecorder(){
18 | re.dic = make(map[string]int)
19 | re.dic[poker.CARD_SYMBOL_THREE] = 0
20 | re.dic[poker.CARD_SYMBOL_FOUR] = 0
21 | re.dic[poker.CARD_SYMBOL_FIVE] = 0
22 | re.dic[poker.CARD_SYMBOL_SIX] = 0
23 | re.dic[poker.CARD_SYMBOL_SEVEN] = 0
24 | re.dic[poker.CARD_SYMBOL_EIGHT] = 0
25 | re.dic[poker.CARD_SYMBOL_NINE] = 0
26 | re.dic[poker.CARD_SYMBOL_TEN] = 0
27 | re.dic[poker.CARD_SYMBOL_JACK] = 0
28 | re.dic[poker.CARD_SYMBOL_QUEEN] = 0
29 | re.dic[poker.CARD_SYMBOL_KING] = 0
30 | re.dic[poker.CARD_SYMBOL_ACE] = 0
31 | re.dic[poker.CARD_SYMBOL_TWO] = 0
32 | re.dic[poker.CARD_SYMBOL_BLACK_JOKER] = 0
33 | re.dic[poker.CARD_SYMBOL_RED_JOKER] = 0
34 | }
35 | //增加记录器
36 | func (re *cardNameRecorder)AddPokerSet(playerPokers ...poker.PokerSet){
37 | re.Lock()
38 | defer re.Unlock()
39 | for _,pokerSet := range playerPokers{
40 | pokerSet.DoOnEachPokerCard(func(index int, card *poker.PokerCard){
41 | re.dic[card.GetCardName()]++
42 | })
43 | }
44 |
45 | }
46 | //更新玩家记牌器,玩家出牌后调用
47 | func (re *cardNameRecorder)RemovePokerSet(cards poker.PokerSet){
48 | re.Lock()
49 | defer re.Unlock()
50 | cards.DoOnEachPokerCard(func(index int,card *poker.PokerCard){
51 | re.dic[card.GetCardName()]--
52 | })
53 | }
54 | //根据牌的顺序从大到小排序的记牌器json对象
55 | func (re *cardNameRecorder) SequenceJsonEncode() string{
56 | re.Lock()
57 | defer re.Unlock()
58 | jsonString := ""
59 | jsonString += "{"
60 | jsonString += "'"+poker.CARD_SYMBOL_RED_JOKER+"'"+":"+strconv.Itoa(re.getPokerNum(poker.CARD_SYMBOL_RED_JOKER))
61 | jsonString += ","
62 | jsonString += "'"+poker.CARD_SYMBOL_BLACK_JOKER+"'"+":"+strconv.Itoa(re.getPokerNum(poker.CARD_SYMBOL_BLACK_JOKER))
63 | jsonString += ","
64 | jsonString += "'"+poker.CARD_SYMBOL_TWO+"'"+":"+strconv.Itoa(re.getPokerNum(poker.CARD_SYMBOL_TWO))
65 | jsonString += ","
66 | jsonString += "'"+poker.CARD_SYMBOL_ACE+"'"+":"+strconv.Itoa(re.getPokerNum(poker.CARD_SYMBOL_ACE))
67 | jsonString += ","
68 | jsonString += "'"+poker.CARD_SYMBOL_KING+"'"+":"+strconv.Itoa(re.getPokerNum(poker.CARD_SYMBOL_KING))
69 | jsonString += ","
70 | jsonString += "'"+poker.CARD_SYMBOL_QUEEN+"'"+":"+strconv.Itoa(re.getPokerNum(poker.CARD_SYMBOL_QUEEN))
71 | jsonString += ","
72 | jsonString += "'"+poker.CARD_SYMBOL_JACK+"'"+":"+strconv.Itoa(re.getPokerNum(poker.CARD_SYMBOL_JACK))
73 | jsonString += ","
74 | jsonString += "'"+poker.CARD_SYMBOL_TEN+"'"+":"+strconv.Itoa(re.getPokerNum(poker.CARD_SYMBOL_TEN))
75 | jsonString += ","
76 | jsonString += "'"+poker.CARD_SYMBOL_NINE+"'"+":"+strconv.Itoa(re.getPokerNum(poker.CARD_SYMBOL_NINE))
77 | jsonString += ","
78 | jsonString += "'"+poker.CARD_SYMBOL_EIGHT+"'"+":"+strconv.Itoa(re.getPokerNum(poker.CARD_SYMBOL_EIGHT))
79 | jsonString += ","
80 | jsonString += "'"+poker.CARD_SYMBOL_SEVEN+"'"+":"+strconv.Itoa(re.getPokerNum(poker.CARD_SYMBOL_SEVEN))
81 | jsonString += ","
82 | jsonString += "'"+poker.CARD_SYMBOL_SIX+"'"+":"+strconv.Itoa(re.getPokerNum(poker.CARD_SYMBOL_SIX))
83 | jsonString += ","
84 | jsonString += "'"+poker.CARD_SYMBOL_FIVE+"'"+":"+strconv.Itoa(re.getPokerNum(poker.CARD_SYMBOL_FIVE))
85 | jsonString += ","
86 | jsonString += "'"+poker.CARD_SYMBOL_FOUR+"'"+":"+strconv.Itoa(re.getPokerNum(poker.CARD_SYMBOL_FOUR))
87 | jsonString += ","
88 | jsonString += "'"+poker.CARD_SYMBOL_THREE+"'"+":"+strconv.Itoa(re.getPokerNum(poker.CARD_SYMBOL_THREE))
89 | jsonString += "}"
90 | return jsonString
91 | }
92 |
93 | func (re *cardNameRecorder) getPokerNum(key string) int{
94 | num,ok := re.dic[key]
95 | if ok {
96 | return num
97 | }else{
98 | return 0
99 | }
100 | }
101 |
102 |
103 |
--------------------------------------------------------------------------------
/doc.go:
--------------------------------------------------------------------------------
1 | package pokergame
2 |
3 | /*
4 | 该包实现一些常用游戏的牌型检测,记牌器,牌型分析器等功能
5 | 1.该包包含扑克牌、扑克集、扑克分析器、扑克记录器、扑克集分析器等概念的定义和实现
6 | 2.根据不同游戏类型,比如斗地主、保皇、升级、扎金花等等扑克牌游戏相关概念的实现,使用工厂模式产生对应的实体
7 | */
8 |
--------------------------------------------------------------------------------
/factory.go:
--------------------------------------------------------------------------------
1 | package pokergame
2 |
3 | import (
4 | "github.com/wqtapp/poker"
5 | )
6 |
7 | //定义扑克牌游戏的类型,用于获取适用于不同扑克牌的set和analayzer
8 | const (
9 | GAME_OF_LANDLORD = iota
10 | GAME_OF_ROYALIST
11 | GAME_OF_ZHAJINHUA
12 | GAME_OF_SHENGJI
13 | )
14 |
15 | type IRecorder interface {
16 | InitRecorder()
17 | AddPokerSet(playerPokers ...poker.PokerSet)
18 | RemovePokerSet(cards poker.PokerSet)
19 | SequenceJsonEncode() string
20 | }
21 |
22 | type IAnalyzer interface {
23 | InitAnalyzer()
24 | AddPokerSet(pokers poker.PokerSet)
25 | RemovePokerSet(pokers poker.PokerSet)
26 | GetMinPlayableCards() poker.PokerSet
27 | GetUseableCards(setType *SetInfo) []poker.PokerSet
28 |
29 | }
30 |
31 | type ISetChecker interface {
32 | GetSetInfo(set poker.PokerSet) (*SetInfo,error)
33 | }
34 |
35 | //获取适用于某一种游戏的扑克集
36 | func NewSetChecker(gameType int) ISetChecker{
37 | switch gameType {
38 | case GAME_OF_LANDLORD:
39 | landLordChecker := landLordChecker{}
40 | return &landLordChecker
41 | case GAME_OF_ROYALIST:
42 | case GAME_OF_SHENGJI:
43 | case GAME_OF_ZHAJINHUA:
44 | default:
45 | return nil
46 | }
47 | return nil
48 | }
49 | //获取适用于某一种游戏的扑克分析器
50 | func NewAnalyzer(gameType int) IAnalyzer{
51 | switch gameType {
52 | case GAME_OF_LANDLORD:
53 | analyzer := landLordAnalyzer{}
54 | analyzer.InitAnalyzer()
55 | return &analyzer
56 | case GAME_OF_ROYALIST:
57 | case GAME_OF_SHENGJI:
58 | case GAME_OF_ZHAJINHUA:
59 | default:
60 | return nil
61 | }
62 | return nil
63 | }
64 | //获取适用于某一种游戏的扑克记录器
65 | func NewRecorder(gameType int) IRecorder{
66 | switch gameType {
67 | case GAME_OF_LANDLORD:
68 | recorder := cardNameRecorder{}
69 | recorder.InitRecorder()
70 | return &recorder
71 | case GAME_OF_ROYALIST:
72 | case GAME_OF_SHENGJI:
73 | case GAME_OF_ZHAJINHUA:
74 | default:
75 | return nil
76 | }
77 | return nil
78 | }
79 |
80 |
81 |
--------------------------------------------------------------------------------
/setchecker_landlord_test.go:
--------------------------------------------------------------------------------
1 | package pokergame
2 |
3 | import (
4 | "testing"
5 | "reflect"
6 | "strconv"
7 | "github.com/wqtapp/poker"
8 | "fmt"
9 | )
10 |
11 | var dec poker.PokerDeck
12 |
13 | func init(){
14 | dec = poker.CreateDeck()
15 | }
16 |
17 | type Check struct{
18 | setStr []string //牌型字符串
19 | isTrue bool //是否检测的类型
20 | setType int //扑克集类型
21 | }
22 |
23 | func checkBool(t *testing.T,c []Check,funcName string){
24 | for i := range c{
25 | set := getPokerset(c[i].setStr)
26 | setInfo := reflect.ValueOf(&landLordChecker{})
27 | method := setInfo.MethodByName(funcName)
28 | if method.String() == ""{
29 | t.Error("no this func "+funcName)
30 | }else{
31 | params := make([]reflect.Value, 1) // 参数
32 | params[0] = reflect.ValueOf(set) // 参数设置为20
33 | res := method.Call(params)
34 | if res[0].Interface().(bool) != c[i].isTrue{
35 | t.Error(funcName+strconv.Itoa(i))
36 | }
37 | }
38 | }
39 | }
40 |
41 | func checkBoolWithType(t *testing.T,c []Check,funcName string){
42 | for i := range c{
43 | set := getPokerset(c[i].setStr)
44 | setInfo := reflect.ValueOf(landLordChecker{})
45 | fmt.Println(setInfo.NumMethod())
46 | return
47 | method := setInfo.MethodByName(funcName)
48 | if method.String() == ""{
49 | t.Error("no this func "+funcName)
50 | }else{
51 | params := make([]reflect.Value, 1) // 参数
52 | params[0] = reflect.ValueOf(set)
53 | res := method.Call(params)
54 | tempBool := false
55 | if res[1].Interface() == nil{
56 | tempBool = true
57 | }
58 |
59 | if tempBool != c[i].isTrue {
60 | t.Error(funcName+" err"+strconv.Itoa(i))
61 | }else{
62 |
63 | if !c[i].isTrue{
64 | continue
65 | }
66 |
67 | if res[0].Interface() != nil{
68 | setTypeInfo,ok := res[0].Interface().(*SetInfo)
69 | if ok{
70 | if setTypeInfo == nil || setTypeInfo.setType != c[i].setType{
71 | if setTypeInfo == nil{
72 | t.Error(funcName+" typeInfo nil"+strconv.Itoa(i))
73 | }else{
74 | t.Error(funcName+" typeInfo "+strconv.Itoa(setTypeInfo.setType)+" "+strconv.Itoa(i))
75 | }
76 | }
77 | }else{
78 | t.Error(funcName+" typeInfo "+strconv.Itoa(setTypeInfo.setType)+" "+strconv.Itoa(i))
79 | }
80 | }else{
81 | t.Error(funcName+" typeInfo result nil"+strconv.Itoa(i))
82 | }
83 | }
84 | }
85 | }
86 | }
87 |
88 | //根据传入的字符数组,生成相应的扑克集,便于写测试用例
89 | //此处不区分花色
90 | func getPokerset(setString []string) poker.PokerSet{
91 | set := poker.PokerSet{}
92 | for _,name := range setString{
93 | for i,card := range dec.GetAllCards(){
94 | if card.GetCardName() == name{
95 | set = append(set,dec.GetCard(i))
96 | break
97 | }
98 | }
99 | }
100 | return set
101 | }
102 | //先测试生成扑克集的正确性
103 | func TestPokerSet_GetPokerset(t *testing.T){
104 | test := []string{"3","4","5"}
105 | set := getPokerset(test)
106 | if set[0].GetCardName() != test[0]{
107 | t.Error("pokerset creator err")
108 | }
109 |
110 | if set[1].GetCardName() != test[1]{
111 | t.Error("pokerset creator err")
112 | }
113 |
114 | if set[2].GetCardName() != test[2]{
115 | t.Error("pokerset creator err")
116 | }
117 |
118 | }
119 |
120 | func TestPokerSet_GetSetTypeInfo(t *testing.T) {
121 | checks := []Check{
122 | {[]string{"3"}, true, LANDLORD_SET_TYPE_SINGLE},
123 | {[]string{"3", "3"}, true, LANDLORD_SET_TYPE_PAIR},
124 | {[]string{"3", "3", "4", "4", "5", "5"}, true, LANDLORD_SET_TYPE_MULIT_PAIRS},
125 | {[]string{"3", "3", "3"}, true, LANDLORD_SET_TYPE_THREE},
126 | {[]string{"3", "3", "3", "4"}, true, LANDLORD_SET_TYPE_THREE_PLUS_ONE},
127 | {[]string{"3", "3", "3", "4", "4"}, true, LANDLORD_SET_TYPE_THREE_PLUS_TWO},
128 | {[]string{"3", "3", "3", "4", "4", "4"}, true, LANDLORD_SET_TYPE_MULITY_THREE},
129 | {[]string{"3", "3", "3", "4", "4", "4", "5", "6"}, true, LANDLORD_SET_TYPE_MULITY_THREE_PLUS_ONE},
130 | {[]string{"3", "3", "3", "4", "4", "4", "5", "5","5","7","7","7"}, true, LANDLORD_SET_TYPE_MULITY_THREE_PLUS_ONE},
131 | {[]string{"3", "3", "3", "4", "4", "4", "5", "6", "5", "6"}, true, LANDLORD_SET_TYPE_MULITY_THREE_PLUS_TWO},
132 | {[]string{"3", "3", "3", "4", "4", "4", "5", "5", "5", "5"}, true, LANDLORD_SET_TYPE_MULITY_THREE_PLUS_TWO},
133 |
134 | {[]string{"3", "3", "3", "3"}, true, LANDLORD_SET_TYPE_COMMON_BOMB},
135 | {[]string{"3", "3", "3", "3", "4", "5"}, true, LANDLORD_SET_TYPE_FOUR_PLUS_TWO},
136 | {[]string{"3", "3", "3", "3", "4", "4", "5", "5"}, true, LANDLORD_SET_TYPE_FOUR_PLUS_FOUR},
137 | {[]string{"3", "3", "3", "3", "5", "5", "5", "5"}, true, LANDLORD_SET_TYPE_FOUR_PLUS_FOUR},
138 | {[]string{"3", "3", "3", "3", "4", "4", "4", "4"}, true, LANDLORD_SET_TYPE_MULITY_FOUR},
139 | {[]string{"3", "3", "3", "3", "4", "4", "4", "4", "5", "6", "7", "8"}, true, LANDLORD_SET_TYPE_MULITY_FOUR_PLUS_TWO},
140 | {[]string{"3", "3", "3", "3", "4", "4", "4", "4", "5", "5", "7", "8"}, true, LANDLORD_SET_TYPE_MULITY_FOUR_PLUS_TWO},
141 | {[]string{"3", "3", "3", "3", "4", "4", "4", "4", "5", "5", "6", "6", "7", "7", "8", "8"}, true, LANDLORD_SET_TYPE_MULITY_FOUR_PLUS_FOUR},
142 |
143 | {[]string{"3", "4", "5", "6", "7", "8"}, true, LANDLORD_SET_TYPE_DRAGON},
144 | {[]string{"BlackJoker", "RedJoker"}, true, LANDLORD_SET_TYPE_JOKER_BOMB},
145 | }
146 |
147 | checkBoolWithType(t, checks, "GetSetInfo")
148 | }
--------------------------------------------------------------------------------
/setchecker_lanlord.go:
--------------------------------------------------------------------------------
1 | package pokergame
2 |
3 | import
4 | (
5 | "errors"
6 | "github.com/wqtapp/poker"
7 | )
8 |
9 | type landLordChecker struct {
10 |
11 | }
12 | func (self landLordChecker) GetSetInfo(set poker.PokerSet) (*SetInfo,error) {
13 | switch set.CountCards() {
14 | case 0:
15 | return nil,errors.New("玩家出牌为空")
16 | //单张
17 | case 1:
18 | return NewSetInfo(LANDLORD_SET_TYPE_SINGLE,set[0].GetValue(),set[0].GetValue()),nil
19 | //对子或者王炸
20 | case 2:
21 | if self.isPair(set){
22 | return NewSetInfo(LANDLORD_SET_TYPE_PAIR,set[0].GetValue(),set[0].GetValue()),nil
23 | }
24 |
25 | if self.isJokerBomb(set){
26 | return NewSetInfo(LANDLORD_SET_TYPE_JOKER_BOMB,set[0].GetValue(),set[1].GetValue()),nil
27 | }
28 |
29 | return nil,errors.New("牌型不符合规则")
30 | //三张
31 | case 3:
32 | return self.checkThreePlus(set)
33 | //炸弹或三带一
34 | case 4:
35 | if self.isCommonBomb(set){
36 | return NewSetInfo(LANDLORD_SET_TYPE_COMMON_BOMB,set[0].GetValue(),set[0].GetValue()),nil
37 | }
38 | return self.checkThreePlus(set)
39 | //三带二或者一条龙
40 | case 5:
41 | if self.isDragon(set){
42 | return NewSetInfo(LANDLORD_SET_TYPE_DRAGON,set[0].GetValue(),set[set.CountCards()-1].GetValue()),nil
43 | }
44 | return self.checkThreePlus(set)
45 | //一条龙,或者四带二,或者四带二对
46 | default:
47 | if self.isDragon(set){
48 | return NewSetInfo(LANDLORD_SET_TYPE_DRAGON,set[0].GetValue(),set[set.CountCards()-1].GetValue()),nil
49 | }
50 |
51 | if self.isMultiPair(set){
52 | return NewSetInfo(LANDLORD_SET_TYPE_MULIT_PAIRS,set[0].GetValue(),set[set.CountCards()-1].GetValue()),nil
53 | }
54 |
55 | if cardsType,err := self.checkFourPlus(set);err == nil{
56 | return cardsType,err
57 | }else if cardsType,err := self.checkMultiFourPlus(set);err == nil{
58 | return cardsType,err
59 | }else{
60 | return self.checkMultiThreePlus(set)
61 | }
62 | }
63 | }
64 |
65 | func (self landLordChecker) isPair(set poker.PokerSet) bool{
66 | if set.CountCards() != 2 {
67 | return false
68 | }
69 |
70 | if(set[0].GetValue() == set[1].GetValue()){
71 | return true
72 | }
73 | return false
74 | }
75 |
76 | func (self landLordChecker) isMultiPair(set poker.PokerSet) bool{
77 | if set.CountCards()%2 != 0 || len(set) < 6 {
78 | return false
79 | }
80 |
81 | set.SortAsc()
82 | //2和王不能作为连对出牌
83 | if set[set.CountCards()-1].GetValue() >= poker.CARD_VALUE_TWO{
84 | return false
85 | }
86 |
87 | currValue := -1
88 |
89 | for i,card := range set{
90 | if i == 0 {
91 | currValue = card.GetValue()
92 | }else{
93 | if i % 2 == 1{
94 | if card.GetValue() != currValue{
95 | return false
96 | }
97 | }else{
98 | if card.GetValue() == currValue+1{
99 | currValue=card.GetValue()
100 | }else{
101 | return false
102 | }
103 | }
104 | }
105 | }
106 | return true
107 | }
108 |
109 | func (self landLordChecker) isJokerBomb(set poker.PokerSet) bool{
110 | if set.CountCards() != 2{
111 | return false
112 | }
113 | set.SortAsc()
114 | if(set[0].GetValue() == poker.CARD_VALUE_BLACK_JOKER && set[1].GetValue() == poker.CARD_VALUE_RED_JOKER){
115 | return true
116 | }else{
117 |
118 | }
119 | return false
120 | }
121 |
122 | func (self landLordChecker) isCommonBomb(set poker.PokerSet) bool{
123 | if set.CountCards() != 4{
124 | return false
125 | }
126 | if set[0].GetValue() == set[1].GetValue() && set[2].GetValue() == set[3].GetValue() &&
127 | set[0].GetValue() == set[2].GetValue(){
128 | return true
129 | }else{
130 | return false
131 | }
132 | }
133 |
134 | func (self landLordChecker) isDragon(set poker.PokerSet) bool{
135 | if len(set) < 5 {
136 | return false
137 | }
138 |
139 | set.SortAsc()
140 | //2和王不能参与顺子出牌
141 | if set[set.CountCards()-1].GetValue() >= poker.CARD_VALUE_TWO{
142 | return false
143 | }
144 |
145 | tempValue := -1
146 | for i,card := range set{
147 | if i == 0 {
148 | tempValue = card.GetValue()
149 | }else{
150 | if card.GetValue() == tempValue+1{
151 | tempValue = card.GetValue()
152 | }else{
153 | return false
154 | }
155 | }
156 | }
157 | return true
158 | }
159 |
160 | func (self landLordChecker) checkThreePlus(set poker.PokerSet) (*SetInfo,error){
161 | pokersNum := set.CountCards()
162 | if pokersNum < 3 || pokersNum >5{
163 | return nil,errors.New("不是三带牌")
164 | }
165 |
166 | set.SortAsc()
167 | cardNum := set.AnalyzeEachCardValueNum()
168 | cardNumCount := len(cardNum)
169 | if pokersNum == 3{
170 | if cardNumCount == 1{
171 | return NewSetInfo(LANDLORD_SET_TYPE_THREE,set[0].GetValue(),set[0].GetValue()),nil
172 | }else{
173 | return nil,errors.New("不是三带牌")
174 | }
175 | }else{
176 | if cardNumCount == 2 {
177 |
178 | for k,v := range cardNum{
179 | if v == 3{
180 | if(pokersNum == 4){
181 | return NewSetInfo(LANDLORD_SET_TYPE_THREE_PLUS_ONE,k,k),nil
182 | }else{
183 | return NewSetInfo(LANDLORD_SET_TYPE_THREE_PLUS_TWO,k,k),nil
184 | }
185 | }
186 | }
187 | return nil,errors.New("不是三带牌")
188 | }else{
189 | return nil,errors.New("不是三带牌")
190 | }
191 | }
192 | }
193 |
194 | //是否是四代一或者四代二
195 | func (self landLordChecker) checkFourPlus(set poker.PokerSet) (*SetInfo,error){
196 |
197 | pokersNum := set.CountCards()
198 | if pokersNum != 6 && pokersNum != 8{
199 | return nil,errors.New("不是四带牌")
200 | }
201 |
202 | set.SortAsc()
203 |
204 | cardNum := set.AnalyzeEachCardValueNum()
205 | cardNumCount := len(cardNum)
206 | if cardNumCount == 2{
207 | k1 := -1
208 | v1 := -1
209 | k2 := -1
210 | v2 := -1
211 | i := 1
212 | for k,v := range cardNum{
213 | if i == 1{
214 | k1 = k
215 | v1 = v
216 | }else{
217 | k2 = k
218 | v2 = v
219 | }
220 | i++
221 | }
222 |
223 | if pokersNum == 6{
224 | //支持444455这种四带二
225 | if v1 == 4{
226 | return NewSetInfo(LANDLORD_SET_TYPE_FOUR_PLUS_TWO,k1,k1),nil
227 | }else if v2 == 4{
228 | return NewSetInfo(LANDLORD_SET_TYPE_FOUR_PLUS_TWO,k2,k2),nil
229 | }else{
230 | return nil,errors.New("不是四带牌")
231 | }
232 | }else{
233 | //不支持44445555这种连续四带四的牌,因为没法判断是四带四还是多连四
234 | //支持44446666这种牌型,以大的作为主牌,即四个6带两对4
235 | if v1 == 4 && k1 != k2+1 && k2 != k1+1{
236 | k := -1
237 | if k1 > k2 {
238 | k = k1
239 | }else{
240 | k = k2
241 | }
242 | return NewSetInfo(LANDLORD_SET_TYPE_FOUR_PLUS_FOUR,k,k),nil
243 | }else{
244 | return nil,errors.New("不是四带牌")
245 | }
246 | }
247 | }else if cardNumCount == 3{
248 | mainValue := -1
249 | for k,v := range cardNum{
250 | if v == 4 {
251 | mainValue = k
252 | }
253 | if pokersNum == 6{
254 | if v == 2 || v == 3 || v == 5 || v == 6{
255 | return nil,errors.New("不是四带牌")
256 | }
257 | }else{
258 | if v == 1 || v == 3 || v == 5 || v == 6 {
259 | return nil,errors.New("不是四带牌")
260 | }
261 | }
262 | }
263 | if mainValue == -1{
264 | return nil,errors.New("不是四带牌")
265 | }else{
266 | if pokersNum == 6 {
267 | //四带二444456这种
268 | return NewSetInfo(LANDLORD_SET_TYPE_FOUR_PLUS_TWO,mainValue,mainValue),nil
269 | }else{
270 | //四带四44445566这种
271 | return NewSetInfo(LANDLORD_SET_TYPE_FOUR_PLUS_FOUR,mainValue,mainValue),nil
272 | }
273 | }
274 | } else{
275 | return nil,errors.New("不是四带牌")
276 | }
277 | }
278 |
279 | //是否多个三带一,或三代二,或不带
280 | func (self landLordChecker) checkMultiThreePlus(set poker.PokerSet) (*SetInfo,error){
281 | pokerNum := set.CountCards()
282 | if pokerNum < 6 {
283 | return nil,errors.New("不是三顺")
284 | }
285 |
286 | set.SortAsc()
287 | cardNum := set.AnalyzeEachCardValueNum()
288 |
289 | //mainCardValue := -1 //暂存主牌的value,用于比较是否连续
290 | //mainCardNum := 0 //主牌的数量
291 | mainCardValues := []int{} //存放主牌的值
292 | attachCardNum := 0 //附牌的数量
293 | attachCardNumMap := make(map[int]int) //附牌的value和num的map
294 |
295 | for k,v := range cardNum{
296 | if v == 3{
297 | mainCardValues = append(mainCardValues,k)
298 | }else{
299 | attachCardNumMap[k] = v
300 | attachCardNum += v
301 | }
302 | }
303 | BubbleSortIntMin2Max(mainCardValues)
304 | //只包含连续的主牌的数量,不连续的同数量的当做附牌对待
305 | realMainCardValues := []int{}
306 | //主牌连续,且只有一个连续的,其他的间断连续作为附牌处理
307 | for i,value := range mainCardValues{
308 | if i < len(mainCardValues)-1 && mainCardValues[i] + 1 == mainCardValues[i+1]{
309 | if len(realMainCardValues) > 0 && value == realMainCardValues[len(realMainCardValues)-1]+1{
310 | realMainCardValues = append(realMainCardValues,value)
311 | }else if len(realMainCardValues) == 0{
312 | realMainCardValues = append(realMainCardValues,value)
313 | }else{
314 | attachCardNumMap[value] = 3
315 | attachCardNum += 3
316 | }
317 | }else if i > 0 && mainCardValues[i] == mainCardValues[i-1]+1{
318 | if len(realMainCardValues) > 0 && value == realMainCardValues[len(realMainCardValues)-1]+1{
319 | realMainCardValues = append(realMainCardValues,value)
320 | }else if len(realMainCardValues) == 0{
321 | realMainCardValues = append(realMainCardValues,value)
322 | }else{
323 | attachCardNumMap[value] = 3
324 | attachCardNum += 3
325 | }
326 | }else{//该值的牌作为附牌对待
327 | attachCardNumMap[value] = 3
328 | attachCardNum += 3
329 | }
330 | }
331 |
332 | mainCardNum := len(realMainCardValues)
333 | if mainCardNum < 2 {//未构成连续牌型
334 | return nil,errors.New("不是三顺")
335 | }
336 |
337 | //2和王不能参与连顺
338 | if mainCardNum > 1 && realMainCardValues[len(realMainCardValues)-1] > poker.CARD_VALUE_ACE{
339 | return nil,errors.New("不是三顺")
340 | }
341 |
342 | //没有附牌
343 | if attachCardNum == 0{
344 | return NewSetInfo(LANDLORD_SET_TYPE_MULITY_THREE,realMainCardValues[0],realMainCardValues[len(realMainCardValues)-1]),nil
345 | }else if mainCardNum == attachCardNum{//三带一
346 | return NewSetInfo(LANDLORD_SET_TYPE_MULITY_THREE_PLUS_ONE,realMainCardValues[0],realMainCardValues[len(realMainCardValues)-1]),nil
347 | }else if mainCardNum*2 == attachCardNum{//三带二
348 | for _,v := range attachCardNumMap{
349 | if v != 2 && v != 4{
350 | return nil,errors.New("不是三顺")
351 | }
352 | }
353 | return NewSetInfo(LANDLORD_SET_TYPE_MULITY_THREE_PLUS_TWO,realMainCardValues[0],realMainCardValues[len(realMainCardValues)-1]),nil
354 | }else{
355 | return nil,errors.New("不是三顺")
356 | }
357 | }
358 |
359 | //是否多个四带一或四代二,或不带
360 | func (self landLordChecker) checkMultiFourPlus(set poker.PokerSet) (*SetInfo,error){
361 |
362 | pokerNum := set.CountCards()
363 | if pokerNum < 8 || pokerNum%2 != 0 {
364 | return nil,errors.New("不是四顺")
365 | }
366 |
367 | set.SortAsc()
368 | cardNum := set.AnalyzeEachCardValueNum()
369 |
370 | //mainCardValue := -1 //暂存主牌的value,用于比较是否连续
371 | //mainCardNum := 0 //主牌的数量
372 | mainCardValues := []int{} //存放主牌的值
373 | attachCardNum := 0 //附牌的数量
374 | attachCardNumMap := make(map[int]int) //附牌的value和num的map
375 |
376 | for k,v := range cardNum{
377 | if v == 4{
378 | mainCardValues = append(mainCardValues,k)
379 | }else{
380 | attachCardNumMap[k] = v
381 | attachCardNum += v
382 | }
383 | }
384 | BubbleSortIntMin2Max(mainCardValues)
385 |
386 | //只包含连续的主牌的数量,不连续的同数量的当做附牌对待
387 | realMainCardValues := []int{}
388 | //主牌连续,且只有一个连续的,其他的间断连续作为附牌处理
389 | for i,value := range mainCardValues{
390 | if i < len(mainCardValues)-1 && mainCardValues[i] + 1 == mainCardValues[i+1]{
391 | if len(realMainCardValues) > 0 && value == realMainCardValues[len(realMainCardValues)-1]+1{
392 | realMainCardValues = append(realMainCardValues,value)
393 | }else if len(realMainCardValues) == 0{
394 | realMainCardValues = append(realMainCardValues,value)
395 | }else{
396 | attachCardNumMap[value] = 4
397 | attachCardNum += 4
398 | }
399 | }else if i > 0 && mainCardValues[i] == mainCardValues[i-1]+1{
400 | if len(realMainCardValues) > 0 && value == realMainCardValues[len(realMainCardValues)-1]+1{
401 | realMainCardValues = append(realMainCardValues,value)
402 | }else if len(realMainCardValues) == 0{
403 | realMainCardValues = append(realMainCardValues,value)
404 | }else{
405 | attachCardNumMap[value] = 4
406 | attachCardNum += 4
407 | }
408 | }else{//该值的牌作为附牌对待
409 | attachCardNumMap[value] = 4
410 | attachCardNum += 4
411 | }
412 | }
413 |
414 | mainCardNum := len(realMainCardValues)
415 | for mainCardNum < 2{
416 | return nil,errors.New("不是四顺")
417 | }
418 |
419 | //2和王不能参与连顺
420 | if mainCardNum > 1 && realMainCardValues[len(realMainCardValues)-1] > poker.CARD_VALUE_ACE{
421 | return nil,errors.New("不是四顺")
422 | }
423 |
424 | //没有附牌
425 | if attachCardNum == 0{//四不带
426 | return NewSetInfo(LANDLORD_SET_TYPE_MULITY_FOUR,realMainCardValues[0],realMainCardValues[len(realMainCardValues)-1]),nil
427 | }else if mainCardNum*2 == attachCardNum{//四带二
428 | return NewSetInfo(LANDLORD_SET_TYPE_MULITY_FOUR_PLUS_TWO,realMainCardValues[0],realMainCardValues[len(realMainCardValues)-1]),nil
429 | }else if mainCardNum*4 == attachCardNum{//四带四
430 | for _,v := range attachCardNumMap{
431 | if v != 2 && v != 4{
432 | return nil,errors.New("不是四顺")
433 | }
434 | }
435 | return NewSetInfo(LANDLORD_SET_TYPE_MULITY_FOUR_PLUS_FOUR,realMainCardValues[0],realMainCardValues[len(realMainCardValues)-1]),nil
436 | }else{
437 | return nil,errors.New("不是四顺")
438 | }
439 | }
--------------------------------------------------------------------------------
/setinfo.go:
--------------------------------------------------------------------------------
1 | package pokergame
2 |
3 | const(
4 | LANDLORD_SET_TYPE_SINGLE = iota //"单牌"
5 | LANDLORD_SET_TYPE_DRAGON //"单顺子(5个及以上)"
6 |
7 | LANDLORD_SET_TYPE_PAIR //"对牌"
8 | LANDLORD_SET_TYPE_MULIT_PAIRS //"双顺子(3个及以上)"
9 |
10 | LANDLORD_SET_TYPE_THREE //三张不带牌
11 | LANDLORD_SET_TYPE_THREE_PLUS_ONE //三带一
12 | LANDLORD_SET_TYPE_THREE_PLUS_TWO //三带二
13 | LANDLORD_SET_TYPE_MULITY_THREE //3顺子不带牌
14 | LANDLORD_SET_TYPE_MULITY_THREE_PLUS_ONE //3顺子带1个牌
15 | LANDLORD_SET_TYPE_MULITY_THREE_PLUS_TWO //3顺子带2个牌
16 |
17 | LANDLORD_SET_TYPE_FOUR_PLUS_TWO //四带2张
18 | LANDLORD_SET_TYPE_FOUR_PLUS_FOUR //四带2对
19 | LANDLORD_SET_TYPE_MULITY_FOUR //四顺子不带牌
20 | LANDLORD_SET_TYPE_MULITY_FOUR_PLUS_TWO //四顺子带2张
21 | LANDLORD_SET_TYPE_MULITY_FOUR_PLUS_FOUR //四顺子带4张
22 |
23 | LANDLORD_SET_TYPE_COMMON_BOMB // "炸弹"
24 | LANDLORD_SET_TYPE_JOKER_BOMB // "王炸"
25 | )
26 |
27 | func GetPokerSetTypeName(pattern int) string {
28 | switch pattern {
29 | case LANDLORD_SET_TYPE_SINGLE:
30 | return "单牌"
31 | case LANDLORD_SET_TYPE_DRAGON:
32 | return "单顺子"
33 | case LANDLORD_SET_TYPE_PAIR:
34 | return "对牌"
35 | case LANDLORD_SET_TYPE_MULIT_PAIRS:
36 | return "双顺子"
37 | case LANDLORD_SET_TYPE_THREE:
38 | return "三张牌"
39 | case LANDLORD_SET_TYPE_THREE_PLUS_ONE:
40 | return "三带一"
41 | case LANDLORD_SET_TYPE_THREE_PLUS_TWO:
42 | return "三带二"
43 | case LANDLORD_SET_TYPE_MULITY_THREE:
44 | return "三顺子不带牌"
45 | case LANDLORD_SET_TYPE_MULITY_THREE_PLUS_ONE:
46 | return "三顺子带一张"
47 | case LANDLORD_SET_TYPE_MULITY_THREE_PLUS_TWO:
48 | return "三顺子带两张"
49 | case LANDLORD_SET_TYPE_FOUR_PLUS_TWO:
50 | return "四带二"
51 | case LANDLORD_SET_TYPE_FOUR_PLUS_FOUR:
52 | return "四带四"
53 | case LANDLORD_SET_TYPE_MULITY_FOUR:
54 | return "四顺子不带牌"
55 | case LANDLORD_SET_TYPE_MULITY_FOUR_PLUS_TWO:
56 | return "四顺子带两张"
57 | case LANDLORD_SET_TYPE_MULITY_FOUR_PLUS_FOUR:
58 | return "四顺子带四张"
59 | case LANDLORD_SET_TYPE_COMMON_BOMB:
60 | return "炸弹"
61 | case LANDLORD_SET_TYPE_JOKER_BOMB:
62 | return "火箭"
63 | default:
64 | return "未定义的牌型"
65 | }
66 | }
67 |
68 | type SetInfo struct{
69 | setType int
70 | cardValueMinAndMax map[string]int
71 | }
72 |
73 | func NewSetInfo(setType int,minValue int,maxValue int) *SetInfo {
74 | setInfo := SetInfo{
75 | setType: setType,
76 | cardValueMinAndMax: make(map[string]int),
77 | }
78 | setInfo.cardValueMinAndMax["min"] = minValue
79 | setInfo.cardValueMinAndMax["max"] = maxValue
80 | return &setInfo
81 | }
82 |
83 | func (setInfo *SetInfo)GetRangeWidth() int{
84 | return setInfo.cardValueMinAndMax["max"] - setInfo.cardValueMinAndMax["min"]+1
85 | }
86 | func (setInfo *SetInfo)GetSetType() int{
87 | return setInfo.setType
88 | }
89 | func (setInfo *SetInfo)GetSetTypeName() string{
90 | return GetPokerSetTypeName(setInfo.setType)
91 | }
92 | func (setInfo *SetInfo)GetMinValue() int{
93 | return setInfo.cardValueMinAndMax["min"]
94 | }
95 | func (setInfo *SetInfo)GetMaxValue() int{
96 | return setInfo.cardValueMinAndMax["max"]
97 | }
98 |
--------------------------------------------------------------------------------
/sorts.go:
--------------------------------------------------------------------------------
1 | package pokergame
2 | //冒泡排序法对整数排序
3 | func BubbleSortIntMin2Max(ints []int){
4 | length := len(ints)
5 | for i :=0;i ints[j]{
8 | ints[i],ints[j] = ints[j],ints[i]
9 | }
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/sorts_test.go:
--------------------------------------------------------------------------------
1 | package pokergame
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestBubbleSortIntMin2Max(t *testing.T) {
8 | ints := []int{1,3,5,4,6,2}
9 | BubbleSortIntMin2Max(ints)
10 | if ints[0] != 1 ||
11 | ints[1] != 2 ||
12 | ints[2] != 3 ||
13 | ints[3] != 4 ||
14 | ints[4] != 5 ||
15 | ints[5] != 6{
16 | t.Error("TestBubbleSortIntMin2Max err")
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------