Skip to content

Instantly share code, notes, and snippets.

@radiofreejohn
Created March 25, 2012 06:33
Show Gist options
  • Save radiofreejohn/2191857 to your computer and use it in GitHub Desktop.
Save radiofreejohn/2191857 to your computer and use it in GitHub Desktop.
Poker game solver
/*
input is 1 line with 10 cards, black first, white second
cards are sorted by value (suit is disregarded when sorting)
when tested for hand type -- they are sorted again based on the
order of evaluation of the hand when comparing the two, so
full house will put the 3 of a kind highest, then the 2 of a kind.
A pair will have the pair as the last two cards, and the rest
sorted by from lowest to highest. This makes it easy to determine
the winner by comparing down from the top.
example:
black white
#echo "3H 4D 4H 4D 4S 9H 9D 9H 9D 4S"| ./poker
White is the winner with four of a kind
*/
#include <stdio.h>
#include <stdlib.h>
struct hand {
char suit[5];
int value[5];
int rank;
};
enum poker_hand {
HIGH_CARD = 1,
PAIR,
TWO_PAIRS,
THREE_OF_A_KIND,
STRAIGHT,
FLUSH,
FULL_HOUSE,
FOUR_OF_A_KIND,
STRAIGHT_FLUSH
};
char *hand_name[] = {
"a high card",
"a pair",
"two pairs",
"three of a kind",
"a straight",
"a flush",
"a full house",
"four of a kind",
"a straight flush"
};
int compare(const void *x, const void *y)
{
if (*(int *)x == *(int *)y)
return 0;
else if (*(int *)x < *(int *)y)
return -1;
else
return 1;
}
int straight(struct hand *hand) {
int i, count = 0;
// already sorted
for (i = 1; i < 5; i++) {
if (hand->value[i] == hand->value[i-1]+1) count++;
}
return (count == 4) ? STRAIGHT : 0;
}
int flush(struct hand *hand) {
int i, count = 0;
// no need to sort, if it's a flush they are all the same so are already sorted
for (i = 1; i < 5; i++) {
if (hand->suit[i] == hand->suit[i-1]) count++;
}
return (count == 4) ? FLUSH : 0;
}
int straight_flush(struct hand *hand) {
// already in proper sorted order
return (flush(hand) && straight(hand)) ? STRAIGHT_FLUSH : 0;
}
int card_value(const char card) {
char values[] = "23456789TJQKA";
int i = 0;
while ((card != values[i]) && (values[i] != '\0')) {
i++;
}
if (values[i] == '\0') {
return -1;
} else {
return i;
}
}
int three_four(struct hand *hand) {
int i, count = 1, index, j;
int temp[5];
for (i = 0; i < 5; i++) {
temp[i] = hand->value[i];
}
for (i = 1; i < 5; i++) {
if ((hand->value[i] == hand->value[i-1]) && count < 4) {
count++;
if (count == 3) index = i-2;
if (count == 4) index = i-3;
} else {
if (count >= 3) {
break;
} else {
count = 1;
}
}
}
if (count == 3) {
j = 0;
for (i = 0; i < 5; i++) {
if (i < index || i >= (index+3)) {
hand->value[j++] = temp[i];
}
}
for (i = index; i < index+3; i++) {
hand->value[j++] = temp[i];
}
return THREE_OF_A_KIND;
}
else if (count == 4) {
j = 0;
for (i = 0; i < 5; i++) {
if (i < index || i >= (index+4)) {
hand->value[j++] = temp[i];
}
}
for (i = index; i < index+4; i++) {
hand->value[j++] = temp[i];
}
return FOUR_OF_A_KIND;
}
else return 0;
}
int full_house(struct hand *hand) {
int i, count = 0;
// need to test values for uniqueness -- should only be 1 change
// it's OK that this would also produce a positive for
// four of a kind, because I check for that first
for (i = 1; i < 5; i++) {
if (hand->value[i] != hand->value[i-1]) {
count++;
}
}
if (count == 1) {
// use three_four to sort it with the three at highest
(void)three_four(hand);
}
return (count == 1) ? FULL_HOUSE : 0;
}
int two_pairs(struct hand *hand) {
int i, npairs = 0, j = 0;
int maxpair = -1, minpair = 99;
int temp[5];
for (i = 0; i < 5; i++) {
temp[i] = hand->value[i];
}
for (i = 1; i < 5; i++) {
if (hand->value[i] == hand->value[i-1]) {
npairs++;
maxpair = (hand->value[i] > maxpair) ? hand->value[i] : maxpair;
minpair = (hand->value[i] < minpair) ? hand->value[i] : minpair;
}
}
if (npairs == 2) {
for (i = 0; i < 5; i++) {
if ((temp[i] != maxpair) && (temp[i] != minpair)) {
hand->value[j++] = temp[i];
}
}
hand->value[j++] = minpair;
hand->value[j++] = minpair;
hand->value[j++] = maxpair;
hand->value[j] = maxpair;
return TWO_PAIRS;
} else {
return 0;
}
}
int pair(struct hand *hand) {
int i, j = 0, pairval = -1;
int temp[5];
for (i = 0; i < 5; i++) {
temp[i] = hand->value[i];
}
for (i = 1; i < 5; i++) {
if (hand->value[i] == hand->value[i-1]) {
pairval = hand->value[i];
}
}
if (pairval != -1) {
for (i = 0; i < 5; i++) {
if (temp[i] != pairval) {
hand->value[j++] = temp[i];
}
}
hand->value[j++] = pairval;
hand->value[j] = pairval;
return PAIR;
}
return 0;
}
int high_card_value(struct hand *hand) {
// should probably qsort once before calling anything
return hand->value[4];
}
int hand_rank(struct hand *hand) {
int rank = 0;
if ((rank = straight_flush(hand)) != 0) {
return rank;
} else if ((rank = three_four(hand)) == FOUR_OF_A_KIND) {
return rank;
} else if ((rank = full_house(hand)) != 0) {
return rank;
} else if ((rank = flush(hand)) != 0) {
return rank;
} else if ((rank = straight(hand)) != 0) {
return rank;
} else if ((rank = three_four(hand)) == THREE_OF_A_KIND) {
return rank;
} else if ((rank = two_pairs(hand)) != 0) {
return rank;
} else if ((rank = pair(hand)) != 0) {
return rank;
} else {
return HIGH_CARD;
}
}
int hand_winner(struct hand black, struct hand white) {
int i;
if (black.rank == white.rank) {
for (i = 4; i >= 0; i--) {
if (black.value[i] == white.value[i]) {
continue;
} else if (black.value[i] > white.value[i]) {
return 0;
} else {
return 1;
}
} // if you get here, it's a tie all around
return -1;
} else if (black.rank > white.rank) {
return 0;
} else {
return 1;
// white > black
}
}
int main(int argc, char *argv[]) {
struct hand black;
struct hand white;
int rank_black, rank_white;
int count = 0, cardval;
char *player[] = {"Black", "White"};
int winner, winner_rank;
char c;
while ((c = getchar()) != EOF) {
if (c == ' ') continue;
if (c == '\n') {
count = 0;
white.rank = 0;
black.rank = 0;
qsort(black.value, 5, sizeof(int), compare);
qsort(white.value, 5, sizeof(int), compare);
black.rank = hand_rank(&black);
white.rank = hand_rank(&white);
winner = hand_winner(black,white);
if (winner == -1) {
printf("Game is a tie\n");
} else {
winner_rank = (winner == 0) ? black.rank : white.rank;
printf("%s is the winner with %s\n", player[winner], hand_name[winner_rank-1]);
}
continue;
}
if (count < 5) {
cardval = card_value(c);
if (cardval == -1) {
printf("Bad card found: %c%c, skipping hand.\n", cardval, getchar());
while ((c = getchar()) != '\n')
;
continue;
}
black.value[count] = cardval;
black.suit[count] = getchar();
count++;
} else {
cardval = card_value(c);
if (cardval == -1) {
printf("Bad card found, skipping hand.\n");
while ((c = getchar()) != '\n')
;
continue;
}
white.value[count-5] = cardval;
white.suit[count-5] = getchar();
count++;
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment