guandan.dev

guandan.dev

https://git.tonybtw.com/guandan.dev.git git://git.tonybtw.com/guandan.dev.git
2,797 bytes raw
1
package game
2
3
func detect_bomb(cards []Card, level Rank) Combination {
4
	n := len(cards)
5
	if n == 4 && is_four_joker_bomb(cards) {
6
		return Combination{
7
			Type:       Comb_Bomb,
8
			Cards:      cards,
9
			Bomb_Power: 1000,
10
		}
11
	}
12
	if is_straight_flush(cards, level) {
13
		return Combination{
14
			Type:       Comb_Bomb,
15
			Cards:      cards,
16
			Bomb_Power: 900 + straight_flush_value(cards, level),
17
		}
18
	}
19
	if n >= 4 && n <= 10 {
20
		if power, ok := is_n_of_kind_bomb(cards, level); ok {
21
			return Combination{
22
				Type:       Comb_Bomb,
23
				Cards:      cards,
24
				Bomb_Power: power,
25
			}
26
		}
27
	}
28
29
	return Combination{Type: Comb_Invalid}
30
}
31
32
func is_four_joker_bomb(cards []Card) bool {
33
	if len(cards) != 4 {
34
		return false
35
	}
36
37
	red_count := 0
38
	black_count := 0
39
40
	for _, c := range cards {
41
		switch c.Rank {
42
		case Rank_Red_Joker:
43
			red_count++
44
		case Rank_Black_Joker:
45
			black_count++
46
		default:
47
			return false
48
		}
49
	}
50
51
	return red_count == 2 && black_count == 2
52
}
53
54
func is_straight_flush(cards []Card, level Rank) bool {
55
	if len(cards) < 5 {
56
		return false
57
	}
58
59
	non_wild, wild := separate_wilds(cards, level)
60
61
	if len(non_wild) == 0 {
62
		return false
63
	}
64
65
	var suit Suit = -1
66
	for _, c := range non_wild {
67
		if c.Rank == Rank_Black_Joker || c.Rank == Rank_Red_Joker {
68
			return false
69
		}
70
		if suit == -1 {
71
			suit = c.Suit
72
		} else if c.Suit != suit {
73
			return false
74
		}
75
	}
76
77
	rank_present := make(map[Rank]bool)
78
	for _, c := range non_wild {
79
		rank_present[c.Rank] = true
80
	}
81
82
	natural_order := []Rank{
83
		Rank_Ace, Rank_Two, Rank_Three, Rank_Four, Rank_Five,
84
		Rank_Six, Rank_Seven, Rank_Eight, Rank_Nine, Rank_Ten,
85
		Rank_Jack, Rank_Queen, Rank_King, Rank_Ace,
86
	}
87
88
	needed_len := len(cards)
89
	wilds_available := len(wild)
90
91
	for start := 0; start <= len(natural_order)-needed_len; start++ {
92
		gaps := 0
93
		for i := 0; i < needed_len; i++ {
94
			rank := natural_order[start+i]
95
			if !rank_present[rank] {
96
				gaps++
97
			}
98
		}
99
		if gaps <= wilds_available {
100
			return true
101
		}
102
	}
103
104
	return false
105
}
106
107
func straight_flush_value(cards []Card, level Rank) int {
108
	non_wild, _ := separate_wilds(cards, level)
109
110
	max_val := 0
111
	for _, c := range non_wild {
112
		v := rank_value(c.Rank, level)
113
		if v > max_val {
114
			max_val = v
115
		}
116
	}
117
118
	return len(cards)*10 + max_val
119
}
120
121
func is_n_of_kind_bomb(cards []Card, level Rank) (int, bool) {
122
	n := len(cards)
123
	if n < 4 || n > 10 {
124
		return 0, false
125
	}
126
127
	non_wild, wild := separate_wilds(cards, level)
128
129
	rank_counts := count_ranks(non_wild)
130
131
	for rank, count := range rank_counts {
132
		if rank == Rank_Black_Joker || rank == Rank_Red_Joker {
133
			continue
134
		}
135
		total := count + len(wild)
136
		if total >= n {
137
			power := n*100 + rank_value(rank, level)
138
			return power, true
139
		}
140
	}
141
142
	if len(wild) >= n {
143
		power := n*100 + rank_value(level, level)
144
		return power, true
145
	}
146
147
	return 0, false
148
}