guandan.dev

guandan.dev

https://git.tonybtw.com/guandan.dev.git git://git.tonybtw.com/guandan.dev.git
9,275 bytes raw
1
package game
2
3
type Combination_Type int
4
5
const (
6
	Comb_Invalid Combination_Type = iota
7
	Comb_Single
8
	Comb_Pair
9
	Comb_Triple
10
	Comb_Full_House
11
	Comb_Straight
12
	Comb_Tube
13
	Comb_Plate
14
	Comb_Bomb
15
)
16
17
type Combination struct {
18
	Type       Combination_Type
19
	Cards      []Card
20
	Rank_Value int
21
	Bomb_Power int
22
}
23
24
func Detect_Combination(cards []Card, level Rank) Combination {
25
	n := len(cards)
26
	if n == 0 {
27
		return Combination{Type: Comb_Invalid}
28
	}
29
30
	non_wild, wild := separate_wilds(cards, level)
31
32
	if bomb := detect_bomb(cards, level); bomb.Type == Comb_Bomb {
33
		return bomb
34
	}
35
36
	switch n {
37
	case 1:
38
		return detect_single(non_wild, wild, level)
39
	case 2:
40
		return detect_pair(non_wild, wild, level)
41
	case 3:
42
		return detect_triple(non_wild, wild, level)
43
	case 5:
44
		if comb := detect_full_house(non_wild, wild, level); comb.Type != Comb_Invalid {
45
			return comb
46
		}
47
		return detect_straight(non_wild, wild, level)
48
	case 6:
49
		if comb := detect_tube(non_wild, wild, level); comb.Type != Comb_Invalid {
50
			return comb
51
		}
52
		return detect_plate(non_wild, wild, level)
53
	}
54
55
	return Combination{Type: Comb_Invalid}
56
}
57
58
func separate_wilds(cards []Card, level Rank) ([]Card, []Card) {
59
	var non_wild, wild []Card
60
	for _, c := range cards {
61
		if Is_Wild(c, level) {
62
			wild = append(wild, c)
63
		} else {
64
			non_wild = append(non_wild, c)
65
		}
66
	}
67
	return non_wild, wild
68
}
69
70
func detect_single(non_wild, wild []Card, level Rank) Combination {
71
	if len(non_wild) == 1 && len(wild) == 0 {
72
		return Combination{
73
			Type:       Comb_Single,
74
			Cards:      non_wild,
75
			Rank_Value: card_value(non_wild[0], level),
76
		}
77
	}
78
	if len(non_wild) == 0 && len(wild) == 1 {
79
		return Combination{
80
			Type:       Comb_Single,
81
			Cards:      wild,
82
			Rank_Value: card_value(wild[0], level),
83
		}
84
	}
85
	return Combination{Type: Comb_Invalid}
86
}
87
88
func detect_pair(non_wild, wild []Card, level Rank) Combination {
89
	total := len(non_wild) + len(wild)
90
	if total != 2 {
91
		return Combination{Type: Comb_Invalid}
92
	}
93
94
	if len(non_wild) == 2 {
95
		if non_wild[0].Rank == non_wild[1].Rank {
96
			return Combination{
97
				Type:       Comb_Pair,
98
				Cards:      append(non_wild, wild...),
99
				Rank_Value: card_value(non_wild[0], level),
100
			}
101
		}
102
		return Combination{Type: Comb_Invalid}
103
	}
104
105
	if len(non_wild) == 1 && len(wild) == 1 {
106
		return Combination{
107
			Type:       Comb_Pair,
108
			Cards:      append(non_wild, wild...),
109
			Rank_Value: card_value(non_wild[0], level),
110
		}
111
	}
112
113
	if len(wild) == 2 {
114
		return Combination{
115
			Type:       Comb_Pair,
116
			Cards:      wild,
117
			Rank_Value: card_value(wild[0], level),
118
		}
119
	}
120
121
	return Combination{Type: Comb_Invalid}
122
}
123
124
func detect_triple(non_wild, wild []Card, level Rank) Combination {
125
	total := len(non_wild) + len(wild)
126
	if total != 3 {
127
		return Combination{Type: Comb_Invalid}
128
	}
129
130
	rank_counts := count_ranks(non_wild)
131
132
	for rank, count := range rank_counts {
133
		needed := 3 - count
134
		if needed <= len(wild) {
135
			return Combination{
136
				Type:       Comb_Triple,
137
				Cards:      append(non_wild, wild...),
138
				Rank_Value: rank_value(rank, level),
139
			}
140
		}
141
	}
142
143
	if len(wild) == 3 {
144
		return Combination{
145
			Type:       Comb_Triple,
146
			Cards:      wild,
147
			Rank_Value: card_value(wild[0], level),
148
		}
149
	}
150
151
	return Combination{Type: Comb_Invalid}
152
}
153
154
func detect_full_house(non_wild, wild []Card, level Rank) Combination {
155
	total := len(non_wild) + len(wild)
156
	if total != 5 {
157
		return Combination{Type: Comb_Invalid}
158
	}
159
160
	rank_counts := count_ranks(non_wild)
161
	wilds_available := len(wild)
162
163
	var triple_rank Rank = -1
164
	var pair_rank Rank = -1
165
166
	ranks := sorted_ranks(rank_counts, level)
167
168
	for _, rank := range ranks {
169
		count := rank_counts[rank]
170
		if count >= 3 && triple_rank == -1 {
171
			triple_rank = rank
172
		} else if count >= 2 && pair_rank == -1 && triple_rank != rank {
173
			pair_rank = rank
174
		}
175
	}
176
177
	if triple_rank != -1 && pair_rank != -1 {
178
		return Combination{
179
			Type:       Comb_Full_House,
180
			Cards:      append(non_wild, wild...),
181
			Rank_Value: rank_value(triple_rank, level),
182
		}
183
	}
184
185
	for _, rank := range ranks {
186
		count := rank_counts[rank]
187
		needed_for_triple := 3 - count
188
		if needed_for_triple <= wilds_available {
189
			remaining_wilds := wilds_available - needed_for_triple
190
			for _, other_rank := range ranks {
191
				if other_rank == rank {
192
					continue
193
				}
194
				other_count := rank_counts[other_rank]
195
				needed_for_pair := 2 - other_count
196
				if needed_for_pair <= remaining_wilds {
197
					return Combination{
198
						Type:       Comb_Full_House,
199
						Cards:      append(non_wild, wild...),
200
						Rank_Value: rank_value(rank, level),
201
					}
202
				}
203
			}
204
			if remaining_wilds >= 2 {
205
				return Combination{
206
					Type:       Comb_Full_House,
207
					Cards:      append(non_wild, wild...),
208
					Rank_Value: rank_value(rank, level),
209
				}
210
			}
211
		}
212
	}
213
214
	return Combination{Type: Comb_Invalid}
215
}
216
217
func detect_straight(non_wild, wild []Card, level Rank) Combination {
218
	total := len(non_wild) + len(wild)
219
	if total != 5 {
220
		return Combination{Type: Comb_Invalid}
221
	}
222
223
	for _, card := range non_wild {
224
		if card.Rank == Rank_Black_Joker || card.Rank == Rank_Red_Joker {
225
			return Combination{Type: Comb_Invalid}
226
		}
227
	}
228
229
	rank_counts := count_ranks(non_wild)
230
	wilds_available := len(wild)
231
232
	natural_order := []Rank{
233
		Rank_Ace, Rank_Two, Rank_Three, Rank_Four, Rank_Five,
234
		Rank_Six, Rank_Seven, Rank_Eight, Rank_Nine, Rank_Ten,
235
		Rank_Jack, Rank_Queen, Rank_King, Rank_Ace,
236
	}
237
238
	for start := 0; start <= len(natural_order)-5; start++ {
239
		needed := 0
240
		valid := true
241
		highest := natural_order[start+4]
242
243
		for i := 0; i < 5; i++ {
244
			rank := natural_order[start+i]
245
			if rank_counts[rank] == 0 {
246
				needed++
247
			} else if rank_counts[rank] > 1 {
248
				valid = false
249
				break
250
			}
251
		}
252
253
		if valid && needed <= wilds_available {
254
			return Combination{
255
				Type:       Comb_Straight,
256
				Cards:      append(non_wild, wild...),
257
				Rank_Value: straight_value(highest, level),
258
			}
259
		}
260
	}
261
262
	return Combination{Type: Comb_Invalid}
263
}
264
265
func straight_value(highest Rank, level Rank) int {
266
	natural_order := []Rank{
267
		Rank_Two, Rank_Three, Rank_Four, Rank_Five,
268
		Rank_Six, Rank_Seven, Rank_Eight, Rank_Nine, Rank_Ten,
269
		Rank_Jack, Rank_Queen, Rank_King, Rank_Ace,
270
	}
271
	for i, r := range natural_order {
272
		if r == highest {
273
			return i
274
		}
275
	}
276
	return 0
277
}
278
279
func detect_tube(non_wild, wild []Card, level Rank) Combination {
280
	total := len(non_wild) + len(wild)
281
	if total != 6 {
282
		return Combination{Type: Comb_Invalid}
283
	}
284
285
	for _, card := range non_wild {
286
		if card.Rank == Rank_Black_Joker || card.Rank == Rank_Red_Joker {
287
			return Combination{Type: Comb_Invalid}
288
		}
289
	}
290
291
	rank_counts := count_ranks(non_wild)
292
	wilds_available := len(wild)
293
294
	natural_order := []Rank{
295
		Rank_Ace, Rank_Two, Rank_Three, Rank_Four, Rank_Five,
296
		Rank_Six, Rank_Seven, Rank_Eight, Rank_Nine, Rank_Ten,
297
		Rank_Jack, Rank_Queen, Rank_King, Rank_Ace,
298
	}
299
300
	for start := 0; start <= len(natural_order)-3; start++ {
301
		needed := 0
302
		valid := true
303
		highest := natural_order[start+2]
304
305
		for i := 0; i < 3; i++ {
306
			rank := natural_order[start+i]
307
			count := rank_counts[rank]
308
			if count < 2 {
309
				needed += 2 - count
310
			}
311
		}
312
313
		if valid && needed <= wilds_available {
314
			return Combination{
315
				Type:       Comb_Tube,
316
				Cards:      append(non_wild, wild...),
317
				Rank_Value: straight_value(highest, level),
318
			}
319
		}
320
	}
321
322
	return Combination{Type: Comb_Invalid}
323
}
324
325
func detect_plate(non_wild, wild []Card, level Rank) Combination {
326
	total := len(non_wild) + len(wild)
327
	if total != 6 {
328
		return Combination{Type: Comb_Invalid}
329
	}
330
331
	for _, card := range non_wild {
332
		if card.Rank == Rank_Black_Joker || card.Rank == Rank_Red_Joker {
333
			return Combination{Type: Comb_Invalid}
334
		}
335
	}
336
337
	rank_counts := count_ranks(non_wild)
338
	wilds_available := len(wild)
339
340
	natural_order := []Rank{
341
		Rank_Ace, Rank_Two, Rank_Three, Rank_Four, Rank_Five,
342
		Rank_Six, Rank_Seven, Rank_Eight, Rank_Nine, Rank_Ten,
343
		Rank_Jack, Rank_Queen, Rank_King, Rank_Ace,
344
	}
345
346
	for start := 0; start <= len(natural_order)-2; start++ {
347
		needed := 0
348
		highest := natural_order[start+1]
349
350
		for i := 0; i < 2; i++ {
351
			rank := natural_order[start+i]
352
			count := rank_counts[rank]
353
			if count < 3 {
354
				needed += 3 - count
355
			}
356
		}
357
358
		if needed <= wilds_available {
359
			return Combination{
360
				Type:       Comb_Plate,
361
				Cards:      append(non_wild, wild...),
362
				Rank_Value: straight_value(highest, level),
363
			}
364
		}
365
	}
366
367
	return Combination{Type: Comb_Invalid}
368
}
369
370
func count_ranks(cards []Card) map[Rank]int {
371
	counts := make(map[Rank]int)
372
	for _, c := range cards {
373
		counts[c.Rank]++
374
	}
375
	return counts
376
}
377
378
func sorted_ranks(counts map[Rank]int, level Rank) []Rank {
379
	var ranks []Rank
380
	for r := range counts {
381
		ranks = append(ranks, r)
382
	}
383
384
	for i := 0; i < len(ranks)-1; i++ {
385
		for j := i + 1; j < len(ranks); j++ {
386
			if rank_value(ranks[i], level) < rank_value(ranks[j], level) {
387
				ranks[i], ranks[j] = ranks[j], ranks[i]
388
			}
389
		}
390
	}
391
392
	return ranks
393
}
394
395
func Can_Beat(play, lead Combination) bool {
396
	if play.Type == Comb_Invalid {
397
		return false
398
	}
399
400
	if play.Type == Comb_Bomb && lead.Type != Comb_Bomb {
401
		return true
402
	}
403
404
	if play.Type == Comb_Bomb && lead.Type == Comb_Bomb {
405
		return play.Bomb_Power > lead.Bomb_Power
406
	}
407
408
	if play.Type != lead.Type {
409
		return false
410
	}
411
412
	if len(play.Cards) != len(lead.Cards) {
413
		return false
414
	}
415
416
	return play.Rank_Value > lead.Rank_Value
417
}