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"

/******************************************************************************
 Local literals
 ******************************************************************************/

typedef struct
{
   card_t      Card;
   const char *pValue;
   const char *pName;
} card_info_t;

/******************************************************************************
 Local structures
 ******************************************************************************/

card_info_t CardTable[eCardMax] = 
{
   { eCardAceClubs,      "CA", "Ace of Clubs"      }, 
   { eCard2Clubs,        "C2", "Two of Clubs"      }, 
   { eCard3Clubs,        "C3", "Three of Clubs"    }, 
   { eCard4Clubs,        "C4", "Four of Clubs"     }, 
   { eCard5Clubs,        "C5", "Five of Clubs"     }, 
   { eCard6Clubs,        "C6", "Six of Clubs"      }, 
   { eCard7Clubs,        "C7", "Seven of Clubs"    }, 
   { eCard8Clubs,        "C8", "Eight of Clubs"    }, 
   { eCard9Clubs,        "C9", "Nine of Clubs"     }, 
   { eCard10Clubs,       "CT", "Ten of Clubs"      }, 
   { eCardJackClubs,     "CJ", "Jack of Clubs"     }, 
   { eCardQueenClubs,    "CQ", "Queen of Clubs"    }, 
   { eCardKingClubs,     "CK", "King of Clubs"     }, 
   { eCardAceSpades,     "SA", "Ace of Spades"     }, 
   { eCard2Spades,       "S2", "Two of Spades"     }, 
   { eCard3Spades,       "S3", "Three of Spades"   }, 
   { eCard4Spades,       "S4", "Four of Spades"    }, 
   { eCard5Spades,       "S5", "Five of Spades"    }, 
   { eCard6Spades,       "S6", "Six of Spades"     }, 
   { eCard7Spades,       "S7", "Seven of Spades"   }, 
   { eCard8Spades,       "S8", "Eight of Spades"   }, 
   { eCard9Spades,       "S9", "Nine of Spades"    }, 
   { eCard10Spades,      "ST", "Ten of Spades"     }, 
   { eCardJackSpades,    "SJ", "Jack of Spades"    }, 
   { eCardQueenSpades,   "SQ", "Queen of Spades"   }, 
   { eCardKingSpades,    "SK", "King of Spades"    }, 
   { eCardAceHearts,     "HA", "Ace of Hearts"     }, 
   { eCard2Hearts,       "H2", "Two of Hearts"     }, 
   { eCard3Hearts,       "H3", "Three of Hearts"   }, 
   { eCard4Hearts,       "H4", "Four of Hearts"    }, 
   { eCard5Hearts,       "H5", "Five of Hearts"    }, 
   { eCard6Hearts,       "H6", "Six of Hearts"     }, 
   { eCard7Hearts,       "H7", "Seven of Hearts"   }, 
   { eCard8Hearts,       "H8", "Eight of Hearts"   }, 
   { eCard9Hearts,       "H9", "Nine of Hearts"    }, 
   { eCard10Hearts,      "HT", "Ten of Hearts"     }, 
   { eCardJackHearts,    "HJ", "Jack of Hearts"    }, 
   { eCardQueenHearts,   "HQ", "Queen of Hearts"   }, 
   { eCardKingHearts,    "HK", "King of Hearts"    }, 
   { eCardAceDiamonds,   "DA", "Ace of Diamonds"   }, 
   { eCard2Diamonds,     "D2", "Two of Diamonds"   }, 
   { eCard3Diamonds,     "D3", "Three of Diamonds" }, 
   { eCard4Diamonds,     "D4", "Four of Diamonds"  }, 
   { eCard5Diamonds,     "D5", "Five of Diamonds"  }, 
   { eCard6Diamonds,     "D6", "Six of Diamonds"   }, 
   { eCard7Diamonds,     "D7", "Seven of Diamonds" }, 
   { eCard8Diamonds,     "D8", "Eight of Diamonds" }, 
   { eCard9Diamonds,     "D9", "Nine of Diamonds"  }, 
   { eCard10Diamonds,    "DT", "Ten of Diamonds"   }, 
   { eCardJackDiamonds,  "DJ", "Jack of Diamonds"  }, 
   { eCardQueenDiamonds, "DQ", "Queen of Diamonds" }, 
   { eCardKingDiamonds,  "DK", "King of Diamonds"  }
};

const char *CardGraphicTable[eSuitMax][11] = 
{
   { /* eSuitClubs */
      " ----------- ",
      "|%-2s         |",
      "|    ###    |",
      "|    ###    |",
      "| ##  #  ## |",
      "| ######### |",
      "| ##  #  ## |",
      "|     #     |",
      "|     #     |",
      "|         %2s|",
      " ----------- "
   }, 
   { /* eSuitSpades */
      " ----------- ",
      "|%-2s         |",
      "|     #     |",
      "|    ###    |",
      "|   #####   |",
      "|  #######  |",
      "|   #####   |",
      "|     #     |",
      "|    ###    |",
      "|         %2s|",
      " ----------- "
   }, 
   { /* eSuitHearts */
      " ----------- ",
      "|%-2s         |",
      "|           |",
      "|   ## ##   |",
      "|  #######  |",
      "|   #####   |",
      "|    ###    |",
      "|     #     |",
      "|           |",
      "|         %2s|",
      " ----------- "
   }, 
   { /* eSuitDiamonds */
      " ----------- ",
      "|%-2s         |",
      "|     #     |",
      "|    ###    |",
      "|   #####   |",
      "|  #######  |",
      "|   #####   |",
      "|    ###    |",
      "|     #     |",
      "|         %2s|",
      " ----------- "
   }
};

/******************************************************************************
 Local variables
 ******************************************************************************/

static boolean_t s_bInit = eFalse;

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

/* Function: CardInit
 *
 * This function seeds the random number generator (used by DeckShuffle), then 
 * goes through the CardTable making sure that it is properly aligned with the 
 * enum defined in the header.  Unfortunately there is no easy way to match an 
 * enum with a string in C, so this works as a sort of automated checker to 
 * make sure you've not accidently messed up the ordering.  This function is 
 * automatically called the first time you use DeckCreate(), and subsequent 
 * calls are ignored (unless it failed the previous time).
 *
 * Arguments: None.
 *
 * Returns: A boolean flag indicating whether initialisation was successful.
 */
boolean_t CardInit( void )
{
   if ( s_bInit == eFalse )
   {
      int i; /* Loop counter */
      s_bInit = eTrue;

      /* Seed the random numbers, used for shuffling */
      srand(time(0));

      /* Varify that the card structure is correctly aligned */
      for ( i = 0; i < eCardMax; ++i )
      {
         if ( CardTable[i].Card != i )
         {
            /* You may want to replace this with mud log/error message */
            printf( "CardInit: Card '%s' is not aligned with its enum.\n\r", 
               CardTable[i].pName );
            s_bInit = eFalse;
         }
      }
   }

   return s_bInit;
}

/* Function: CardValue
 *
 * This function returns the value of the specified card.  For example the 
 * Queen of Hearts would be returned as 'HQ', stored as a string.  If an 
 * invalid card type is passed in, the function will return '??'.
 *
 * Arguments: The card you want to know the value of.
 *
 * Returns: A constant string, containing the card value.
 */
const char *CardValue( card_t aCard )
{
   const char *pResult = "??";

   if ( aCard >= eCardAceClubs && aCard <= eCardKingDiamonds )
   {
      /* Retrieve the value of the card (eg 'C5') */
      pResult = CardTable[aCard].pValue;
   }

   return pResult;
}

/* Function: CardName
 *
 * This function returns the name of the specified card.  For example the 
 * Queen of Hearts would be literally returned as 'Queen of Hearts', stored 
 * as a string.  If an invalid card type is passed in, the function will 
 * return 'Invalid card'.
 *
 * Arguments: The card you want to know the name of.
 *
 * Returns: A constant string, containing the card name.
 */
const char *CardName( card_t aCard )
{
   const char *pResult = "Invalid card";

   if ( aCard >= eCardAceClubs && aCard <= eCardKingDiamonds )
   {
      /* Retrieve the full name of the card (eg 'Five of Clubs') */
      pResult = CardTable[aCard].pName;
   }

   return pResult;
}

/* Function: CardType
 *
 * This function returns the card type by combining the specified suit and 
 * rank.  For example if you give it eSuitClubs and eRankFive, it will return 
 * eCard5Clubs.  If an invalid suit or rank are give, the function will 
 * return eCardMax.
 *
 * Arguments: The suit and rank you wish to find the card type of.
 *
 * Returns: The card type.
 */
card_t CardType( suit_t aSuit, rank_t aRank )
{
   card_t Card = eCardMax;

   if ( aSuit < eSuitMax && aRank < eRankMax )
   {
      int i; /* Loop counter */
      char Value[3] = { '\0' };

      Value[0] = CardSuitRepresentation(aSuit);
      Value[1] = CardRankRepresentation(aRank);

      for ( i = eCardAceClubs; i < eCardMax && Card == eCardMax; ++i )
      {
         if ( !strcmp(CardTable[i].pValue, Value) )
            Card = (card_t)i;
      }
   }

   return Card;
}

/* Function: CardRank
 *
 * This function returns the rank of the specified character representation - 
 * for example, 'A' would return eValueAce.
 *
 * Arguments: The character representation you want to know the rank of.
 *
 * Returns: The rank.
 */
rank_t CardRank( char aRankRepresentation )
{
   rank_t Result;

   switch ( aRankRepresentation )
   {
      case 'A':
         Result = eRankAce;
         break;
      case '2':
         Result = eRankTwo;
         break;
      case '3':
         Result = eRankThree;
         break;
      case '4':
         Result = eRankFour;
         break;
      case '5':
         Result = eRankFive;
         break;
      case '6':
         Result = eRankSix;
         break;
      case '7':
         Result = eRankSeven;
         break;
      case '8':
         Result = eRankEight;
         break;
      case '9':
         Result = eRankNine;
         break;
      case 'T':
         Result = eRankTen;
         break;
      case 'J':
         Result = eRankJack;
         break;
      case 'Q':
         Result = eRankQueen;
         break;
      case 'K':
         Result = eRankKing;
         break;
      default: /* Invalid rank type */
         Result = eRankMax;
   }

   return Result;
}

/* Function: CardRankRepresentation
 *
 * This function returns the character representation of the specified rank - 
 * for example, eValueAce would return 'A'.
 *
 * Arguments: The rank you want to know the character representation of.
 *
 * Returns: The character representation.
 */
char CardRankRepresentation( rank_t aRank )
{
   char Result;

   switch ( aRank )
   {
      case eRankAce:
         Result = 'A';
         break;
      case eRankTwo:
         Result = '2';
         break;
      case eRankThree:
         Result = '3';
         break;
      case eRankFour:
         Result = '4';
         break;
      case eRankFive:
         Result = '5';
         break;
      case eRankSix:
         Result = '6';
         break;
      case eRankSeven:
         Result = '7';
         break;
      case eRankEight:
         Result = '8';
         break;
      case eRankNine:
         Result = '9';
         break;
      case eRankTen:
         Result = 'T';
         break;
      case eRankJack:
         Result = 'J';
         break;
      case eRankQueen:
         Result = 'Q';
         break;
      case eRankKing:
         Result = 'K';
         break;
      default: /* Invalid rank type */
         Result = '?';
   }

   return Result;
}

/* Function: CardSuit
 *
 * This function returns the suit of the specified character representation - 
 * for example, 'C' would return eSuitClubs.
 *
 * Arguments: The character representation you want to know the suit of.
 *
 * Returns: The suit.
 */
suit_t CardSuit( char aSuitRepresentation )
{
   suit_t Result;

   switch ( aSuitRepresentation )
   {
      case 'C':
         Result = eSuitClubs;
         break;
      case 'S':
         Result = eSuitSpades;
         break;
      case 'H':
         Result = eSuitHearts;
         break;
      case 'D':
         Result = eSuitDiamonds;
         break;
      default: /* Invalid suit type */
         Result = eSuitMax;
   }

   return Result;
}

/* Function: CardSuitRepresentation
 *
 * This function returns the character representation of the specified suit - 
 * for example, eSuitClubs would return 'C'.
 *
 * Arguments: The suit you want to know the character representation of.
 *
 * Returns: The character representation.
 */
char CardSuitRepresentation( suit_t aSuit )
{
   char Result;

   switch ( aSuit )
   {
      case eSuitClubs:
         Result = 'C';
         break;
      case eSuitSpades:
         Result = 'S';
         break;
      case eSuitHearts:
         Result = 'H';
         break;
      case eSuitDiamonds:
         Result = 'D';
         break;
      default: /* Invalid suit type */
         Result = '?';
   }

   return Result;
}

/* Function: CardGraphicRepresentation
 *
 * This function returns the character representation of the specified row 
 * of the specified card suit and rank.
 *
 * Arguments: The row of the card to show, and its suit/rank.
 *
 * Returns: The representation of the required row.
 */
const char *CardGraphicRepresentation( int aRow, suit_t aSuit, rank_t aRank )
{
   static char CardRow[14];

   if ( aSuit < eSuitMax && aRank < eRankMax )
   {
      if ( aRow == 1 || aRow == 9 )
      {
         char Rank[3] = {'\0', '\0', '\0'};
         Rank[0] = CardRankRepresentation(aRank);
         if ( Rank[0] == 'T' )
         {
            Rank[0] = '1';
            Rank[1] = '0';
         }

         sprintf( CardRow, CardGraphicTable[aSuit][aRow], Rank );
      }
      else /* Don't display the rank on this row */
      {
         sprintf( CardRow, CardGraphicTable[aSuit][aRow] );
      }
   }
   else /* Invalid card, so display a blank */
   {
      strcpy( CardRow, "             " );
   }

   return CardRow;
}