#include #include #include #include "common.h" #define get_bits(value, position, bits) (((value) >> (position)) & ((1 << (bits)) - 1)) #define set_bits(value, position, bits, update) \ ((value) ^= (get_bits(value, position, bits) ^ (update)) << (position)) struct game_result { unsigned wins; unsigned losses; unsigned ties; }; unsigned char * get_hand_from_input(unsigned char, unsigned char); struct game_result calculate_result_frequencies(const char *, const char *, const char *); unsigned long long calculate_mask(const char *); struct game_result try_hands(const char *, const char *, const char *, unsigned char, unsigned char, unsigned long long); unsigned char generate_card(unsigned char); unsigned char determine_winner(const char *, const char *, const char *); unsigned char * create_hand_from_cards(const char *); unsigned char parse_card(const char *); unsigned score_hand(unsigned char *, unsigned); unsigned get_hand_characteristic(unsigned); unsigned score_characteristic(unsigned); unsigned search_insert(unsigned, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char); int main (void) { unsigned char * hand1 = NULL; unsigned char * hand2 = NULL; unsigned char * community = NULL; while (!hand1) { printf("Enter player 1's hand (2 cards): "); hand1 = get_hand_from_input(2, 2); if (!hand1) printf("Invalid hand.\n"); } while (!hand2) { printf("Enter player 2's hand (2 cards): "); hand2 = get_hand_from_input(2, 2); if (!hand2) printf("Invalid hand.\n"); } while (!community) { printf("Enter up to 5 community cards: "); community = get_hand_from_input(0, 5); if (!community) printf("Invalid input.\n"); } unsigned long long mask = calculate_mask(hand1) | calculate_mask(hand2) | calculate_mask(community); unsigned char card, count = 0; for (card = 0; card < 64; card ++) if (mask & (1ULL << card)) count ++; if ((strlen((char *) hand1) + strlen((char *) hand2) + strlen((char *) community)) != count) { printf("There are duplicate cards in the input.\n"); return 1; } struct game_result odds = calculate_result_frequencies(hand1, hand2, community); free(hand1); free(hand2); free(community); double p1, p2, tie; unsigned total; total = odds.wins + odds.losses + odds.ties; p1 = ((double) odds.wins) * 100 / total; p2 = ((double) odds.losses) * 100 / total; tie = ((double) odds.ties) * 100 / total; printf("P1 win:% 11.6f%%\nP2 win:% 11.6f%%\nDraw :% 11.6f%%\n", p1, p2, tie); return 0; } unsigned char * get_hand_from_input (unsigned char min_cards, unsigned char max_cards) { char * line = get_line(NULL); unsigned char * hand = create_hand_from_cards(line); free(line); if (!hand) return NULL; if ((strlen((char *) hand) < min_cards) || (strlen((char *) hand) > max_cards)) { free(hand); return NULL; } return hand; } struct game_result calculate_result_frequencies (const char * player1, const char * player2, const char * community) { if (!community) community = ""; if (strlen(player1) != 2) return (struct game_result) {.wins = 0, .losses = 0, .ties = 0}; if (strlen(player2) != 2) return (struct game_result) {.wins = 0, .losses = 0, .ties = 0}; if (strlen(community) > 5) return (struct game_result) {.wins = 0, .losses = 0, .ties = 0}; if (strlen(community) == 5) { unsigned char result = determine_winner(player1, player2, community); switch (result) { case 0: return (struct game_result) {.wins = 0, .losses = 0, .ties = 1}; case 1: return (struct game_result) {.wins = 1, .losses = 0, .ties = 0}; case 2: return (struct game_result) {.wins = 0, .losses = 1, .ties = 0}; } return (struct game_result) {.wins = 0, .losses = 0, .ties = 0}; } unsigned long long mask = calculate_mask(player1) | calculate_mask(player2) | calculate_mask(community); return try_hands(player1, player2, community, strlen(community), 0, mask); } unsigned long long calculate_mask (const char * cards) { unsigned long long mask = 0; const char * card; for (card = cards; *card; card ++) mask |= 1ULL << *card; return mask; } struct game_result try_hands (const char * player1, const char * player2, const char * community, unsigned char position, unsigned char base, unsigned long long mask) { struct game_result accumulated = {.wins = 0, .losses = 0, .ties = 0}; struct game_result next_result; unsigned char cards[6]; unsigned char card, value, result; cards[5] = 0; memcpy(cards, community, position); for (card = base; card < (48 + position); card ++) { value = generate_card(card); if (mask & (1ULL << value)) continue; cards[position] = value; if (position == 4) { result = determine_winner(player1, player2, cards); switch (result) { case 0: accumulated.ties ++; break; case 1: accumulated.wins ++; break; case 2: accumulated.losses ++; } } else { next_result = try_hands(player1, player2, cards, position + 1, card + 1, mask); accumulated.wins += next_result.wins; accumulated.ties += next_result.ties; accumulated.losses += next_result.losses; } } return accumulated; } unsigned char generate_card (unsigned char index) { return ((index / 13) << 4) | ((index % 13) + 2); } unsigned char determine_winner (const char * player1, const char * player2, const char * community) { char p1hand[8]; char p2hand[8]; memcpy(p1hand, player1, 2); memcpy(p2hand, player2, 2); memcpy(p1hand + 2, community, 6); memcpy(p2hand + 2, community, 6); unsigned score1 = score_hand(p1hand, 7); unsigned score2 = score_hand(p2hand, 7); if (score1 > score2) return 1; if (score2 > score1) return 2; return 0; } unsigned char * create_hand_from_cards (const char * card_list) { if ((!card_list) || (!*card_list)) { char * empty = malloc(1); *empty = 0; return empty; } char ** card_names = tokenize_string(card_list, NULL, 1); unsigned char * hand = malloc(1); unsigned length; unsigned char card; for (length = 0; card_names[length]; length ++) { card = parse_card(card_names[length]); if (!card) { free(hand); free(card_names); return NULL; } hand[length] = card; hand = realloc(hand, length + 2); } free(card_names); hand[length] = 0; return hand; } unsigned char parse_card (const char * card) { if (strlen(card) != 2) return 0; unsigned char value; if ((*card >= '2') && (*card <= '9')) value = *card - '0'; else switch (*card) { case 'T': case 't': value = 10; break; case 'J': case 'j': value = 11; break; case 'Q': case 'q': value = 12; break; case 'K': case 'k': value = 13; break; case 'A': case 'a': value = 14; break; default: return 0; } switch(card[1]) { case 'C': case 'c': break; case 'D': case 'd': value |= 0x10; break; case 'H': case 'h': value |= 0x20; break; case 'S': case 's': value |= 0x30; break; default: return 0; } return value; } unsigned score_hand(unsigned char * cards, unsigned count) { if (!count) return score_hand(cards, strlen((char *) cards)); if (count < 5) return 0; if (count == 5) { unsigned hand = 0; unsigned char card_pos; for (card_pos = 0; card_pos < 5; card_pos ++) { hand <<= 6; hand |= cards[card_pos]; } hand = get_hand_characteristic(hand); if (!hand) return 0; return score_characteristic(hand); } unsigned combination[5] = {0, 1, 2, 3, 4}; unsigned max_score = 0; unsigned score; signed char index, ii; unsigned char card_values[5]; while (1) { for (index = 4; index >= 0; index --) { combination[index] ++; for (ii = index + 1; ii < 5; ii ++) combination[ii] = combination[ii - 1] + 1; if (combination[4] < count) break; } if (index < 0) return max_score; for (ii = 0; ii < 5; ii ++) card_values[ii] = cards[combination[ii]]; score = score_hand(card_values, 5); if (score > max_score) max_score = score; } } unsigned get_hand_characteristic (unsigned hand) { unsigned characteristic = 0; unsigned char lastsuit = get_bits(hand, 4, 2); unsigned char rank, suit, position, count; for (position = 0; position < 5; position ++) { rank = hand & 15; if ((rank < 2) || (rank == 15)) return 0; suit = get_bits(hand, 4, 2); hand >>= 6; if (lastsuit != suit) lastsuit = 4; count = get_bits(characteristic, 2 * rank - 4, 2); if (count == 3) { set_bits(characteristic, 2 * rank - 4, 2, 0); set_bits(characteristic, 28, 4, rank); } else set_bits(characteristic, 2 * rank - 4, 2, count + 1); } if (lastsuit != 4) set_bits(characteristic, 28, 4, 1); return characteristic; } unsigned score_characteristic (unsigned characteristic) { if (characteristic == 0x01000055) return 0x400005; if (characteristic == 0x11000055) return 0x800005; if (characteristic >= 0x20000000) return 0x700000 | (get_bits(characteristic, 28, 4) << 4) | search_insert(characteristic, 1, 1, 0, 0, 0); unsigned char counts = 0; unsigned char current, pos; for (pos = 0; pos < 13; pos ++) { current = get_bits(characteristic, 2 * pos, 2); if (current) counts += 1 << (3 * (current - 1)); } switch (counts) { case 0110: return 0x600000 | search_insert(characteristic, 2, 1, 0, 3, 1); case 0102: return 0x300000 | search_insert(characteristic, 1, 2, 0, 3, 2); case 0021: return 0x200000 | search_insert(characteristic, 2, 2, 1, 1, 0); case 0013: return 0x100000 | search_insert(characteristic, 1, 3, 0, 2, 3); case 0005: break; default: return 0; } unsigned score = search_insert(characteristic, 1, 5, 0, 0, 0); if (!((score + 0x1234) % 0x11111)) return ((get_bits(characteristic, 28, 4) == 1) ? 0x800000 : 0x400000) + ((score + 0x1234) / 0x11111); if (get_bits(characteristic, 28, 4) == 1) score += 0x500000; return score; } unsigned search_insert (unsigned characteristic, unsigned char target_count, unsigned char amount, unsigned char base, unsigned char special, unsigned char special_position) { unsigned char pos, current; unsigned score = 0; for (pos = 12; (pos < 13) && (special || amount); pos --) { current = get_bits(characteristic, pos * 2, 2); if (!current) continue; if (current == special) { set_bits(score, 4 * special_position, 4, pos + 2); special = 0; continue; } if (amount && (current == target_count)) { amount --; set_bits(score, 4 * (base + amount), 4, pos + 2); } } return score; }