/* N.B.: see the notes at the end of the file! */

#include <stdio.h>
#include <stdlib.h>           /* for the qsort() function */

#include "io.h"       /* for the drain() function */
#include "rmath.h"    /* for the between() function */
#include "array.h"    /* for the array functions */

#define RANKS        13
#define SUITS         4
#define DEAL_SIZE     7
#define HAND_SIZE     5

/*
  There is a better way to handle this set of flags.  After we
  talk about the bitwise operators -- they allow you to treat
  integer values as a series of bits -- we can code it.
  However, let's take this opportunity to play with bit fields.
*/
struct flag_type
{
 unsigned straight : 1,
          flush : 1,       /* all the same suit */
          four : 1,
          three : 1;
 unsigned pairs;
};
typedef struct flag_type FLAGS;


void deal_hand (int[], int);
void display_hand (int[], int);
FLAGS analyze_hand (int[], int);
void display_analysis (FLAGS);
int run_again (void);

int main (void)
{
 int hand[DEAL_SIZE], size=DEAL_SIZE;
 FLAGS flags;

  do {
   deal_hand (hand, size);
   display_hand (hand, size);
   flags = analyze_hand (hand, size);
   display_analysis (flags);
  } while (run_again());
   return 0;
}


void deal_hand (int hand[], int size)
{
 int x, value;
 int deck[SUITS*RANKS];

   setup_array (deck, SUITS*RANKS, 0);
   for (x = 0; x < size; x++)
    {
      do {
         value = between (0, 51);
        } while (deck[value] == 1);
      deck[value] = 1;
      hand[x] = value;       
    }
   qsort (hand, size, sizeof (int), compare_ints);
}

void display_hand (int hand[], int size)
{
 int x;
 void display_card (int);
   for (x = 0; x < size; x++) display_card (hand[x]);
   putchar ('\n');
}

void display_card (int card)
{
 const char *suits = "SHDC";
 const char *ranks = "A23456789TJQK";
   printf ("%c %c   ", ranks[card % RANKS], suits[card / RANKS]);
}

void clear_flags (FLAGS *f)
{
 f->straight = f->flush = f->four = f->three = f->pairs = 0;
}

FLAGS analyze_hand (int hand[], int size)
{
 int x, rank, suit;
 int num_in_rank[RANKS], num_in_suit[SUITS];
 int consecutive;
 FLAGS temp;
 void clear_flags (FLAGS *);

  setup_array (num_in_rank, RANKS, 0);
  setup_array (num_in_suit, SUITS, 0);
  clear_flags (&temp);

  for (x = 0; x < size; x++)
   {
    /* how many cards of each rank? */
    for (rank = 0; rank < RANKS; rank++)
     {
      if ( (hand[x] % RANKS) == rank )
        (num_in_rank[rank])++;
     }
    /* how many cards of each suit? */
    for (suit = 0; suit < SUITS; suit++)
     {
      if ( (hand[x] / RANKS) == suit )
        (num_in_suit[suit])++;          
     }
   }

  /* check for a flush */
  for (suit = 0; suit < SUITS && temp.flush == 0; suit++)
   {
    if (num_in_suit[suit] == HAND_SIZE) temp.flush = 1;
   }


  /* now look for a straight -- THIS CODE IS INCOMPLETE */
  rank = 0;   consecutive = 0;
  /* find the first nonzero item in num_in_rank */
  while (num_in_rank[rank] == 0) rank++;
  /* are the next 4 ranks nonzero? */
  for (; rank < RANKS && num_in_rank[rank]; rank++)
    {
      consecutive++;
    }
  if (consecutive >= HAND_SIZE) temp.straight = 1;

  /* check for multiples of a rank */
  for (rank = 0; rank < 13; rank++)
   {
     if (num_in_rank[rank] == 4) temp.four = 1;
     if (num_in_rank[rank] == 3) temp.three = 1;
     if (num_in_rank[rank] == 2) temp.pairs++;
   }

  return temp;
}

void display_analysis (FLAGS flags)
{
  putchar ('\t');
  if (flags.straight && flags.flush)
    printf ("Straight flush");
  else if (flags.four)
    printf ("Four of a kind");
  else if (flags.three && flags.pairs == 1)
    printf ("Full house");
  else if (flags.flush)
    printf ("Flush");
  else if (flags.straight)
    printf ("Straight");
  else if (flags.three)
    printf ("Three of a kind");
  else if (flags.pairs == 2)
    printf ("Two pair");
  else if (flags.pairs == 1)
    printf ("Pair");
  else
    printf ("High card");
  putchar ('\n');
}

int run_again (void)
{
 char response;
  printf ("\nFancy another go, luv? ");
  response = toupper(getchar());
  if (response != '\n') drain();
  return (response == 'Y');
}


/*
  - this code must be modified so it can recognize A-high straights
  - ...and straights like 2, 4, 6, 7, 8, 9, 10 as well
  - when DEAL_SIZE exceeds HAND_SIZE, all sorts of mischief can
    happen: among these are that you can have a flush and a straight,
    but not a straight flush

 Needless to say, these matters need to be cleared up before this
 program can be considered complete.  But, for our purposes, at
 this stage of the semester, this'll do.

Also, you can handle the tabulation like this:

  for (x = 0; x < size; x++)
   {
    (num_in_rank [(hand[x] % RANKS)])++;
    (num_in_suit [(hand[x] / RANKS)])++;
   }
*/

