summaryrefslogtreecommitdiff
path: root/c3prj2_eval/eval.c~
diff options
context:
space:
mode:
Diffstat (limited to 'c3prj2_eval/eval.c~')
-rw-r--r--c3prj2_eval/eval.c~366
1 files changed, 366 insertions, 0 deletions
diff --git a/c3prj2_eval/eval.c~ b/c3prj2_eval/eval.c~
new file mode 100644
index 0000000..5e880a2
--- /dev/null
+++ b/c3prj2_eval/eval.c~
@@ -0,0 +1,366 @@
+#include "eval.h"
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int card_ptr_comp(const void *vp1, const void *vp2) {
+ const card_t *const *cp1 = vp1;
+ const card_t *const *cp2 = vp2;
+
+ if ((*cp1)->value != (*cp2)->value) {
+ return (*cp2)->value - (*cp1)->value;
+ }
+
+ return (*cp2)->suit - (*cp1)->suit;
+}
+
+suit_t flush_suit(deck_t *hand) {
+ int numClub = 0;
+ int numDiamond = 0;
+ int numHeart = 0;
+ int numSpade = 0;
+
+ for (size_t i = 0; i < hand->n_cards; i++) {
+ switch (hand->cards[i]->suit) {
+ case SPADES:
+ numSpade++;
+ break;
+ case HEARTS:
+ numHeart++;
+ break;
+ case DIAMONDS:
+ numDiamond++;
+ break;
+ default:
+ numClub++;
+ }
+ }
+
+ if (numSpade >= 5) {
+ return SPADES;
+ }
+ if (numHeart >= 5) {
+ return HEARTS;
+ }
+ if (numDiamond >= 5) {
+ return DIAMONDS;
+ }
+ if (numClub >= 5) {
+ return CLUBS;
+ }
+ return NUM_SUITS;
+}
+
+unsigned get_largest_element(unsigned *arr, size_t n) {
+ if (n == 0) {
+ return 0;
+ }
+ unsigned ans = arr[0];
+ for (size_t i = 1; i < n; i++) {
+ if (arr[i] > ans) {
+ ans = arr[i];
+ }
+ }
+ return ans;
+}
+
+size_t get_match_index(unsigned *match_counts, size_t n, unsigned n_of_akind) {
+
+ for (size_t i = 0; i < n; i++) {
+ if (match_counts[i] == n_of_akind) {
+ return i;
+ }
+ }
+ assert(1 == 2);
+}
+
+ssize_t find_secondary_pair(deck_t *hand, unsigned *match_counts,
+ size_t match_idx) {
+
+ for (size_t i = 0; i < hand->n_cards; i++) {
+ if (match_counts[i] > 1) {
+ if (hand->cards[i]->value != hand->cards[match_idx]->value) {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+int is_ace_low_straight_at_five(deck_t *hand, size_t index, suit_t fs) {
+ int straightTally = 2;
+ int currentCardValue = 5;
+ for (size_t i = index + 1; i < hand->n_cards; i++) {
+ if (straightTally == 5) {
+ return -1;
+ }
+
+ if (hand->cards[i]->value == currentCardValue) {
+ continue;
+ }
+
+ if (hand->cards[i]->value == currentCardValue - 1) {
+ if (fs == NUM_SUITS || hand->cards[i]->suit == fs) {
+ straightTally++;
+ currentCardValue--;
+ } else {
+ continue;
+ }
+ } else {
+ break;
+ }
+ }
+ if (straightTally == 5) {
+ return -1;
+ }
+ return 0;
+}
+
+int is_ace_low_straight_at(deck_t *hand, size_t index, suit_t fs) {
+ int currentCardValue = hand->cards[index]->value;
+ if (currentCardValue == 5) {
+ return is_ace_low_straight_at_five(hand, index, fs);
+ }
+
+ if (currentCardValue == VALUE_ACE) {
+ for (size_t i = index + 1; i < hand->n_cards; i++) {
+
+ if (hand->cards[i]->value == currentCardValue) {
+ continue;
+ }
+
+ if (hand->cards[i]->value == 5) {
+ return is_ace_low_straight_at_five(hand, i, fs);
+ }
+ }
+ }
+
+ return 0;
+}
+
+int is_straight_at(deck_t *hand, size_t index, suit_t fs) {
+ if (hand->cards[index]->suit != fs && fs != NUM_SUITS) {
+ return 0;
+ }
+ int currentCardValue = hand->cards[index]->value;
+ if (currentCardValue < 5) {
+ return 0;
+ }
+ if (currentCardValue == 5) {
+ if (hand->cards[0]->value != 14) {
+ return 0;
+ } else {
+ return is_ace_low_straight_at(hand, index, fs);
+ }
+ }
+
+ int straightTally = 1;
+ for (size_t i = index + 1; i < hand->n_cards; i++) {
+ if (straightTally == 5) {
+ return 1;
+ }
+
+ if (hand->cards[i]->value == currentCardValue) {
+ continue;
+ }
+
+ if (hand->cards[i]->value == currentCardValue - 1) {
+ if (fs == NUM_SUITS || hand->cards[i]->suit == fs) {
+ straightTally++;
+ currentCardValue--;
+ } else {
+ continue;
+ }
+ } else {
+ break;
+ }
+ }
+ if (straightTally == 5) {
+ return 1;
+ }
+
+ if (hand->cards[index]->value == VALUE_ACE) {
+ return is_ace_low_straight_at(hand, index, fs);
+ } else {
+ return 0;
+ }
+}
+
+hand_eval_t build_hand_from_match(deck_t *hand, unsigned n, hand_ranking_t what,
+ size_t idx) {
+
+ hand_eval_t ans;
+ ans.ranking = what;
+ for (int i = 0; i < n; i++) {
+ ans.cards[i] = hand->cards[idx + i];
+ }
+
+ if (idx == 0) {
+ for (int i = n; i < 5; i++) {
+ ans.cards[i] = hand->cards[i];
+ }
+ } else if (idx >= 5 - n) {
+ for (int i = 0; i < 5 - n; i++) {
+ ans.cards[n + i] = hand->cards[i];
+ }
+ } else {
+ for (int i = 0; i < idx; i++) {
+ ans.cards[n + i] = hand->cards[i];
+ }
+ for (int i = idx + n; i < 5; i++) {
+ ans.cards[i] = hand->cards[i];
+ }
+ }
+ return ans;
+}
+
+int compare_hands(deck_t *hand1, deck_t *hand2) {
+
+ qsort(hand1->cards, hand1->n_cards, sizeof(card_t), card_ptr_comp);
+ qsort(hand2->cards, hand2->n_cards, sizeof(card_t), card_ptr_comp);
+ hand_eval_t ht1 = evaluate_hand(hand1);
+ hand_eval_t ht2 = evaluate_hand(hand2);
+
+ if (ht1.ranking != ht2.ranking) {
+ return ht1.ranking - ht2.ranking;
+ }
+
+ for (int i = 0; i < 5; i++) {
+ if (ht1.cards[i]->value == ht2.cards[i]->value) {
+ continue;
+ } else {
+ return ht1.cards[i]->value - ht2.cards[i]->value;
+ }
+ }
+ return 0;
+}
+
+// You will write this function in Course 4.
+// For now, we leave a prototype (and provide our
+// implementation in eval-c4.o) so that the
+// other functions we have provided can make
+// use of get_match_counts.
+unsigned *get_match_counts(deck_t *hand);
+
+// We provide the below functions. You do NOT need to modify them
+// In fact, you should not modify them!
+
+// This function copies a straight starting at index "ind" from deck "from".
+// This copies "count" cards (typically 5).
+// into the card array "to"
+// if "fs" is NUM_SUITS, then suits are ignored.
+// if "fs" is any other value, a straight flush (of that suit) is copied.
+void copy_straight(card_t **to, deck_t *from, size_t ind, suit_t fs,
+ size_t count) {
+ assert(fs == NUM_SUITS || from->cards[ind]->suit == fs);
+ unsigned nextv = from->cards[ind]->value;
+ size_t to_ind = 0;
+ while (count > 0) {
+ assert(ind < from->n_cards);
+ assert(nextv >= 2);
+ assert(to_ind < 5);
+ if (from->cards[ind]->value == nextv &&
+ (fs == NUM_SUITS || from->cards[ind]->suit == fs)) {
+ to[to_ind] = from->cards[ind];
+ to_ind++;
+ count--;
+ nextv--;
+ }
+ ind++;
+ }
+}
+
+// This looks for a straight (or straight flush if "fs" is not NUM_SUITS)
+// in "hand". It calls the student's is_straight_at for each possible
+// index to do the work of detecting the straight.
+// If one is found, copy_straight is used to copy the cards into
+// "ans".
+int find_straight(deck_t *hand, suit_t fs, hand_eval_t *ans) {
+ if (hand->n_cards < 5) {
+ return 0;
+ }
+ for (size_t i = 0; i <= hand->n_cards - 5; i++) {
+ int x = is_straight_at(hand, i, fs);
+ if (x != 0) {
+ if (x < 0) { // ace low straight
+ assert(hand->cards[i]->value == VALUE_ACE &&
+ (fs == NUM_SUITS || hand->cards[i]->suit == fs));
+ ans->cards[4] = hand->cards[i];
+ size_t cpind = i + 1;
+ while (hand->cards[cpind]->value != 5 ||
+ !(fs == NUM_SUITS || hand->cards[cpind]->suit == fs)) {
+ cpind++;
+ assert(cpind < hand->n_cards);
+ }
+ copy_straight(ans->cards, hand, cpind, fs, 4);
+ } else {
+ copy_straight(ans->cards, hand, i, fs, 5);
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+// This function puts all the hand evaluation logic together.
+// This function is longer than we generally like to make functions,
+// and is thus not so great for readability :(
+hand_eval_t evaluate_hand(deck_t *hand) {
+ suit_t fs = flush_suit(hand);
+ hand_eval_t ans;
+ if (fs != NUM_SUITS) {
+ if (find_straight(hand, fs, &ans)) {
+ ans.ranking = STRAIGHT_FLUSH;
+ return ans;
+ }
+ }
+ unsigned *match_counts = get_match_counts(hand);
+ unsigned n_of_a_kind = get_largest_element(match_counts, hand->n_cards);
+ assert(n_of_a_kind <= 4);
+ size_t match_idx = get_match_index(match_counts, hand->n_cards, n_of_a_kind);
+ ssize_t other_pair_idx = find_secondary_pair(hand, match_counts, match_idx);
+ free(match_counts);
+ if (n_of_a_kind == 4) { // 4 of a kind
+ return build_hand_from_match(hand, 4, FOUR_OF_A_KIND, match_idx);
+ } else if (n_of_a_kind == 3 && other_pair_idx >= 0) { // full house
+ ans = build_hand_from_match(hand, 3, FULL_HOUSE, match_idx);
+ ans.cards[3] = hand->cards[other_pair_idx];
+ ans.cards[4] = hand->cards[other_pair_idx + 1];
+ return ans;
+ } else if (fs != NUM_SUITS) { // flush
+ ans.ranking = FLUSH;
+ size_t copy_idx = 0;
+ for (size_t i = 0; i < hand->n_cards; i++) {
+ if (hand->cards[i]->suit == fs) {
+ ans.cards[copy_idx] = hand->cards[i];
+ copy_idx++;
+ if (copy_idx >= 5) {
+ break;
+ }
+ }
+ }
+ return ans;
+ } else if (find_straight(hand, NUM_SUITS, &ans)) { // straight
+ ans.ranking = STRAIGHT;
+ return ans;
+ } else if (n_of_a_kind == 3) { // 3 of a kind
+ return build_hand_from_match(hand, 3, THREE_OF_A_KIND, match_idx);
+ } else if (other_pair_idx >= 0) { // two pair
+ assert(n_of_a_kind == 2);
+ ans = build_hand_from_match(hand, 2, TWO_PAIR, match_idx);
+ ans.cards[2] = hand->cards[other_pair_idx];
+ ans.cards[3] = hand->cards[other_pair_idx + 1];
+ if (match_idx > 0) {
+ ans.cards[4] = hand->cards[0];
+ } else if (other_pair_idx > 2) { // if match_idx is 0, first pair is in 01
+ // if other_pair_idx > 2, then, e.g. A A K Q Q
+ ans.cards[4] = hand->cards[2];
+ } else { // e.g., A A K K Q
+ ans.cards[4] = hand->cards[4];
+ }
+ return ans;
+ } else if (n_of_a_kind == 2) {
+ return build_hand_from_match(hand, 2, PAIR, match_idx);
+ }
+ return build_hand_from_match(hand, 0, NOTHING, 0);
+}