#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}
Comments