// Programming Assignment 1 - Example Solution.
// CS 176, Summer 2001
#include <ctype.h>
static const int number_of_ranks = 13;
static int kinds(char suits[], int hand_size) {
// Return the number of points due to n-of-a-kind cards in array suits
// containing hand_size suits.
// Assume all suits are the same, in which case the number of points is equal
// to the number of cards in the hand.
int points = hand_size;
// If there's any mismatch in suits, the number of points is zero.
for (int i = 1; i < hand_size; i++)
if (tolower(suits[i]) != tolower(suits[0])) {
points = 0;
break;
}
return points;
}
static int pairs(int ranks[], int hand_size) {
// Return the number of points due to pairs in array ranks containing
// hand_size ranks.
int pair_cnt = 0;
// Count the number of pairs in the hand. For each card ranks[i], find the
// number of pairs that it can form with the remaining cards, then throw
// ranks[i] away and repeat the process with one of the remaining cards.
// Stop when there's no cards left.
for (int i = 0; i < hand_size; i++)
for (int j = i + 1; j < hand_size; j++)
if (ranks[i] == ranks[j])
pair_cnt++;
// The number of points is the number of pairs times two.
return pair_cnt*2;
}
static int runs(int ranks[], int hand_size) {
// Return the number of points due to runs in array ranks containing
// hand_size ranks.
// The easiest way to compute runs is to sort the hand by rank and count the
// number of times each rank is repeated. Becuase there's a fixed number of
// ranks (thirteen - ace through king), we can use an array to both sort and
// count at the same time. The index i - 1 represents rank i, and the value
// rank_counts[i - 1] represents the number of times rank i appears in the
// hand. For example, rank_count[10]= 3 means that jacks appear three times
// in the hand.
int rank_counts[number_of_ranks] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int i;
for (i = 0; i < hand_size; i++)
rank_counts[ranks[i] - 1]++;
// A sequence of consecutive non-zero values in the rank_counts array
// represents a run. run_start is the index of the start of a run, and
// run_end is the index of the end of the run plus one.
int run_points = 0;
int run_start = 0;
while (run_start < number_of_ranks) {
int run_end = run_start + 1;
if (rank_counts[run_start] > 0) {
while ((run_end < number_of_ranks) && (rank_counts[run_end] > 0))
run_end++;
// A run has to contain at least three sequential ranks, and the value
// of the run is the number of ranks in the sequence.
int points = run_end - run_start;
if (points > 2) {
// The value of a run is multiplied by the number of times each
// rank appears in the run.
for (i = run_start; i < run_end; i++)
points *= rank_counts[i];
run_points += points;
}
}
run_start = run_end;
}
return run_points;
}
static bool is_suit(char suit) {
// Return true if suit is legal suit, false otherwise; case is ignored.
suit = tolower(suit);
return ((suit == 'c') || (suit == 'd') || (suit == 'h') || (suit == 's'));
}
int count_hand(int ranks[], char suits[], int hand_size) {
// Return the number of points in a hand of hand_size cards. Card i has rank
// ranks[i] and suit suits[i]. Return -1 if the hand's broken.
// Do some sanity checks on the hand: hand size, legal card ranks and suits.
if ((hand_size < 0) || (hand_size > 52))
return -1;
for (int i = 0; i < hand_size; i++) {
if ((ranks[i] < 1) || (number_of_ranks < ranks[i]))
return -1;
if (!is_suit(suits[i]))
return -1;
}
// Hand points come from runs, pairs, and repeated suits.
return runs(ranks, hand_size) +
pairs(ranks, hand_size) +
kinds(suits, hand_size);
}
// If you've understood the previous code, then you'll understand why you can
// use the rank_counts array computed in runs() to also count the number of
// pairs. This leads to a simpler implementation of count_hand() than is shown
// above.
static int new_pairs(int rank_counts[]) {
// Return the number of points due to pairs in array ranks containing
// hand_size ranks.
// Set pair_points[i] to be the number of points i cards of the same rank
// create due to pairs.
int pair_points[] = { 0, 0, 2, 6, 12 };
// This code really should check to make sure rank_counts[i] is a number
// between 0 and 4 inclusive.
int points = 0;
for (int i = 0; i < number_of_ranks; i++)
points += pair_points[rank_counts[i]];
return points;
}
static int new_runs(int rank_counts[]) {
// Return the number of points due to runs in array ranks containing
// hand_size ranks.
int run_points = 0;
int run_start = 0;
// The same code as before, excpet the rank_counts computation has been moved
// to count_hands() and rank_counts is passed in as an argument.
while (run_start < number_of_ranks) {
int run_end = run_start + 1;
if (rank_counts[run_start] > 0) {
while ((run_end < number_of_ranks) && (rank_counts[run_end] > 0))
run_end++;
int points = run_end - run_start;
if (points > 2) {
for (int i = run_start; i < run_end; i++)
points *= rank_counts[i];
run_points += points;
}
}
run_start = run_end;
}
return run_points;
}
int new_count_hand(int ranks[], char suits[], int hand_size) {
// Return the number of points in a hand of hand_size cards. Card i has rank
// ranks[i] and suit suits[i]. Return -1 if the hand's broken.
// Skip the sanity checks.
// Set rank_counts[i] to be the number of cards in the hand that have
// rank i + 1.
int rank_counts[number_of_ranks] = { 0 };
for (int i = 0; i < hand_size; i++)
rank_counts[ranks[i] - 1]++;
return new_runs(rank_counts) +
new_pairs(rank_counts) +
kinds(suits, hand_size);
}
syntax highlighted by Code2HTML, v. 0.9