contest/
contest/Merc21/
contest/Merc21/log/
contest/Merc21/player/
/******************************************************************************
 Copyright 2005-2007 Richard Woolcock.  All rights reserved.

 Redistribution and use in source and binary forms, with or without 
 modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, 
   this list of conditions and the following disclaimer. 

 * Redistributions in binary form must reproduce the above copyright notice, 
   this list of conditions and the following disclaimer in the documentation 
   and/or other materials provided with the distribution. 

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/

/******************************************************************************
 Headers
 ******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "card.h"
#include "hand.h"

/******************************************************************************
 Global functions
 ******************************************************************************/

/* Function: HandCreate
 *
 * This function creates a new, empty hand.
 *
 * Arguments: None.
 *
 * Returns: Pointer to the newly created hand, or NULL.
 */
hand_t *HandCreate( void )
{
   hand_t *pHand = (hand_t*) malloc( sizeof(hand_t) );

   if ( pHand != NULL )
   {
      /* Initialise the empty hand */
      pHand->Size    = 0;
      pHand->Bet     = 0;
      pHand->bDealer = eFalse;
      pHand->pHeld   = NULL;
   }

   /* This may return NULL, if malloc fails */
   return pHand;
}

/* Function: HandAddCard
 *
 * This function adds the specified card to the hand.  If the hand hasn't 
 * been initialised, or if it already has that card, the function will fail.
 *
 * Arguments: The hand, and the card to add to it.
 *
 * Returns: A boolean flag indicating whether this operation succeeded.
 */
boolean_t HandAddCard( hand_t *apHand, card_t aCard )
{
   boolean_t bSuccess = eFalse;

   if ( apHand != NULL && aCard < eCardMax )
   {
      held_card_t *pHeld; /* Used for the list search */

      /* Create a new held card to be added to the hand */
      held_card_t *pNewHeld = (held_card_t*) malloc( sizeof(held_card_t) );
      pNewHeld->Card = aCard;
      pNewHeld->pNext = NULL;

      /* If we've got this far, assume success */
      bSuccess = eTrue;

      for ( pHeld = apHand->pHeld; pHeld != NULL; pHeld = pHeld->pNext )
      {
         if ( pHeld->Card == aCard )
         {
            /* They've already got that card! */
            free(pNewHeld);
            bSuccess = eFalse;
         }
      }

      if ( bSuccess )
      {
         /* Set the new card to point to the previous front card */
         pNewHeld->pNext = apHand->pHeld;

         /* Set the hand to point to the new card */
         apHand->pHeld = pNewHeld;

         /* Increment the number of cards in the hand */
         ++apHand->Size;
      }
   }

   return bSuccess;
}

/* Function: HandRemoveCard
 *
 * This function removes the specified card from the hand.  If the hand hasn't 
 * been initialised, or if it isn't holding the specified card, the function 
 * will fail.
 *
 * Arguments: The hand, and the card to remove from it.
 *
 * Returns: A boolean flag indicating whether this operation succeeded.
 */
boolean_t HandRemoveCard( hand_t *apHand, card_t aCard )
{
   if ( apHand != NULL )
   {
      held_card_t *pHeld = apHand->pHeld;
      held_card_t *pPrev = NULL;

      while ( pHeld != NULL )
      {
         if ( pHeld->Card == aCard )
         {
            /* Remove the node from the list */
            if ( pPrev != NULL )
               pPrev->pNext = pHeld->pNext;
            else /* It was the first entry */
               apHand->pHeld = pHeld->pNext;

            /* Decrement the number of cards in the hand */
            --apHand->Size;

            /* Destroy the card */
            free(pHeld);

            /* Indicate success */
            return eTrue;
         }

         /* Increment to the next list node, but store the current one */
         pPrev = pHeld;
         pHeld = pHeld->pNext;
      }
   }

   return eFalse;
}

/* Function: HandCountCards
 *
 * This function returns the number of cards in the hand.  The same result 
 * can be gained simply from checking apHand->Size, but the MudMagic Code 
 * Challenge requirements specified that this functionality should be
 * available as a function, so better safe than sorry!
 *
 * Arguments: Pointer to the hand to be counted.
 *
 * Returns: A integer, containing the number of held cards.
 */
int HandCountCards( hand_t *apHand )
{
   int Total = 0;

   if ( apHand != NULL )
      Total = apHand->Size;

   return Total;
}

/* Function: HandGetSuit
 *
 * This function returns the number of cards in the hand which belong to the 
 * specified suit.  Note that the MudMagic Code Challenge only stated that 
 * the function should return true if any matching cards existed, but that 
 * is still technically what this does (in C, 'true' is defined as any value 
 * other than zero).  However for many card games it is important to know 
 * how many of a particular suit there are, which is why I did it this way.
 *
 * Arguments: Pointer to the hand, and the suit type.
 *
 * Returns: A integer, containing the number of matching cards.
 */
int HandGetSuit( hand_t *apHand, suit_t aSuit )
{
   int Total = 0;

   if ( apHand != NULL && apHand->pHeld != NULL )
   {
      held_card_t *pHeld; /* Used for the list search */

      for ( pHeld = apHand->pHeld; pHeld != NULL; pHeld = pHeld->pNext )
      {
         /* If the card matches the required suit, increment the total */
         Total += (CardValue(pHeld->Card)[0] == CardSuitRepresentation(aSuit));
      }
   }

   return Total;
}

/* Function: HandGetRank
 *
 * This function returns the number of cards in the hand which have the 
 * specified rank.  Note that the MudMagic Code Challenge only stated that 
 * the function should return true if any matching cards existed, but that 
 * is still technically what this does (in C, 'true' is defined as any value 
 * other than zero).  However for many card games it is important to know 
 * how many of a particular rank there are, which is why I did it this way.
 *
 * Arguments: Pointer to the hand, and the rank type.
 *
 * Returns: A integer, containing the number of matching cards.
 */
int HandGetRank( hand_t *apHand, rank_t aRank )
{
   int Total = 0;

   if ( apHand != NULL && apHand->pHeld != NULL )
   {
      held_card_t *pHeld; /* Used for the list search */

      for ( pHeld = apHand->pHeld; pHeld != NULL; pHeld = pHeld->pNext )
      {
         /* If the card matches the required rank, increment the total */
         Total += (CardValue(pHeld->Card)[1] == CardRankRepresentation(aRank));
      }
   }

   return Total;
}

/* Function: HandGetSuitRank
 *
 * This function returns a boolean flag to indicate whether the hand contains 
 * the card of the specific suit and rank.
 *
 * Arguments: Pointer to the hand, the suit type, and the rank.
 *
 * Returns: A boolean, indicating whether or not the card is in the hand.
 */
boolean_t HandGetSuitRank( hand_t *apHand, suit_t aSuit, rank_t aRank )
{
   if ( apHand != NULL && apHand->pHeld != NULL )
   {
      held_card_t *pHeld; /* Used for the list search */

      for ( pHeld = apHand->pHeld; pHeld != NULL; pHeld = pHeld->pNext )
      {
         /* Check if the card matches the specified suit */
         if ( CardValue(pHeld->Card)[0] == CardSuitRepresentation(aSuit) )
         {
            /* Check if the card matches the specified rank */
            if ( CardValue(pHeld->Card)[1] == CardRankRepresentation(aRank) )
            {
               /* The card of the specific suit and rank was found */
               return eTrue;
            }
         }
      }
   }

   /* The card was not found */
   return eFalse;
}

/* Function: HandShow
 *
 * This function generates a string containing a list of all the card values 
 * in the specified hand.
 *
 * Arguments: Pointer to the hand to be shown.
 *
 * Returns: Pointer to a static string containing the card values.
 */
const char *HandShow( hand_t *apHand, boolean_t abGraphical )
{
   static char HandBuffer[512];

   /* Clear the buffer */
   HandBuffer[0] = '\0';

   if ( apHand != NULL && apHand->pHeld != NULL )
   {
      held_card_t *pHeld = apHand->pHeld; /* Used for the list search */
      int Pos = 0;              /* The current position in the string */

      for ( ; pHeld != NULL; pHeld = pHeld->pNext )
      {
         sprintf( &HandBuffer[Pos], "%-3s", CardValue(pHeld->Card) );
         Pos += 3;
      }
   }

   if ( abGraphical == eTrue )
   {
      int Max = strlen(HandBuffer);
      int Cards = Max/3;

      if ( Cards <= 10 )
      {
         int i, j; /* Loop counters */
         static char GraphicBuffer[2048];

         GraphicBuffer[0] = '\0';

         /* Go through the first row. */
         for ( i = 0; i < 11; ++i )
         {
            for ( j = 0; j < Max && j < 15; j += 3 )
            {
               strcat( GraphicBuffer, 
                  CardGraphicRepresentation( i, 
                  CardSuit(HandBuffer[j]), CardRank(HandBuffer[j+1]) ) );
               strcat( GraphicBuffer, "  " );
            }
            strcat( GraphicBuffer, "\n\r" );
         }

         /* Draw a second row if required. */
         if ( Cards > 5 )
         {
            /* Go through the second row. */
            for ( i = 0; i < 11; ++i )
            {
               for ( j = 15; j < Max; j += 3 )
               {
                  strcat( GraphicBuffer, 
                     CardGraphicRepresentation( i, 
                     CardSuit(HandBuffer[j]), CardRank(HandBuffer[j+1]) ) );
                  strcat( GraphicBuffer, "  " );
               }
               strcat( GraphicBuffer, "\n\r" );
            }
         }

         return GraphicBuffer;
      }
      else /* Add a newline, as the caller isn't expecting to have to add it */
      {
         strcat( HandBuffer, "\n\r" );
      }
   }

   return HandBuffer;
}