-
Notifications
You must be signed in to change notification settings - Fork 3
/
hand.c
150 lines (133 loc) · 3.7 KB
/
hand.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include "hand.h"
#include <stdio.h>
hand_rank_t _calc_rank(hand_t hand);
static const char *level_string[] = {
"HIGH_CARD",
"ONE_PAIR",
"TWO_PAIR",
"THREE_OF_A_KIND",
"STRAIGHT",
"FLUSH",
"FULL_HORSE",
"FOUR_OF_A_KIND",
"STRAIGHT_FLUSH",
"ROYAL_FLUSH",
};
static unsigned int masks[] = {
0x1f, 0x2f, 0x37, 0x3b, 0x3d, 0x3e, 0x4f,
0x57, 0x5b, 0x5d, 0x5e, 0x67, 0x6b, 0x6d,
0x6e, 0x73, 0x75, 0x76, 0x79, 0x7a, 0x7c,
};
#define NUM_MASKS (sizeof(masks) / sizeof(unsigned int))
inline const char *level_to_string(hand_level_t level)
{
return level_string[level];
}
hand_rank_t calc_rank(hand_t hand)
{
card_t cards[CARD_NUM];
unsigned int i, j, k;
hand_rank_t max_rank, rank;
max_rank.score = 0;
for (i = 0; i < NUM_MASKS; i++) {
for (j = 0, k = 0; j < HAND_NUM; j++) {
if (masks[i] & (1u << j)) {
cards[k++] = hand[j];
}
}
rank = _calc_rank(cards);
rank.mask = masks[i];
if (rank.score > max_rank.score) {
max_rank = rank;
}
}
return max_rank;
}
hand_rank_t _calc_rank(hand_t hand)
{
int i, j, numbers[CARD_BASE] = {0}, suits[4] = {0}, statistics[CARD_NUM] = {0};
int flush = 0, straight = 0;
hand_rank_t rank;
// prepare
for (i = 0; i < CARD_NUM; i++) {
numbers[hand[i] % CARD_BASE]++;
suits[hand[i] / CARD_BASE]++;
}
// statistics
for (i = 0; i < CARD_BASE; i++) {
statistics[numbers[i]]++;
}
// check flush
for (i = 0; i < 4; i++) {
if (suits[i] == CARD_NUM) {
flush = 1;
}
}
// check straight
if (!(statistics[2] || statistics[3] || statistics[4])) {
for (i = 0; numbers[i] == 0 && i < CARD_BASE; i++);
for (j = 0; j < 5 && i + j < CARD_BASE; j++) {
if (!numbers[i + j]) {
break;
}
}
if (j == 5) {
straight = 1;
} else if (i == 0 && j == 4 && numbers[CARD_BASE - 1] > 0) {
straight = 1;
numbers[CARD_BASE - 1] = 0;
}
}
// calculate score
rank.score = 0;
for (i = 4; i > 0; i--) {
if (statistics[i] == 0) {
continue;
}
for (j = CARD_BASE - 1; j >= 0; j--) {
if (numbers[j] == i) {
rank.score <<= 4;
rank.score |= j;
}
}
}
// calc levels
if (flush && straight) {
SET_RANK(rank.score, STRAIGHT_FLUSH);
} else if (statistics[4]) {
SET_RANK(rank.score, FOUR_OF_A_KIND);
} else if (statistics[3] && statistics[2]) {
SET_RANK(rank.score, FULL_HORSE);
} else if (flush) {
SET_RANK(rank.score, FLUSH);
} else if (straight) {
SET_RANK(rank.score, STRAIGHT);
} else if (statistics[3]) {
SET_RANK(rank.score, THREE_OF_A_KIND);
} else if (statistics[2] >= 2) {
SET_RANK(rank.score, TWO_PAIR);
} else if (statistics[2]) {
SET_RANK(rank.score, ONE_PAIR);
} else {
SET_RANK(rank.score, HIGH_CARD);
}
return rank;
}
// see hamming weight(http://en.wikipedia.org/wiki/Hamming_weight)
inline unsigned int bit_count(unsigned int i)
{
i = i - ((i >> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}
int hand_to_string(card_t *cards, hand_rank_t rank, char *buffer, int size)
{
int i, offset = 0;
for (i = 0; i < HAND_NUM; i++) {
if (rank.mask & (1u << i)) {
offset += snprintf(buffer + offset, size - offset, "%s,", card_to_string(cards[i]));
}
}
buffer[--offset] = '\0';
return offset;
}