summaryrefslogtreecommitdiff
path: root/c3prj2_eval
diff options
context:
space:
mode:
authorHaidong Ji2022-04-15 15:51:30 -0500
committerHaidong Ji2022-04-15 15:51:30 -0500
commit442a49ad5a48d417345959b903ae6a6d32d55759 (patch)
treec7127bb497e5e439018b1915e0136eec2c9cb124 /c3prj2_eval
Great C programming funHEADmaster
Excellent fundamentals and displine training, many tools and techniques exercises: gdb, emacs, valgrind, git
Diffstat (limited to 'c3prj2_eval')
-rw-r--r--c3prj2_eval/.gitignore4
-rw-r--r--c3prj2_eval/Makefile10
-rw-r--r--c3prj2_eval/README332
-rw-r--r--c3prj2_eval/README~332
-rw-r--r--c3prj2_eval/cards.c131
-rw-r--r--c3prj2_eval/cards.h38
-rw-r--r--c3prj2_eval/deck-c4.obin0 -> 4752 bytes
-rw-r--r--c3prj2_eval/deck.c40
-rw-r--r--c3prj2_eval/deck.c~40
-rw-r--r--c3prj2_eval/deck.h22
-rwxr-xr-xc3prj2_eval/eval-c4.obin0 -> 2504 bytes
-rw-r--r--c3prj2_eval/eval.c366
-rw-r--r--c3prj2_eval/eval.c~366
-rw-r--r--c3prj2_eval/eval.h13
-rwxr-xr-xc3prj2_eval/future.obin0 -> 3216 bytes
-rw-r--r--c3prj2_eval/grade.txt49
-rwxr-xr-xc3prj2_eval/input.obin0 -> 5504 bytes
-rw-r--r--c3prj2_eval/t1.txt2
-rw-r--r--c3prj2_eval/t2.txt2
-rw-r--r--c3prj2_eval/t3.txt2
-rw-r--r--c3prj2_eval/t4.txt2
-rw-r--r--c3prj2_eval/t5.txt2
-rw-r--r--c3prj2_eval/test-eval.obin0 -> 7808 bytes
-rwxr-xr-xc3prj2_eval/tests.txt30
24 files changed, 1783 insertions, 0 deletions
diff --git a/c3prj2_eval/.gitignore b/c3prj2_eval/.gitignore
new file mode 100644
index 0000000..15d0dfb
--- /dev/null
+++ b/c3prj2_eval/.gitignore
@@ -0,0 +1,4 @@
+deck.o
+eval.o
+cards.o
+test-eval
diff --git a/c3prj2_eval/Makefile b/c3prj2_eval/Makefile
new file mode 100644
index 0000000..d297bdb
--- /dev/null
+++ b/c3prj2_eval/Makefile
@@ -0,0 +1,10 @@
+CFLAGS=-ggdb3 -Wall -Werror -pedantic -std=gnu99
+GIVEN_OBJS=deck-c4.o eval-c4.o future.o input.o main.o
+MY_OBJS=cards.o deck.o eval.o
+
+test-eval: deck.o eval.o eval-c4.o test-eval.o deck-c4.o cards.o input.o future.o
+ gcc -o test-eval -ggdb3 deck.o deck-c4.o eval-c4.o eval.o test-eval.o cards.o input.o future.o
+poker: $(GIVEN_OBJS) $(MY_OBJS)
+ gcc -o poker -ggdb3 $(MY_OBJS) $(GIVEN_OBJS)
+clean:
+ rm -f test poker cards.o my-test-main.o *~
diff --git a/c3prj2_eval/README b/c3prj2_eval/README
new file mode 100644
index 0000000..ce5530e
--- /dev/null
+++ b/c3prj2_eval/README
@@ -0,0 +1,332 @@
+Hand Evaluation
+---------------
+The other part of the project that you will do in this
+course is write some of the code to evaluate and compare hands.
+Remember that in Course 2 you already wrote test cases
+for this code. That means you have already thought
+about various corner cases that might come up
+and will have a nice suite of tests ready to go
+when you finish your code.
+
+Your ultimate goal in this step is to write a function,
+which when passed two hands of cards, determines
+which one won (or if they tied). We'll use the
+deck_t type that you worked with in the previous
+part to represent a hand of cards as well (a hand
+of cards is just a much smaller deck of cards---they
+are both just sets of cards).
+
+There are three major steps to determining who won:
+ (1) Figuring out what ranking each hand has (straight, flush, etc)
+ If you look in cards.h, you will see enum hand_ranking_t,
+ which you worked with in Course 2.
+ (2) Figuring out which 5 cards make up the hand (picking out
+ the 5 cards that made the flush, or the two pairs and tiebreaker)
+ (3) Comparing the rankings, and if they are the same, breaking
+ ties by comparing the values in the hands.
+
+At this point, you might be thinking that there is going to
+be a lot of code to write with all the different possible
+arrangements of cards and different possible hand rankings.
+However, there are a few important things that will make
+this managable:
+
+(1) You will start by sorting the cards into descending order
+ by value. This makes it much easier to find straights (cards
+ in order), and you will have "N of a kind"s grouped together.
+(2) The code to find "N of a kind" is basically the same
+ for 4, 3, and 2 (so we can abstract it out into a function...)
+(3) Full house and two pair are just three of a kind and a pair
+ (so we already have that code...) with another pair
+ (so we can just write a function to find a secondary pair)
+(4) We are going to make two simplifying assumptions:
+ - if there is a flush, it will occur in at most one suit.
+ (i.e., you won't have As Ah Kh Qs 8s 7h 4s 3s 3h 2h,
+ which has two different flushes).
+ - if there is an ace-high straight, there is not also
+ an ace-low straight.
+ (These both hold for all major poker variants)
+
+If you open up eval.c, you will find the following functions
+that you will need to write:
+
+ - int card_ptr_comp(const void * vp1, const void * vp2)
+ You want to sort the hand by value, so you need
+ a comparison function to pass to quicksort.
+ Quicksort sorts into ascending order, but you
+ want descending order, so you will want to
+ return
+ something < 0 if card1 > card2
+ 0 if card1 == card2
+ something > 0 if card1 < card2
+ If two cards have the same value, compare them by
+ suit in the same order as the enum suit_t:
+ club < diamond < heart < spade
+ Note that vp1 and vp2 are passed as const void *
+ because that is the type that qsort demands.
+ They will should each be assigned to variables
+ of type
+ const card_t * const * cp1
+ before using them (this is much like sorting
+ an array of strings from your readings).
+ To learn more about using the C library function qsort,
+ we suggest reviewing the course reading
+ "Sorting Functions" in the "Function Pointers"
+ lesson and consulting "man qsort"
+ to read about the comparison function.
+
+ - suit_t flush_suit(deck_t * hand);
+ This function looks at the hand and determines
+ if a flush (at least 5 cards of one suit) exists.
+ If so, it returns the suit of the cards comprising
+ the flush. If not, it returns NUM_SUITS.
+ For example:
+ Given Ks Qs 0s 9h 8s 7s, it would return SPADES.
+ Given Kd Qd 0s 9h 8c 7c, it would return NUM_SUITS.
+
+ - unsigned get_largest_element(unsigned * arr, size_t n);
+ This function returns the largest element in an array
+ of unsigned integers. This should be familiar
+ from the videos you watched.
+
+ In course 4 (after you learn to dynamically allocate
+ memory), you will write get_match_counts,
+ which will construct an array with one element
+ per card in the hand. That array will
+ tell you how many cards in the hand
+ have the same value as the corresponding
+ card. You will then use get_largest_element
+ to figure out which is the best "N of a kind".
+
+
+ - size_t get_match_index(unsigned * match_counts, size_t n,unsigned n_of_akind);
+ This function returns the index in the array (match_counts) whose
+ value is n_of_akind. The array has n elements. The array match_counts
+ may have multiple values equal to n_of_akind. You should return
+ the LOWEST index whose value is n_of_akind [which also guarantees
+ it corresponds to the largest valued cards, since they will be sorted].
+ (Once you figure out the best n_of_akind above,
+ you will use this to locate that group of cards
+ in the hand).
+ Note that it is guaranteed that n_of_akind is in match_counts.
+ If not, you should abort as this is evidence of an error.
+
+
+ - ssize_t find_secondary_pair(deck_t * hand,
+ unsigned * match_counts,
+ size_t match_idx) ;
+ When you have a hand with 3 of a kind or a pair,
+ you will want to look and see if there is another
+ pair to make the hand into a full house or
+ or two pairs. This function takes in
+ the hand, the match counts from before, and
+ the index where the original match (3 of a kind
+ or pair) was found. It should find
+ the index of a card meeting the following conditions:
+ - Its match count is > 1 [so there is at least a pair of them]
+ - The card's value is not the same as the value of the
+ card at match_idx (so it is not part of the original
+ three of a kind/pair)
+ - It is the lowest index meeting the first two conditions
+ (which will be the start of that pair, and the highest
+ value pair other than the original match).
+ If no such index can be found, this function should
+ return -1.
+
+ - int is_straight_at(deck_t * hand, size_t index, suit_t fs)
+ This function should determine if there is a straight
+ starting at index (and only starting at index) in the
+ given hand. If fs is NUM_SUITS, then it should look
+ for any straight. If fs is some other value, then
+ it should look for a straight flush in the specified suit.
+ This function should return:
+ -1 if an Ace-low straight was found at that index (and that index is the Ace)
+ 0 if no straight was found at that index
+ 1 if any other straight was found at that index
+
+ When writing this function, you can assume
+ that the hand is sorted by value: the
+ values of cards will appear in descending order.
+ (A K Q ... 4 3 2).
+
+ There are two things that make this function
+ tricky (probably the trickiest function in
+ this assignment):
+ (1) Ace low straights. An Ace low straight
+ will appear in the hand with the Ace
+ first, then possibly some other cards,
+ then the 5 4 3 2. For example, you
+ might have
+ As Ks Qc 5s 4c 3d 2c
+ (2) You may have multiple cards with the
+ same value, but still have a straight:
+ As Ac Ks Kc Qh Jh 0d
+ has a straight even though A K Q
+ do not appear next to each other in
+ our sorted order.
+ Hint: I made this easier on myself, by writing
+ two helper functions:
+ int is_n_length_straight_at(deck_t * hand, size_t index, suit_t fs, int n) ;
+ and
+ int is_ace_low_straight_at(deck_t * hand, size_t index, suit_t fs);
+
+ The second of these lets me pull out the complexities of an ace
+ low straight. However, in doing so, I realized that there
+ would be a lot of duplication of code between the ace low straight
+ helper and the original function (for an ace low, you want to find
+ a 5, then a straight of length 4: 5, 4, 3, 2). This realization
+ caused me to pull out much of the code into is_n_length_straight_at,
+ so that I could call it with n=4 to search for the 5,4,3,2 part
+ of an ace low straight.
+
+
+ - hand_eval_t build_hand_from_match(deck_t * hand,
+ unsigned n,
+ hand_ranking_t what,
+ size_t idx) ;
+ Now you have written a bunch of functions that
+ will figure out which ranking a hand has. It
+ is time to construct a hand_eval_t (see eval.h) which
+ has the ranking and the 5 cards used for it.
+ This helper function will handle the
+ "n of a kind" case.
+ It should make hand_eval_t and set its
+ ranking to the passed in "what" value.
+ Then it should copy "n" cards from
+ the hand, starting at "idx" into
+ the first "n" elements of the hand_eval_t's
+ "cards" array. The cards field in
+ hand_eval_t is declared as:
+ card_t * cards[5]
+ This is an array of pointers, each to a card_t.
+ Draw a picture to be sure you know how to name
+ each card_t "box" before you start writing code.
+
+ Your function should then fill the remainder
+ of the "cards" array with the highest-value
+ cards from the hand which were not in
+ the "n of a kind".
+
+ For example, given this hand:
+ As Kc Kh Kd Qc 8s 5d
+ The hand has 3 kings, and the As and Qc will break ties.
+ Note that here n = 3, what= THREE_OF_A_KIND, idx= 1.
+ So the cards array in the hand_eval_t should have
+
+ Kc Kh Kd As Qc
+
+ Note that what may also be FULL_HOUSE or TWO_PAIR,
+ since this function will get used for the first
+ part of preparing those evaluations (then other code
+ will later fix the rest of the hand with the other pair).
+
+
+ - int compare_hands(deck_t * hand1, deck_t * hand2)
+
+ This is the goal of the whole thing: given two hands,
+ figure out which wins (or if it is a tie).
+ Everything you wrote goes together to make this work!
+
+
+ We're providing you with
+ hand_eval_t evaluate_hand(deck_t * hand) ;
+ since it involves some things you won't learn until
+ Course 4. It's also not super interesting:
+ it mostly make a bunch of calls to the functions
+ you wrote above, and has a lot of if-statements
+ to handle the rules of poker.
+
+ The important part of evaluate_hand is that
+ (a) assumes the cards in the passed in hand are
+ sorted and (b) it returns a hand_eval_t for the passed in hand.
+
+ That means that to implement compare_hands, you should
+
+ (a) sort each hand using qsort on the hand's cards
+ and your card_ptr_comp [from earlier]
+ (b) Call evaluate_hand on each hand, which gives you a hand_eval_t
+ for each hand.
+ (c) Check if the rankings in the hand_eval_t are the same
+ or different. If they are different, you can just use
+ the ranking to determine the winner.
+ (d) If they are the same, then you need to look
+ at the values in the cards array of each hand_eval_t
+ to break the tie. The way that we constructed
+ the hand_eval_t's cards array means that
+ the cards are already ordered from most significant (at index 0)
+ to least significant (at index 4). You can just
+ do a lexicographic comparison on the values in the arrays.
+ (Its like comparing strings, but you are comparing values
+ of cards---if element 0 is the different, use that difference
+ to determine your answer. If element 0 is the same,
+ look at element 1, and so on).
+Note that compare hands should return a positive number
+if hand 1 is better, 0 if the hands tie, and a negative number
+if hand 2 is better.
+
+You will also notice some functions at the bottom of eval.c that
+we provided. You don't need to do anything to these---we wrote
+them for you to keep the amount of code manageable.
+
+--------------
+That sure was a lot of code! You've been compiling and testing
+along the way, right? We sure hope so :)
+
+However, to help you test things out even more, we've
+provided some test infrastructure for you.
+
+If you do
+
+make
+
+You will compile the test-eval program you are
+familiar with from Course 2. This program behaves
+exactly like it did in Course 2. As a reminder,
+it expects input where each line looks like:
+
+hand1 ; hand2
+
+where a hand looks like something that print_hand
+would output. So a valid input might be
+
+Kc Ac Jh 8s 9c 2s ; Ah Kh 0s 7c 7h 3c
+
+For each line in the input, the test program
+will tell you:
+ - The results of your functions that went into evaluating it
+ (if there was a straight, if there was a flush, etc).
+ - What hand_eval_t was returned by evaluate_hand for each hand
+ - Which hand won (or if it was a tie) according to compare_hands
+
+Good thing you have all those test cases from Course 2
+to use with it!
+
+Because you have an object file test-eval.o and not the source
+test-eval.c, you may need to use the debugger differently than you're
+used to. For this test program, we recommend running gdb in emacs,
+then first, specifying the command line argument (in this case, a file
+name with your tests)
+
+set args tests.txt
+
+Then you will want to set a breakpoint in the code you wrote (since
+you can't see test-eval.c, where main is, to step through it). For
+example, if you just wrote the function is_straight_at, and it doesn't
+behave the way you expect, you can do
+
+break is_straight_at
+
+and gdb will pause execution any time the program calls that
+function. Then you can use the command "run" instead of "start," since
+you don't need to pause execution at the start of main. Also recall
+the command "continue," which you can review from the debugging
+lesson.
+
+
+As usual, when you are finished, use the "grade" command.
+When you pass, this, congratulations! You are done
+with Course 3 and ready to move on to Course 4 :)
+
+
+
+
diff --git a/c3prj2_eval/README~ b/c3prj2_eval/README~
new file mode 100644
index 0000000..1b77db5
--- /dev/null
+++ b/c3prj2_eval/README~
@@ -0,0 +1,332 @@
+Hand Evaluation
+---------------
+The other part of the project that you will do in this
+course is write some of the code to evaluate and compare hands.
+Remember that in Course 2 you already wrote test cases
+for this code. That means you have already thought
+about various corner cases that might come up
+and will have a nice suite of tests ready to go
+when you finish your code.
+
+Your ultimate goal in this step is to write a function,
+which when passed two hands of cards, determines
+which one won (or if they tied). We'll use the
+deck_t type that you worked with in the previous
+part to represent a hand of cards as well (a hand
+of cards is just a much smaller deck of cards---they
+are both just sets of cards).
+
+There are three major steps to determining who won:
+ (1) Figuring out what ranking each hand has (straight, flush, etc)
+ If you look in cards.h, you will see enum hand_ranking_t,
+ which you worked with in Course 2.
+ (2) Figuring out which 5 cards make up the hand (picking out
+ the 5 cards that made the flush, or the two pairs and tiebreaker)
+ (3) Comparing the rankings, and if they are the same, breaking
+ ties by comparing the values in the hands.
+
+At this point, you might be thinking that there is going to
+be a lot of code to write with all the different possible
+arrangements of cards and different possible hand rankings.
+However, there are a few important things that will make
+this managable:
+
+(1) You will start by sorting the cards into descending order
+ by value. This makes it much easier to find straights (cards
+ in order), and you will have "N of a kind"s grouped together.
+(2) The code to find "N of a kind" is basically the same
+ for 4, 3, and 2 (so we can abstract it out into a function...)
+(3) Full house and two pair are just three of a kind and a pair
+ (so we already have that code...) with another pair
+ (so we can just write a function to find a secondary pair)
+(4) We are going to make two simplifying assumptions:
+ - if there is a flush, it will occur in at most one suit.
+ (i.e., you won't have As Ah Kh Qs 8s 7h 4s 3s 3h 2h,
+ which has two different flushes).
+ - if there is an ace-high straight, there is not also
+ an ace-low straight.
+ (These both hold for all major poker variants)
+
+If you open up eval.c, you will find the following functions
+that you will need to write:
+
+ - int card_ptr_comp(const void * vp1, const void * vp2)
+ You want to sort the hand by value, so you need
+ a comparison function to pass to quicksort.
+ Quicksort sorts into ascending order, but you
+ want descending order, so you will want to
+ return
+ something < 0 if card1 > card2
+ 0 if card1 == card2
+ something > 0 if card1 < card2
+ If two cards have the same value, compare them by
+ suit in the same order as the enum suit_t:
+ club < diamond < heart < spade
+ Note that vp1 and vp2 are passed as const void *
+ because that is the type that qsort demands.
+ They will should each be assigned to variables
+ of type
+ const card_t * const * cp1
+ before using them (this is much like sorting
+ an array of strings from your readings).
+ To learn more about using the C library function qsort,
+ we suggest reviewing the course reading
+ "Sorting Functions" in the "Function Pointers"
+ lesson and consulting "man qsort"
+ to read about the comparison function.
+
+ - suit_t flush_suit(deck_t * hand);
+ This function looks at the hand and determines
+ if a flush (at least 5 cards of one suit) exists.
+ If so, it returns the suit of the cards comprising
+ the flush. If not, it returns NUM_SUITS.
+ For example:
+ Given Ks Qs 0s 9h 8s 7s, it would return SPADES.
+ Given Kd Qd 0s 9h 8c 7c, it would return NUM_SUITS.
+
+ - unsigned get_largest_element(unsigned * arr, size_t n);
+ This function returns the largest element in an array
+ of unsigned integers. This should be familiar
+ from the videos you watched.
+
+ In course 4 (after you learn to dynamically allocate
+ memory), you will write get_match_counts,
+ which will construct an array with one element
+ per card in the hand. That array will
+ tell you how many cards in the hand
+ have the same value as the corresponding
+ card. You will then use get_largest_element
+ to figure out which is the best "N of a kind".
+
+
+ - size_t get_match_index(unsigned * match_counts, size_t n,unsigned n_of_akind);
+ This function returns the index in the array (match_counts) whose
+ value is n_of_akind. The array has n elements. The array match_counts
+ may have multiple values equal to n_of_akind. You should return
+ the LOWEST index whose value is n_of_akind [which also guarantees
+ it corresponds to the largest valued cards, since they will be sorted].
+ (Once you figure out the best n_of_akind above,
+ you will use this to locate that group of cards
+ in the hand).
+ Note that it is guaranteed that n_of_akind is in match_counts.
+ If not, you should abort as this is evidence of an error.
+
+
+ - size_t find_secondary_pair(deck_t * hand,
+ unsigned * match_counts,
+ size_t match_idx) ;
+ When you have a hand with 3 of a kind or a pair,
+ you will want to look and see if there is another
+ pair to make the hand into a full house or
+ or two pairs. This function takes in
+ the hand, the match counts from before, and
+ the index where the original match (3 of a kind
+ or pair) was found. It should find
+ the index of a card meeting the following conditions:
+ - Its match count is > 1 [so there is at least a pair of them]
+ - The card's value is not the same as the value of the
+ card at match_idx (so it is not part of the original
+ three of a kind/pair)
+ - It is the lowest index meeting the first two conditions
+ (which will be the start of that pair, and the highest
+ value pair other than the original match).
+ If no such index can be found, this function should
+ return -1.
+
+ - int is_straight_at(deck_t * hand, size_t index, suit_t fs)
+ This function should determine if there is a straight
+ starting at index (and only starting at index) in the
+ given hand. If fs is NUM_SUITS, then it should look
+ for any straight. If fs is some other value, then
+ it should look for a straight flush in the specified suit.
+ This function should return:
+ -1 if an Ace-low straight was found at that index (and that index is the Ace)
+ 0 if no straight was found at that index
+ 1 if any other straight was found at that index
+
+ When writing this function, you can assume
+ that the hand is sorted by value: the
+ values of cards will appear in descending order.
+ (A K Q ... 4 3 2).
+
+ There are two things that make this function
+ tricky (probably the trickiest function in
+ this assignment):
+ (1) Ace low straights. An Ace low straight
+ will appear in the hand with the Ace
+ first, then possibly some other cards,
+ then the 5 4 3 2. For example, you
+ might have
+ As Ks Qc 5s 4c 3d 2c
+ (2) You may have multiple cards with the
+ same value, but still have a straight:
+ As Ac Ks Kc Qh Jh 0d
+ has a straight even though A K Q
+ do not appear next to each other in
+ our sorted order.
+ Hint: I made this easier on myself, by writing
+ two helper functions:
+ int is_n_length_straight_at(deck_t * hand, size_t index, suit_t fs, int n) ;
+ and
+ int is_ace_low_straight_at(deck_t * hand, size_t index, suit_t fs);
+
+ The second of these lets me pull out the complexities of an ace
+ low straight. However, in doing so, I realized that there
+ would be a lot of duplication of code between the ace low straight
+ helper and the original function (for an ace low, you want to find
+ a 5, then a straight of length 4: 5, 4, 3, 2). This realization
+ caused me to pull out much of the code into is_n_length_straight_at,
+ so that I could call it with n=4 to search for the 5,4,3,2 part
+ of an ace low straight.
+
+
+ - hand_eval_t build_hand_from_match(deck_t * hand,
+ unsigned n,
+ hand_ranking_t what,
+ size_t idx) ;
+ Now you have written a bunch of functions that
+ will figure out which ranking a hand has. It
+ is time to construct a hand_eval_t (see eval.h) which
+ has the ranking and the 5 cards used for it.
+ This helper function will handle the
+ "n of a kind" case.
+ It should make hand_eval_t and set its
+ ranking to the passed in "what" value.
+ Then it should copy "n" cards from
+ the hand, starting at "idx" into
+ the first "n" elements of the hand_eval_t's
+ "cards" array. The cards field in
+ hand_eval_t is declared as:
+ card_t * cards[5]
+ This is an array of pointers, each to a card_t.
+ Draw a picture to be sure you know how to name
+ each card_t "box" before you start writing code.
+
+ Your function should then fill the remainder
+ of the "cards" array with the highest-value
+ cards from the hand which were not in
+ the "n of a kind".
+
+ For example, given this hand:
+ As Kc Kh Kd Qc 8s 5d
+ The hand has 3 kings, and the As and Qc will break ties.
+ Note that here n = 3, what= THREE_OF_A_KIND, idx= 1.
+ So the cards array in the hand_eval_t should have
+
+ Kc Kh Kd As Qc
+
+ Note that what may also be FULL_HOUSE or TWO_PAIR,
+ since this function will get used for the first
+ part of preparing those evaluations (then other code
+ will later fix the rest of the hand with the other pair).
+
+
+ - int compare_hands(deck_t * hand1, deck_t * hand2)
+
+ This is the goal of the whole thing: given two hands,
+ figure out which wins (or if it is a tie).
+ Everything you wrote goes together to make this work!
+
+
+ We're providing you with
+ hand_eval_t evaluate_hand(deck_t * hand) ;
+ since it involves some things you won't learn until
+ Course 4. It's also not super interesting:
+ it mostly make a bunch of calls to the functions
+ you wrote above, and has a lot of if-statements
+ to handle the rules of poker.
+
+ The important part of evaluate_hand is that
+ (a) assumes the cards in the passed in hand are
+ sorted and (b) it returns a hand_eval_t for the passed in hand.
+
+ That means that to implement compare_hands, you should
+
+ (a) sort each hand using qsort on the hand's cards
+ and your card_ptr_comp [from earlier]
+ (b) Call evaluate_hand on each hand, which gives you a hand_eval_t
+ for each hand.
+ (c) Check if the rankings in the hand_eval_t are the same
+ or different. If they are different, you can just use
+ the ranking to determine the winner.
+ (d) If they are the same, then you need to look
+ at the values in the cards array of each hand_eval_t
+ to break the tie. The way that we constructed
+ the hand_eval_t's cards array means that
+ the cards are already ordered from most significant (at index 0)
+ to least significant (at index 4). You can just
+ do a lexicographic comparison on the values in the arrays.
+ (Its like comparing strings, but you are comparing values
+ of cards---if element 0 is the different, use that difference
+ to determine your answer. If element 0 is the same,
+ look at element 1, and so on).
+Note that compare hands should return a positive number
+if hand 1 is better, 0 if the hands tie, and a negative number
+if hand 2 is better.
+
+You will also notice some functions at the bottom of eval.c that
+we provided. You don't need to do anything to these---we wrote
+them for you to keep the amount of code manageable.
+
+--------------
+That sure was a lot of code! You've been compiling and testing
+along the way, right? We sure hope so :)
+
+However, to help you test things out even more, we've
+provided some test infrastructure for you.
+
+If you do
+
+make
+
+You will compile the test-eval program you are
+familiar with from Course 2. This program behaves
+exactly like it did in Course 2. As a reminder,
+it expects input where each line looks like:
+
+hand1 ; hand2
+
+where a hand looks like something that print_hand
+would output. So a valid input might be
+
+Kc Ac Jh 8s 9c 2s ; Ah Kh 0s 7c 7h 3c
+
+For each line in the input, the test program
+will tell you:
+ - The results of your functions that went into evaluating it
+ (if there was a straight, if there was a flush, etc).
+ - What hand_eval_t was returned by evaluate_hand for each hand
+ - Which hand won (or if it was a tie) according to compare_hands
+
+Good thing you have all those test cases from Course 2
+to use with it!
+
+Because you have an object file test-eval.o and not the source
+test-eval.c, you may need to use the debugger differently than you're
+used to. For this test program, we recommend running gdb in emacs,
+then first, specifying the command line argument (in this case, a file
+name with your tests)
+
+set args tests.txt
+
+Then you will want to set a breakpoint in the code you wrote (since
+you can't see test-eval.c, where main is, to step through it). For
+example, if you just wrote the function is_straight_at, and it doesn't
+behave the way you expect, you can do
+
+break is_straight_at
+
+and gdb will pause execution any time the program calls that
+function. Then you can use the command "run" instead of "start," since
+you don't need to pause execution at the start of main. Also recall
+the command "continue," which you can review from the debugging
+lesson.
+
+
+As usual, when you are finished, use the "grade" command.
+When you pass, this, congratulations! You are done
+with Course 3 and ready to move on to Course 4 :)
+
+
+
+
diff --git a/c3prj2_eval/cards.c b/c3prj2_eval/cards.c
new file mode 100644
index 0000000..8e467ec
--- /dev/null
+++ b/c3prj2_eval/cards.c
@@ -0,0 +1,131 @@
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include "cards.h"
+
+
+void assert_card_valid(card_t c) {
+ assert(c.value >= 2 && c.value <= VALUE_ACE);
+ assert(c.suit >= SPADES && c.suit <= CLUBS);
+}
+
+const char * ranking_to_string(hand_ranking_t r) {
+ switch (r) {
+ case STRAIGHT_FLUSH:
+ return "STRAIGHT_FLUSH";
+ case FOUR_OF_A_KIND:
+ return "FOUR_OF_A_KIND";
+ case FULL_HOUSE:
+ return "FULL_HOUSE";
+ case FLUSH:
+ return "FLUSH";
+ case STRAIGHT:
+ return "STRAIGHT";
+ case THREE_OF_A_KIND:
+ return "THREE_OF_A_KIND";
+ case TWO_PAIR:
+ return "TWO_PAIR";
+ case PAIR:
+ return "PAIR";
+ default:
+ return "NOTHING";
+ }
+}
+
+char value_letter(card_t c) {
+ switch(c.value) {
+ case VALUE_ACE:
+ return 'A';
+ case VALUE_KING:
+ return 'K';
+ case VALUE_QUEEN:
+ return 'Q';
+ case VALUE_JACK:
+ return 'J';
+ case 10:
+ return '0';
+ default:
+ return '0' + c.value;
+ }
+}
+
+
+char suit_letter(card_t c) {
+ switch(c.suit) {
+ case SPADES:
+ return 's';
+ case HEARTS:
+ return 'h';
+ case DIAMONDS:
+ return 'd';
+ default:
+ return 'c';
+ }
+
+}
+
+void print_card(card_t c) {
+ printf("%c%c", value_letter(c), suit_letter(c));
+}
+
+card_t card_from_letters(char value_let, char suit_let) {
+ card_t temp;
+ switch(value_let) {
+ case 'A':
+ temp.value = VALUE_ACE;
+ break;
+ case 'K':
+ temp.value = VALUE_KING;
+ break;
+ case 'Q':
+ temp.value = VALUE_QUEEN;
+ break;
+ case 'J':
+ temp.value = VALUE_JACK;
+ break;
+ case '0':
+ temp.value = 10;
+ break;
+ default:
+ temp.value = value_let - '0';
+ break;
+ }
+ switch(suit_let) {
+ case 's':
+ temp.suit = SPADES;
+ break;
+ case 'h':
+ temp.suit = HEARTS;
+ break;
+ case 'd':
+ temp.suit = DIAMONDS;
+ break;
+ case 'c':
+ temp.suit = CLUBS;
+ break;
+ }
+ assert_card_valid(temp);
+ return temp;
+}
+
+card_t card_from_num(unsigned c) {
+ card_t temp;
+ if (c <= 12) {
+ temp.value = c + 2;
+ temp.suit = SPADES;
+ }
+ else if (c > 12 && c <= 25) {
+ temp.value = c % 13 + 2;
+ temp.suit = HEARTS;
+ }
+ else if (c > 25 && c <= 38) {
+ temp.value = c % 13 + 2;
+ temp.suit = DIAMONDS;
+ }
+ else {
+ temp.value = c % 13 + 2;
+ temp.suit = CLUBS;
+ }
+ assert_card_valid(temp);
+ return temp;
+}
diff --git a/c3prj2_eval/cards.h b/c3prj2_eval/cards.h
new file mode 100644
index 0000000..fef0529
--- /dev/null
+++ b/c3prj2_eval/cards.h
@@ -0,0 +1,38 @@
+#ifndef CARD_H
+#define CARD_H
+#define VALUE_ACE 14
+#define VALUE_KING 13
+#define VALUE_QUEEN 12
+#define VALUE_JACK 11
+typedef enum {
+ SPADES,
+ HEARTS,
+ DIAMONDS,
+ CLUBS,
+ NUM_SUITS
+} suit_t;
+
+struct card_tag {
+ unsigned value;
+ suit_t suit;
+};
+typedef struct card_tag card_t;
+typedef enum {
+ STRAIGHT_FLUSH,
+ FOUR_OF_A_KIND,
+ FULL_HOUSE,
+ FLUSH,
+ STRAIGHT,
+ THREE_OF_A_KIND,
+ TWO_PAIR,
+ PAIR,
+ NOTHING
+} hand_ranking_t;
+card_t card_from_num(unsigned c);
+void assert_card_valid(card_t c);
+const char * ranking_to_string(hand_ranking_t r) ;
+char value_letter(card_t c);
+char suit_letter(card_t c) ;
+void print_card(card_t c);
+card_t card_from_letters(char value_let, char suit_let);
+#endif
diff --git a/c3prj2_eval/deck-c4.o b/c3prj2_eval/deck-c4.o
new file mode 100644
index 0000000..5fc5541
--- /dev/null
+++ b/c3prj2_eval/deck-c4.o
Binary files differ
diff --git a/c3prj2_eval/deck.c b/c3prj2_eval/deck.c
new file mode 100644
index 0000000..c4a3d78
--- /dev/null
+++ b/c3prj2_eval/deck.c
@@ -0,0 +1,40 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "deck.h"
+
+void print_hand(deck_t * hand){
+ for (size_t i = 0; i < hand->n_cards; i++) {
+ print_card(*hand->cards[i]);
+ printf(" ");
+ }
+}
+
+int deck_contains(deck_t * d, card_t c) {
+ for (size_t i = 0; i < d->n_cards; i++) {
+ if (d->cards[i]->value == c.value && d->cards[i]->suit == c.suit ) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void shuffle(deck_t * d){
+ card_t c;
+ for (size_t i = d->n_cards; i > 0; i--) {
+ int r = rand() % i;
+ c = *d->cards[i-1];
+ *d->cards[i-1] = *d->cards[r];
+ //d[i-1] = d[r];
+ *d->cards[r] = c;
+ }
+}
+
+void assert_full_deck(deck_t * d) {
+ card_t temp;
+ for (int i = 0; i <= 51; i++) {
+ temp = card_from_num(i);
+ assert(deck_contains(d, temp) == 1);
+ }
+
+}
diff --git a/c3prj2_eval/deck.c~ b/c3prj2_eval/deck.c~
new file mode 100644
index 0000000..c4a3d78
--- /dev/null
+++ b/c3prj2_eval/deck.c~
@@ -0,0 +1,40 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "deck.h"
+
+void print_hand(deck_t * hand){
+ for (size_t i = 0; i < hand->n_cards; i++) {
+ print_card(*hand->cards[i]);
+ printf(" ");
+ }
+}
+
+int deck_contains(deck_t * d, card_t c) {
+ for (size_t i = 0; i < d->n_cards; i++) {
+ if (d->cards[i]->value == c.value && d->cards[i]->suit == c.suit ) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void shuffle(deck_t * d){
+ card_t c;
+ for (size_t i = d->n_cards; i > 0; i--) {
+ int r = rand() % i;
+ c = *d->cards[i-1];
+ *d->cards[i-1] = *d->cards[r];
+ //d[i-1] = d[r];
+ *d->cards[r] = c;
+ }
+}
+
+void assert_full_deck(deck_t * d) {
+ card_t temp;
+ for (int i = 0; i <= 51; i++) {
+ temp = card_from_num(i);
+ assert(deck_contains(d, temp) == 1);
+ }
+
+}
diff --git a/c3prj2_eval/deck.h b/c3prj2_eval/deck.h
new file mode 100644
index 0000000..f5f44bf
--- /dev/null
+++ b/c3prj2_eval/deck.h
@@ -0,0 +1,22 @@
+#ifndef DECK_H
+#define DECK_H
+#include <stdlib.h>
+#include "cards.h"
+struct deck_tag {
+ card_t ** cards;
+ size_t n_cards;
+};
+typedef struct deck_tag deck_t;
+
+void print_hand(deck_t * hand);
+int deck_contains(deck_t * d, card_t c) ;
+void shuffle(deck_t * d);
+void assert_full_deck(deck_t * d) ;
+//The below functions will be done in course 4.
+deck_t * make_deck_exclude(deck_t * excluded_cards);
+void add_card_to(deck_t * deck, card_t c);
+card_t * add_empty_card(deck_t * deck);
+void free_deck(deck_t * deck) ;
+deck_t * build_remaining_deck(deck_t ** hands, size_t n_hands) ;
+#endif
+//
diff --git a/c3prj2_eval/eval-c4.o b/c3prj2_eval/eval-c4.o
new file mode 100755
index 0000000..8cca00b
--- /dev/null
+++ b/c3prj2_eval/eval-c4.o
Binary files differ
diff --git a/c3prj2_eval/eval.c b/c3prj2_eval/eval.c
new file mode 100644
index 0000000..b4bb37a
--- /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 ht2.ranking - ht1.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);
+}
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);
+}
diff --git a/c3prj2_eval/eval.h b/c3prj2_eval/eval.h
new file mode 100644
index 0000000..1967917
--- /dev/null
+++ b/c3prj2_eval/eval.h
@@ -0,0 +1,13 @@
+#ifndef EVAL_H
+#define EVAL_H
+#include "deck.h"
+struct hand_eval_tag {
+ hand_ranking_t ranking;
+ card_t *cards[5];
+};
+typedef struct hand_eval_tag hand_eval_t;
+
+hand_eval_t evaluate_hand(deck_t * hand) ;
+int compare_hands(deck_t * hand1, deck_t * hand2) ;
+
+#endif
diff --git a/c3prj2_eval/future.o b/c3prj2_eval/future.o
new file mode 100755
index 0000000..a770c6a
--- /dev/null
+++ b/c3prj2_eval/future.o
Binary files differ
diff --git a/c3prj2_eval/grade.txt b/c3prj2_eval/grade.txt
new file mode 100644
index 0000000..b751b74
--- /dev/null
+++ b/c3prj2_eval/grade.txt
@@ -0,0 +1,49 @@
+Grading at Sat 11 Dec 2021 09:52:46 PM UTC
+Compiling your code
+rm -f test poker cards.o my-test-main.o *~
+cc -ggdb3 -Wall -Werror -pedantic -std=gnu99 -c -o deck.o deck.c
+cc -ggdb3 -Wall -Werror -pedantic -std=gnu99 -c -o eval.o eval.c
+cc -ggdb3 -Wall -Werror -pedantic -std=gnu99 -c -o cards.o cards.c
+gcc -o test-eval -ggdb3 deck.o deck-c4.o eval-c4.o eval.o test-eval.o cards.o input.o future.o
+Testcase 1: Trying hands with nothing
+ Checking the output
+Your file matched the expected output
+ - Testcase passed
+Testcase 2: Trying hands with pairs
+ Checking the output
+Your file matched the expected output
+ - Testcase passed
+Testcase 3: Trying hands with 2 pairs
+ Checking the output
+Your file matched the expected output
+ - Testcase passed
+Testcase 4: Trying hands with 3 of a kind
+ Checking the output
+Your file matched the expected output
+ - Testcase passed
+Testcase 5: Trying hands with straights
+ Checking the output
+Your file matched the expected output
+ - Testcase passed
+Testcase 6: Trying hands with flushes
+ Checking the output
+Your file matched the expected output
+ - Testcase passed
+Testcase 7: Trying hands with full houses
+ Checking the output
+Your file matched the expected output
+ - Testcase passed
+Testcase 8: Trying hands with 4 of a kind
+ Checking the output
+Your file matched the expected output
+ - Testcase passed
+Testcase 9: Trying hands with straight flushes
+ Checking the output
+Your file matched the expected output
+ - Testcase passed
+Testcase 10: Trying each type of hand ranking
+ Checking the output
+Your file matched the expected output
+ - Testcase passed
+
+Overall Grade: A
diff --git a/c3prj2_eval/input.o b/c3prj2_eval/input.o
new file mode 100755
index 0000000..65cc44b
--- /dev/null
+++ b/c3prj2_eval/input.o
Binary files differ
diff --git a/c3prj2_eval/t1.txt b/c3prj2_eval/t1.txt
new file mode 100644
index 0000000..cc33372
--- /dev/null
+++ b/c3prj2_eval/t1.txt
@@ -0,0 +1,2 @@
+7c 3d 9h Qd As 2s; Kc 2h Js 6c 4d 7h
+
diff --git a/c3prj2_eval/t2.txt b/c3prj2_eval/t2.txt
new file mode 100644
index 0000000..efc6951
--- /dev/null
+++ b/c3prj2_eval/t2.txt
@@ -0,0 +1,2 @@
+0s 9s 8c 7h 6d; Js 0c 9s 8d 7c
+
diff --git a/c3prj2_eval/t3.txt b/c3prj2_eval/t3.txt
new file mode 100644
index 0000000..6620302
--- /dev/null
+++ b/c3prj2_eval/t3.txt
@@ -0,0 +1,2 @@
+As 5c 4h 3s 2c; 6c 5h 4s 3s 2d
+
diff --git a/c3prj2_eval/t4.txt b/c3prj2_eval/t4.txt
new file mode 100644
index 0000000..3d961ef
--- /dev/null
+++ b/c3prj2_eval/t4.txt
@@ -0,0 +1,2 @@
+Ac As Kc Ks Qs Js 0s; Ad Kh Qh Jh Js 0h 9h
+
diff --git a/c3prj2_eval/t5.txt b/c3prj2_eval/t5.txt
new file mode 100644
index 0000000..d42cde9
--- /dev/null
+++ b/c3prj2_eval/t5.txt
@@ -0,0 +1,2 @@
+As Kc Qs Js 0s 2s; Kc Kd Kh Ks 8c 6d
+
diff --git a/c3prj2_eval/test-eval.o b/c3prj2_eval/test-eval.o
new file mode 100644
index 0000000..92f6913
--- /dev/null
+++ b/c3prj2_eval/test-eval.o
Binary files differ
diff --git a/c3prj2_eval/tests.txt b/c3prj2_eval/tests.txt
new file mode 100755
index 0000000..63059d5
--- /dev/null
+++ b/c3prj2_eval/tests.txt
@@ -0,0 +1,30 @@
+Kc Qs Jd 9h 8c 7s 6d; Ac Qs Jd 9h 8c 7s 6d
+Kh Ac Kc 8c 7h 3d 6s; Kh As 7h 3s 5d 6h Ks
+As Ah Ks Kd 2h 3d 6s; Ac Ad Kh Kc Jd 3d 6s
+Kh Kc Kd Ac 3s 6h 2s; Kh Kc Kd Ac 7h 6s 3d
+Ks Qd Js 0h 6h 9d 2s; 0h 5d 8s 4s 3c 2h Ah
+Ah Qh 5s 6d 9h 7h 2h; 4s 6s 5s 7d 0s Qs As
+Kc Ks 3d 0c 0s Kh 8d; 9h Jd 9s Js 9d 3d 0c
+0c 0s 0h 2d 7c 0d 2h; Kc Kd Kh Ks 3c 4h 5d
+As 2d 3c Ks Qs Js 0s; 5s 4s 3s 2d Jc 2s As
+As Ks 4d 5d Jd 0d Qd; Kd Qd Js 0s 9s 4s 5s
+Qd Jd 0d 9s 9h 8h 8c; Jd 0d 9d 8s 8h 7h 7c
+0c 0s 8s 7d 6d 6s 5c; Js 0s 8s 7d 6s 5c 4c
+2d 3d 6d 8d 7c As Js; 2d 3d 6d 8d 7c Ah Ac
+Ac 2d 3c 0s 4d 5s 0h; Ac 2d 3c 0s 4d 8h Jh
+6c 3c 6d 4h Qs As 2d; 6c 3c 6d 4h Qs 2h Jh
+6c 3c 6d 4h Qs 6h 2d; 6c 3c 6d 4h Qs 2h Jh
+6c 3c 6d 4h 6h Qs 2d; 6c 3c 6d 4h Qs 6s Jh
+6c 3c 6d 4h Qs 6h 2d; 6c 3c 6d 4h Qs 6s Ac
+2d 3c 3d Jh Qs Js 3h; 2d 3c 3d Jh Qs Jd 3c
+2d 3c 3d Jh Qs Js 2s; 2d 3c 3d Jh Qs Jd 3c
+7d 2c 8h Ah 2h 9h 0h; 7d 2c 8h Ah 2h Jh Qh
+6h 7h 8d 9d Jd 0d Qh; 6h 7h 8d 9d Jd 2c 9s
+2c 5d 9h 8h 7h 3d As; 2c 5d 9h 8h 7h 0h Jh
+Ah 2c 3c 7h 4s 5s 0d; Ah 2c 3c 7h 4s 0s 0h
+4s 3s 8h 2s 9d As 5s; 4s 3s 8h 2s 9d 9h 9s
+9d 9h 9s 8c 9c 0h Ah; 9d 9h 9s 8c 9c 0c As
+9d 9h 8h 9c 7h 6h 5h; 9d 9h 8h 9c 7h 6c 5c
+2s 3s 4s 6s 5h 8s 9h; As 2s 3s 4s 5s 8h 9h
+2s 3s 4h 5s 6s 4s 0h; 2s 3s 4h 5s 6s 8d Kh
+Kc Ac 2c 3c 2s Qc 7c; Kc Ac 2c As 2s 8c 5c