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 "card.h"
#include "deck.h"

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

/* Function: DeckCreate
 *
 * This function creates a new deck of cards.  It will also call the CardInit()
 * function which will seed the random numbers used for shuffling the deck.
 *
 * Arguments: None.
 *
 * Returns: Pointer to the newly created deck, or NULL.
 */
deck_t *DeckCreate( void )
{
   deck_t *pDeck = NULL;

   if ( CardInit() == eTrue )
   {
      pDeck = (deck_t*)malloc( sizeof(deck_t) );

      if ( pDeck != NULL )
      {
         int i; /* Loop counter */

         /* The deck starts off full */
         pDeck->Size = eCardMax;

         /* There is nobody using the deck to start with */
         pDeck->Instances = 0;

         /* Clear the bet and the pot */
         pDeck->Bet = 0;
         pDeck->Pot = 0;

         /* Start on turn 0 */
         pDeck->Turn = 0;

         /* There is no game being played */
         pDeck->Playing = eFalse;

         /* Initialise each card in the deck */
         for ( i = 0; i < eCardMax; ++i )
         {
            /* Set the card, and indicate that it's not been drawn */
            pDeck->Card[i]  = (card_t)i;
            pDeck->Drawn[i] = eFalse;
         }
      }
   }

   /* This will be NULL if initialisation or malloc failed */
   return pDeck;
}

/* Function: DeckShuffle
 *
 * This function shuffles the deck.  It does this by looping through the 
 * entire deck, with every undrawn card being swapped with one other undrawn 
 * card picked at random from the deck.
 *
 * Arguments: Pointer to the deck to be shuffled.
 *
 * Returns: Nothing.
 */
void DeckShuffle( deck_t *apDeck )
{
   if ( apDeck != NULL )
   {
      int i; /* Loop counter */

      /* Loop through every undrawn card in the deck */
      for ( i = 0; i < apDeck->Size; ++i )
      {
         card_t CardSwap; /* Temporary swap variable */

         /* Pick another card, ensuring a card cannot be swapped with itself */
         int SwapWith = (rand()%(apDeck->Size-1));
         if ( SwapWith >= i )
            SwapWith++;

         /* Swap the two cards */
         CardSwap = apDeck->Card[i];
         apDeck->Card[i] = apDeck->Card[SwapWith];
         apDeck->Card[SwapWith] = CardSwap;
      }
   }
}

/* Function: DeckDrawCard
 *
 * This function draws the top card from the deck.  If there is not a valid 
 * deck to draw from, or the deck is empty, then the function will return 
 * eCardMax.  Otherwise it will return the value of the top card, flag it as 
 * drawn, and lower the number of undrawn cards in the deck by 1.
 *
 * Arguments: Pointer to the deck to be shuffled.
 *
 * Returns: The enumerated value of the top card.
 */
card_t DeckDrawCard( deck_t *apDeck )
{
   card_t Card = eCardMax;

   if ( apDeck != NULL )
   {
      if ( apDeck->Size > 0 )
      {
         /* Pull the card off the deck */
         apDeck->Size--;
         Card = apDeck->Card[apDeck->Size];
         apDeck->Drawn[apDeck->Size] = eTrue;
      }
   }

   return Card;
}

/* Function: DeckReturnCard
 *
 * This function returns the specified card to the bottom of the deck, and 
 * will return 'false' if the deck is invalid, or if it already contains the 
 * specified card.  If successful, this function will move the specified card 
 * to the end of the deck and flag it as undrawn, then return 'true'.
 *
 * Arguments: Pointer to the deck to be shuffled, and the card to return.
 *
 * Returns: A boolean flag to indicate success or failure.
 */
boolean_t DeckReturnCard( deck_t *apDeck, card_t aCard )
{
   boolean_t bSuccess = eFalse;

   if ( apDeck != NULL )
   {
      int i; /* Loop counter */

      /* Search through the deck until a match is found */
      for ( i = 0; i < eCardMax && bSuccess == eFalse; ++i )
      {
         /* Find the card being returned */
         if ( apDeck->Card[i] == aCard )
         {
            /* Make sure that card isn't already in the deck */
            if ( apDeck->Drawn[i] == eTrue )
            {
               int j; /* Nested loop counter */

               /* Shuffle the other cards up one position */
               for ( j = i; j > 0; --j )
               {
                  apDeck->Card[j] = apDeck->Card[j-1];
                  apDeck->Drawn[j] = apDeck->Drawn[j-1];
               }

               /* Set the returned card as being no longer drawn */
               apDeck->Card[0] = aCard;
               apDeck->Drawn[0] = eFalse;

               /* Increment the number of undrawn cards in the deck */
               apDeck->Size++;

               /* Indicate that the card was successfully returned */
               bSuccess = eTrue;
            }
         }
      }
   }

   return bSuccess;
}

/* Function: DeckCountCards
 *
 * This function returns the number of undrawn cards in the deck.  The same 
 * result can be gained simply from checking apDeck->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 deck to be counted.
 *
 * Returns: A integer, containing the number of undrawn cards.
 */
int DeckCountCards( deck_t *apDeck )
{
   int Total = 0;

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

   return Total;
}

/* Function: DeckReset
 *
 * This function flags every card in the deck as 'undrawn'.  The ordering of 
 * the cards will remain unchanged, so the caller will probably want to call 
 * DeckShuffle() afterwards.
 *
 * Arguments: Pointer to the deck to be reset.
 *
 * Returns: Nothing.
 */
void DeckReset( deck_t *apDeck )
{
   if ( apDeck != NULL )
   {
      int i; /* Loop counter */

      /* Ensure that every card has been returned to the deck */
      for ( i = 0; i < eCardMax; ++i )
         apDeck->Drawn[i] = eFalse;

      /* Set the size of the deck back to full */
      apDeck->Size = eCardMax;
   }
}

/* Function: DeckShow
 *
 * This function generates a string containing a list of all the undrawn card 
 * values in the deck.  The 'abUndrawn' flag, when set, will display drawn 
 * cards as '--', while the 'abFormat' flag will add newlines for formatting 
 * purposes.  These functions make it much easier for testing the function as 
 * part of a standalone application.
 *
 * Arguments: Pointer to the deck, a boolean flags for displaying drawn cards,
 *            and another boolean flag for formatting the output with newlines.
 *
 * Returns: Pointer to a static string containing the card values.
 */
const char *DeckShow( deck_t *apDeck, boolean_t abUndrawn, boolean_t abFormat )
{
   static char DeckBuffer[512];
   int i;         /* Loop counter                               */
   int Pos = 0;   /* The current position in the string         */
   int Count = 0; /* Count the number of cards displayed so far */

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

   /* Go through the deck in reverse order (it's stored upside down) */
   for ( i = eCardMax-1; i >= 0 ; --i )
   {
      /* Ignore cards that have already been drawn from the deck */
      if ( apDeck->Drawn[i] == eFalse || abUndrawn == eTrue )
      {
         if ( apDeck->Drawn[i] == eFalse )
            sprintf( &DeckBuffer[Pos], "%-3s", CardValue(apDeck->Card[i]) );
         else /* It's an undrawn drawn card */
            sprintf( &DeckBuffer[Pos], "-- " );

         Pos += 3;

         /* Add newlines, if required */
         if ( abFormat == eTrue && (++Count%26) == 0 )
         {
            strcat( DeckBuffer, "\n\r" );
            Pos += 2;
         }
      }
   }

   /* Add another newline to the end, if required */
   if ( abFormat && (Count%26) != 0 )
      strcat( DeckBuffer, "\n\r" );

   return DeckBuffer;
}