aaaaaa123456789 icon

JV programming challenges, week 5, challenge 2

aaaaaa123456789 | PRO | 12/16/13 10:11:55 AM UTC | 0 ⭐ | 419 👁️ | Never ⏰ | []
C |

10.8 KB

|

None

|

0 👍

/

0 👎

#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