Bridge Player

This is the start of a bridge playing program. It has zero bidding and playing intelligence though. Someday ...

It does know how to shuffle, deal, etc. It knows what bids are legal and what plays are legal. It also knows how to count points and how to keep score.

Bridge.c - main source file
Bridge.h - include file
Display.c - source file for printing hands
Bid.c - source file for bidding
Play.c - source file for playing
Score.c - source file for keeping score
          North (7+2=9)
          S: T 2
          H: A T 9 2
          D: 4 2
          C: K 9 6 4 3

West (4+1=5)           East (13+2=15)
S: 6 5 4               S: K Q 9 8 3
H: Q 8 6               H: K 4
D: J T 7 5 3           D: K Q 9 8
C: J 5                 C: 8 7

         South (16+1=17)
         S: A J 7
         H: J 7 5 3
         D: A 6
         C: A Q T 2

Bridge.c - main source file

   1: /* Bridge -- Steve O'Hara -- 1/12/94 */
   2: 
   3: #include <time.h>
   4: 
   5: #include "Bridge.h"
   6: 
   7: char SuitChar[NSUITSNT] = "CDHSN";
   8: char *SuitName[] = {"Club", "Diamond", "Heart", "Spade", "No Trump"};
   9: char *SuitNames[] = {"Clubs", "Diamonds", "Hearts", "Spades", "No Trump"};
  10: 
  11: char CardChar[NCARDS] = "23456789TJQKA";
  12: char *CardName[] = {"2", "3", "4", "5", "6", "7", "8", "9",
  13: 					"Ten", "Jack", "Queen", "King", "Ace"};
  14: 							
  15: char PlayerChar[NPLAYERS] = "SWNE";
  16: char *PlayerName[] = {"South", "West", "North", "East"};
  17: int LeftOf[NPLAYERS] = {West, North, East, South};
  18: 
  19: char *TeamAbbrev[NTEAMS] = {"N-S", "E-W"};
  20: char *TeamName[NTEAMS] = {"North-South", "East-West"};
  21: int Other[NTEAMS] = {EW, NS};
  22: int Team[NPLAYERS] = {NS, EW, NS, EW};
  23: 
  24: unsigned int Seed;		/* Easier this way */
  25: int Hand;
  26: 
  27: 
  28: /* Returns a number a <= x < b */
  29: /* So random(0,4) will be in {0,1,2,3} */
  30: int random (int a, int b)
  31: {
  32: 	int		r;
  33: 	
  34: 	r = (int) ((b-a) * (rand()/(RAND_MAX+1.0))) + a;
  35: 	return r;
  36: } /* End of random */
  37: 
  38: 
  39: static int initRand ()
  40: {
  41: 	char	ans[80];
  42:     
  43:     while (1)
  44:     {
  45: 		printf ("\nEnter seed [q to quit or press return] -->");
  46: 		gets (ans);
  47: 		if (tolower (ans[0]) == 'q') return 0;
  48: 		if (ans[0] == '\0')
  49: 		{
  50: 			Seed = clock ();
  51: 			printf ("Seed = %u\n", Seed);
  52: 		}
  53: 		else
  54: 		{
  55: 			if (sscanf (ans, "%u", &Seed) != 1)
  56: 			{
  57: 				fprintf (stderr, "\nInvalid seed: %s\n", ans);
  58: 				continue;
  59: 			}
  60: 		}
  61: 	    srand (Seed);
  62: 	    return 1;
  63:     }
  64: } /* End of initRand */
  65: 
  66: 
  67: static void shuffle (int *deck)
  68: {
  69: 	int		i, j, k;
  70: 	int		temp;
  71: 	int		times;
  72: 	
  73: 	/* First, initialize the deck */
  74: 	for (i=0; i<DECKSIZE; i++) deck[i] = i;
  75: 	
  76: 	/* Now shuffle */
  77: 	times = random (100, 500);
  78: 	for (i=0; i<times; i++)
  79: 	{
  80: 		j = random (0, DECKSIZE);
  81: 		k = random (0, DECKSIZE);
  82: 		temp = deck[j];
  83: 		deck[j] = deck[k];
  84: 		deck[k] = temp;
  85: 	}
  86: } /* End of shuffle */
  87: 
  88: 
  89: int suitLength (Boolean haveIt[NCARDS])
  90: {
  91: 	int		card;
  92: 	int		k;
  93: 	
  94: 	k = 0;
  95: 	for (card=0; card<NCARDS; card++)
  96: 	{
  97: 		if (haveIt[card]) k++;
  98: 	}
  99: 	return k;
 100: } /* End of suitLength */
 101: 
 102: 
 103: int highestCard (Boolean haveIt[NCARDS])
 104: {
 105: 	int		card;
 106: 	
 107: 	for (card=NCARDS-1; card>=0; card--)
 108: 	{
 109: 		if (haveIt[card]) return card;
 110: 	}
 111: 	return NoCard;
 112: } /* End of highestCard */
 113: 
 114: 
 115: static void deal (int *deck, Boolean haveIt[NPLAYERS][NSUITS][NCARDS])
 116: {
 117: 	int		card;
 118: 	int		i, j, k;
 119: 	
 120: 	/* Initialize all to False */
 121: 	for (i=0; i<NPLAYERS; i++)
 122: 	{
 123: 		for (j=0; j<NSUITS; j++)
 124: 		{
 125: 			for (k=0; k<NCARDS; k++)
 126: 			{
 127: 				haveIt[i][j][k] = False;
 128: 			}
 129: 		}
 130: 	}
 131: 	
 132: 	/* Now see what they really have */
 133: 	for (card=0; card<DECKSIZE; card++)
 134: 	{
 135: 		i = card % NPLAYERS;		/* Who gets this card? */
 136: 		j = deck[card] / NCARDS;	/* What suit is it? */
 137: 		k = deck[card] % NCARDS;	/* What number (or face card) */
 138: 		haveIt[i][j][k] = True;
 139: 	}
 140: } /* End of deal */
 141: 
 142: 
 143: #if 0
 144: static int playHand (int level, int trump, int declarer, int *made)
 145: {
 146: 	char	ans[80];
 147: 	
 148: 	*made = 0;
 149: 	while (1)
 150: 	{
 151: 		printf ("\nHow many tricks did %s make at %d%c -->",
 152: 				PlayerName[declarer], level, SuitChar[trump]);
 153: 		gets (ans);
 154: 		sscanf (ans, "%d", made);
 155: 		if (*made > 0 && *made <= NCARDS) return 1;
 156: 		printf ("Must be from 1 to %d\n", NCARDS);
 157: 	}
 158: } /* End of playHand */
 159: #endif
 160: 
 161: 
 162: #if 0
 163: /* Fails only if all 4 pass */
 164: static int fakeBid (int *level, int *trump, int *dbl, int *bidder, int *made)
 165: {
 166: 	char	ans[80];
 167: 	char	ch;
 168: 	char	decl[20];
 169: 	int		i;
 170: 	int		ok;
 171: 	char	suit[20];
 172: 
 173: 	while (1)
 174: 	{
 175: 		printf ("\nEnter bid declarer tricks [4HD E 10] -->");
 176: 		gets (ans);
 177: 		
 178: 		/* If just hit return, make something up! */
 179: 		if (ans[0] == '\0')
 180: 		{
 181: 			*level = random (0, MAXBID) + 1;
 182: 			*trump = random (0, NSUITSNT);
 183: 			*dbl = random (0, NDOUBLES);
 184: 			*bidder = random (0, NPLAYERS);
 185: 			*made = random (7, 13);
 186: 			printf ("%s bid %d %s %s and made %d.\n",
 187: 					PlayerName[*bidder], *level,
 188: 					(*level == 1 ? SuitName[*trump] : SuitNames[*trump]),
 189: 					(*dbl == NoDouble ? "" :
 190: 						(*dbl == Double ? "(Doubled)" : "(Redoubled)")),
 191: 					*made);
 192: 			return 1;
 193: 		}
 194: 		
 195: 		if (strcmp (ans, "pass") == 0) return 0;
 196: 		ok = (sscanf (ans, "%d%s%s%d", level, suit, decl, made) == 4);
 197: 		
 198: 		if (*level < 1 || *level > MAXBID) ok = 0;
 199: 		if (*made < 0 || *made > NCARDS) ok = 0;
 200: 		
 201: 		ch = toupper (suit[0]);
 202: 		for (i=0; i<NSUITSNT; i++)
 203: 		{
 204: 			if (ch == SuitChar[i]) break;
 205: 		}
 206: 		if (i == NSUITSNT) ok = 0;
 207: 		*trump = i;
 208: 		
 209: 		ch = toupper (suit[1]);
 210: 		if (ch == '\0') *dbl = NoDouble;
 211: 		else if (ch == 'D') *dbl = Double;
 212: 		else if (ch == 'R') *dbl = ReDouble;
 213: 		else ok = 0;
 214: 		
 215: 		ch = toupper (decl[0]);
 216: 		for (i=0; i<NPLAYERS; i++)
 217: 		{
 218: 			if (ch == PlayerChar[i]) break;
 219: 		}
 220: 		if (i == NPLAYERS) ok = 0;
 221: 		*bidder = i;
 222: 		
 223: 		if (ok) return 1;
 224: 		
 225: 		/* printf ("%s bid %d %s (dbl=%d), made %d\n", PlayerName[*bidder],
 226: 				*level, SuitName[*trump], *dbl, *made); */
 227: 		printf ("NSD B M is the expected format\n");
 228: 		printf (" where N = 1 to 7    (bid number)\n");
 229: 		printf ("       S = C D H S N (trump)\n");
 230: 		printf ("       D = blank D R (doubles)\n");
 231: 		printf ("       B = S W N E   (bidder)\n");
 232: 		printf ("       M = 1 to 13   (made)\n");
 233: 	}
 234: } /* End of fakeBid */
 235: #endif
 236: 
 237: 
 238: int main ()
 239: {
 240: 	int		above;
 241: 	int		below;
 242: 	int		dealer;
 243: 	int		deck[DECKSIZE];
 244: 	int		declarer;
 245: 	int		doubled;
 246: 	int		games;
 247: 	Boolean	haveIt[NPLAYERS][NSUITS][NCARDS];
 248: 	int		i;
 249: 	int		level;
 250: 	int		made;
 251: 	int		oppAbove;
 252: 	int		pts;
 253: 	int		ptsAbove[NTEAMS];
 254: 	int		ptsBelow[3][NTEAMS];
 255: 	int		ptsTotal[NTEAMS];
 256: 	int		team;
 257: 	int		trump;
 258: 	Boolean	vulnerable[NTEAMS];
 259: 	
 260: 	/* Randomize for who deals first */
 261: 	srand (clock ());
 262: 	dealer = random (0, NPLAYERS);
 263: 	
 264: 	for (team=0; team<NTEAMS; team++)
 265: 	{
 266: 		vulnerable[team] = False;
 267: 		ptsAbove[team] = 0;
 268: 		for (i=0; i<3; i++)
 269: 		{
 270: 			ptsBelow[i][team] = 0;
 271: 		}
 272: 	}
 273: 	games = 0;
 274: 	Hand = 0;
 275: 	
 276: 	FirstScore = NULL;
 277: 	LastScore = NULL;
 278: 		
 279: 	while (1)
 280: 	{
 281: 		if (!initRand ())	/* Pressed Quit */
 282: 		{
 283: 			Hand = 0;
 284: 			
 285: 			/* Check for partial scores */
 286: 			for (team=0; team<NTEAMS; team++)
 287: 			{
 288: 				if (ptsBelow[0][team] >= 100 || ptsBelow[1][team] >= 100)
 289: 				{
 290: 					ptsAbove[team] += 300;
 291: 					scoreItem (team, 300, "one game in unfinished rubber");
 292: 				}
 293: 				if (ptsBelow[games][team] > 0)
 294: 				{
 295: 					ptsAbove[team] += 50;
 296: 					scoreItem (team, 50, "part score in unfinished game");
 297: 				}
 298: 			}
 299: 			break;
 300: 		}
 301: 	
 302: 		shuffle (deck);
 303: 		deal (deck, haveIt);
 304: 		display (stdout, haveIt, True);
 305: 		printf ("\nDealer: %s\n", PlayerName[dealer]);
 306: 		Hand++;
 307: 		
 308: 		/* Get a bogus bid & result */
 309: 		if (getBid (haveIt, dealer, &level, &trump, &doubled, &declarer) &&
 310: 			playHand (level, trump, declarer, haveIt, &made))
 311: 		{
 312: 			/* First, see if anybody got a bonus for 4 aces, etc */
 313: 			i = scoreBonus (haveIt, &pts, trump);
 314: 			if (i != NoPlayer)
 315: 			{
 316: 				ptsAbove[Team[i]] += pts;
 317: 			}
 318: 			
 319: 			team = Team[declarer];
 320: 				
 321: 			/* Now, score the hand by itself */
 322: 			if (scoreHand (level, trump, vulnerable[team], doubled,
 323: 					made, team, &above, &below, &oppAbove))
 324: 			{
 325: 				ptsAbove[team] += above;
 326: 				ptsAbove[Other[team]] += oppAbove;
 327: 				if ((ptsBelow[games][team] += below) >= 100)
 328: 				{
 329: 					if (games == 2)
 330: 					{
 331: 						Hand = 0;
 332: 						ptsAbove[team] += 500;
 333: 						scoreItem (team, 500, "winning 2 of 3 games");
 334: 						break;	/* Won 2 out of 3 games */
 335: 					}
 336: 					if (games == 1 && ptsBelow[0][team] >= 100)
 337: 					{
 338: 						Hand = 0;
 339: 						ptsAbove[team] += 700;
 340: 						scoreItem (team, 700, "winning 2 of 2 games");
 341: 						break;	/* Won 2 out of 2 games */
 342: 					}
 343: 
 344: 					vulnerable[team] = True;
 345: 					games++;
 346: 				}
 347: 			}
 348: 			
 349: 			printf ("\nPartial Score\n");
 350: 			printf ("%5s   %5s\n", TeamAbbrev[NS], TeamAbbrev[EW]);
 351: 			printf ("%5d   %5d\n", ptsAbove[NS], ptsAbove[EW]);
 352: 			printf ("=============\n");
 353: 			printf ("%5d   %5d\n", ptsBelow[0][NS], ptsBelow[0][EW]);
 354: 			if (games > 0)
 355: 			{
 356: 				printf ("-------------\n");
 357: 				printf ("%5d   %5d\n", ptsBelow[1][NS], ptsBelow[1][EW]);
 358: 			}
 359: 			if (games > 1)
 360: 			{
 361: 				printf ("-------------\n");
 362: 				printf ("%5d   %5d\n", ptsBelow[2][NS], ptsBelow[2][EW]);
 363: 			}
 364: 		}
 365: 		
 366: 		/* Shift to the next dealer, to the left */
 367: 		dealer = LeftOf[dealer];
 368: 	}
 369: 	
 370: 	printf ("\n==== Scoring Summary ====\n\n");
 371: 	printf (" Hand  Team  Pts  Explanation.\n");
 372: 	while (FirstScore)
 373: 	{
 374: 		if (FirstScore->hand == 0) printf ("%4c", '-');
 375: 		else printf ("%4d", FirstScore->hand);
 376: 		printf ("  %5s %4d  %s.\n",
 377: 				TeamAbbrev[FirstScore->team],
 378: 				FirstScore->points, FirstScore->msg);
 379: 		FirstScore = FirstScore->next;
 380: 	}
 381: 
 382: 	for (team=0; team<NTEAMS; team++)
 383: 	{
 384: 		ptsTotal[team] = ptsAbove[team] + ptsBelow[0][team] +
 385: 						ptsBelow[1][team] + ptsBelow[2][team];
 386: 	}
 387: 	printf ("\n  Final Score\n");
 388: 	printf ("%5s   %5s\n", TeamAbbrev[NS], TeamAbbrev[EW]);
 389: 	printf ("%5d   %5d\n", ptsAbove[NS], ptsAbove[EW]);
 390: 	printf ("=============\n");
 391: 	printf ("%5d   %5d\n", ptsBelow[0][NS], ptsBelow[0][EW]);
 392: 	printf ("-------------\n");
 393: 	printf ("%5d   %5d\n", ptsBelow[1][NS], ptsBelow[1][EW]);
 394: 	if (games > 1)
 395: 	{
 396: 		printf ("-------------\n");
 397: 		printf ("%5d   %5d\n", ptsBelow[2][NS], ptsBelow[2][EW]);
 398: 	}
 399: 	printf ("=============\n");
 400: 	printf ("%5d   %5d\n", ptsTotal[NS], ptsTotal[EW]);
 401: 
 402: 	return 0;
 403: } /* End of main */
 404: 
 405: /* Sample printing:
 406: 	Enter seed [q to quit or press return] -->
 407: 	Seed = 9299
 408: 	
 409: 	
 410: 	               North (13+4=17)
 411: 	               S: 2
 412: 	               H: A Q 9 8 3 2
 413: 	               D: A K 7 6 4
 414: 	               C: 3
 415: 	West (9+1=10)                 East (8+2=10)
 416: 	S: J 9 8 5 4                  S: A 7
 417: 	H: 6 4                        H: J 5
 418: 	D: J 8 3                      D: Q T 9 5 2
 419: 	C: A K 7                      C: J 8 6 5
 420: 	               South (10+3=13)
 421: 	               S: K Q T 6 3
 422: 	               H: K T 7
 423: 	               D:
 424: 	               C: Q T 9 4 2
 425: 
 426: 
 427: 	==== Scoring Summary ====
 428: 	
 429: 	 Hand  Team  Pts  Explanation.
 430: 	   1    N-S  120  bidding 3 Hearts, making 4.
 431: 	   2    N-S   50  setting 3 No Trump by 1 trick.
 432: 	   3    E-W  160  bidding 4 No Trump, making 5.
 433: 	   4    E-W  120  making 4 Spades.
 434: 	   -    E-W  700  winning 2 of 2 games.
 435: 	
 436: 	  Final Score
 437: 	  N-S     E-W
 438: 	   80     730
 439: 	=============
 440: 	   90     130
 441: 	-------------
 442: 	    0     120
 443: 	=============
 444: 	  170     980
 445: */

Bridge.h - include file

   1: #include <stdio.h>
   2: #include <stdlib.h>
   3: #include <ctype.h>
   4: 
   5: typedef int Boolean;
   6: enum {False, True};
   7: 
   8: enum {NoDouble, Double, ReDouble};
   9: 
  10: #define NSUITS 		4
  11: #define NSUITSNT	(NSUITS+1)	/* Including No Trump */
  12: #define NPLAYERS	4
  13: #define NCARDS 		13
  14: #define DECKSIZE	(NSUITS*NCARDS)
  15: #define NTEAMS		2
  16: #define NDOUBLES	3
  17: 
  18: extern char SuitChar[];
  19: extern char *SuitName[];
  20: extern char *SuitNames[];
  21: enum {Clubs, Diamonds, Hearts, Spades, NoTrump, NoSuit};
  22: 
  23: extern char CardChar[];
  24: extern char *CardName[];
  25: enum {Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten,
  26: 							Jack, Queen, King, Ace, NoCard};
  27: 							
  28: extern char PlayerChar[];
  29: extern char *PlayerName[];
  30: enum {South, West, North, East, NoPlayer};
  31: extern int LeftOf[];
  32: 
  33: extern char *TeamAbbrev[];
  34: extern char *TeamName[];
  35: enum {NS, EW};
  36: extern int Other[];
  37: 
  38: extern int Team[NPLAYERS];
  39: 
  40: typedef struct score_t {
  41: 	int		hand;
  42: 	int		team;
  43: 	int		points;
  44: 	char	*msg;
  45: 	struct score_t *next;
  46: } score_t;
  47: 
  48: extern score_t *FirstScore, *LastScore;
  49: 
  50: #define BOOK 6
  51: #define MAXBID (NCARDS-BOOK)	/* 7 */
  52: 
  53: extern unsigned int Seed;		/* Easier this way */
  54: extern int Hand;
  55: 
  56: extern void scoreItem (int team, int points, char *msg);
  57: extern int scoreHand (int level, int trump, int vulnerable, int doubled,
  58: 			int tricks, int team, int *above, int *below, int *oppAbove);
  59: extern int scoreBonus (Boolean haveIt[NPLAYERS][NSUITS][NCARDS],
  60: 			int *pts, int trump);
  61: extern int getBid (Boolean haveIt[NPLAYERS][NSUITS][NCARDS],
  62: 			int dealer, int *level, int *trump, int *doubled, int *bidder);
  63: extern void display (FILE *out, Boolean haveIt[NPLAYERS][NSUITS][NCARDS],
  64: 			int prtPts);
  65: extern int playHand (int level, int trump, int declarer,
  66: 			Boolean haveIt[NPLAYERS][NSUITS][NCARDS],int *made);
  67: extern int suitLength (Boolean haveIt[NCARDS]);
  68: extern int highestCard (Boolean haveIt[NCARDS]);
  69: extern int random (int a, int b);
  70: 

Display.c - source file for printing hands

   1: #include <string.h>
   2: #include "Bridge.h"
   3: 
   4: static int prtSuit (FILE *out, Boolean haveIt[NSUITS][NCARDS], int suit)
   5: {
   6: 	int		k;
   7: 	int		len;
   8: 	
   9: 	len = 0;	
  10: 	fprintf (out, "%c:", SuitChar[suit]);
  11: 	for (k=NCARDS-1; k>=0; k--)
  12: 	{
  13: 		if (haveIt[suit][k])
  14: 		{
  15: 			len++;
  16: 			fprintf (out, " %c", CardChar[k]);
  17: 		}
  18: 	}
  19: 	
  20: 	return len;
  21: } /* End of prtSuit */
  22: 
  23: 
  24: static void countPoints (Boolean haveIt[NSUITS][NCARDS],
  25: 				int trump, int *hcp, int *dp)
  26: {
  27:     int		cards;
  28:     int		suit;
  29:     
  30:     *hcp = 0;
  31:     *dp = 0;
  32:     for (suit=0; suit<NSUITS; suit++)
  33:     {
  34:     	if (haveIt[suit][Ace]) *hcp += 4;
  35:     	if (haveIt[suit][King]) *hcp += 3;
  36:     	if (haveIt[suit][Queen]) *hcp += 2;
  37:     	if (haveIt[suit][Jack]) *hcp += 1;
  38:     
  39: 	    if (trump != NoTrump && suit != trump)
  40: 	    {
  41: 	    	cards = suitLength (haveIt[suit]);
  42: 	    	if (cards == 0)			/* void */
  43: 	    	{
  44: 	    		*dp += 3;
  45: 	    	}
  46: 	    	else if (cards == 1)	/* singleton */
  47: 	    	{
  48: 	    		if (highestCard (haveIt[suit]) != King) *dp += 2;
  49: 	    	}
  50: 	    	else if (cards == 2)	/* doubleton */
  51: 	    	{
  52: 	    		if (highestCard (haveIt[suit]) != Queen) *dp += 1;
  53: 	    	}
  54: 	    }
  55:     }
  56: } /* End of countPoints */
  57: 
  58: 
  59: static void prtPoints (FILE *out, Boolean haveIt[NSUITS][NCARDS])
  60: {
  61: 	int		hcp, dp;
  62: 	char	tmp[12];
  63: 	
  64: 	countPoints (haveIt, NoSuit, &hcp, &dp);
  65: 	sprintf (tmp, "(%d+%d=%d)", hcp, dp, hcp+dp);
  66: 	fprintf (out, " %-9s", tmp);
  67: } /* End of prtPoints */
  68: 
  69: 
  70: void display (FILE *out, Boolean haveIt[NPLAYERS][NSUITS][NCARDS],
  71: 			int prtPts)
  72: {
  73: 	static int Indent = 15;
  74: 	int		suit;
  75: 	int		suitLen;
  76: 	
  77: 	/* Print North's hand */
  78: 	fprintf (out, "\n");
  79: 	fprintf (out, "\n%*c%s", Indent, ' ', PlayerName[North]);
  80: 	if (prtPts) prtPoints (out, haveIt[North]);
  81: 	for (suit=NSUITS-1; suit>=0; suit--)
  82: 	{
  83: 		fprintf (out, "\n%*c", Indent, ' ');
  84: 		prtSuit (out, haveIt[North], suit);
  85: 	}
  86: 	
  87: 	/* Print West's and East's hands */
  88: 	fprintf (out, "\n%s", PlayerName[West]);
  89: 	if (prtPts) prtPoints (out, haveIt[West]);
  90: 	else fprintf (out, "          ");
  91: 	fprintf (out, "%*c%s", 2*Indent-10-strlen(PlayerName[West]), ' ',
  92: 						PlayerName[East]);
  93: 	if (prtPts) prtPoints (out, haveIt[East]);
  94: 	for (suit=NSUITS-1; suit>=0; suit--)
  95: 	{
  96: 		fprintf (out, "\n");
  97: 		suitLen = prtSuit (out, haveIt[West], suit);
  98: 		fprintf (out, "%*c", 2*(NCARDS+1-suitLen), ' ');
  99: 		prtSuit (out, haveIt[East], suit);
 100: 	}
 101: 	
 102: 	/* Print South's hand */
 103: 	fprintf (out, "\n%*c%s", Indent, ' ', PlayerName[South]);
 104: 	if (prtPts) prtPoints (out, haveIt[South]);
 105: 	for (suit=NSUITS-1; suit>=0; suit--)
 106: 	{
 107: 		fprintf (out, "\n%*c", Indent, ' ');
 108: 		prtSuit (out, haveIt[South], suit);
 109: 	}
 110: 	fprintf (out, "\n");
 111: } /* End of display */
 112: 

Bid.c - source file for bidding

   1: #include "Bridge.h"
   2: 
   3: typedef struct bid_t {
   4: 	int		bidder;
   5: 	int		level;		/* 0=pass -1=dbl -2=redbl */
   6: 	int		suit;
   7: 	struct bid_t *next;
   8: } bid_t;
   9: 
  10: static bid_t *FirstBid, *LastBid;
  11: 
  12: static void addBid (int player, int level, int suit)
  13: {
  14: 	bid_t	*bid;
  15: 	
  16: 	bid = (bid_t *) malloc (sizeof (bid_t));
  17: 	bid->bidder = player;
  18: 	bid->level = level;
  19: 	bid->suit = suit;
  20: 	bid->next = NULL;
  21: 	if (LastBid) LastBid->next = bid;
  22: 	else FirstBid = bid;
  23: 	LastBid = bid;
  24: } /* End of addBid */
  25: 
  26: 
  27: static int whoFirstBid (int suit, int team)
  28: {
  29: 	bid_t	*bid;
  30: 	
  31: 	bid = FirstBid;
  32: 	while (bid)
  33: 	{
  34: 		if (bid->suit == suit && Team[bid->bidder] == team)
  35: 		{
  36: 			return bid->bidder;
  37: 		}
  38: 		bid = bid->next;
  39: 	}
  40: 	
  41: 	fprintf (stderr, "\nERROR : Couldn't figure out who bid what!\n");
  42: 	return 0;
  43: } /* End of whoFirstBid */
  44: 
  45: 
  46: static void prtBidSummary (void)
  47: {
  48: 	bid_t	*bid;
  49: 	int		i;
  50: 	
  51: 	if (!FirstBid) return;
  52: 	
  53: 	printf ("\nBidding Summary\n");
  54: 	printf ("\n   ");
  55: 	for (i=0; i<NPLAYERS; i++)
  56: 	{
  57: 		printf ("%-14s", PlayerName[i]);
  58: 	}
  59: 	printf ("\n   ");
  60: 	
  61: 	/* Start at right bidder */
  62: 	for (i=FirstBid->bidder; i>South; i--) printf ("%-14s", "----");
  63: 	
  64: 	bid = FirstBid;
  65: 	while (bid)
  66: 	{
  67: 		if (bid->level == 0) printf ("%-14s", "Pass");
  68: 		else if (bid->level == -1) printf ("%-14s", "Double");
  69: 		else if (bid->level == -2) printf ("%-14s", "Redouble");
  70: 		else printf ("%d %-12s", bid->level, (bid->level == 1 ?
  71: 					SuitName[bid->suit] : SuitNames[bid->suit]));
  72: 		if (bid->bidder == East && bid->next != NULL) printf ("\n   ");
  73: 		bid = bid->next;
  74: 	}
  75: 	printf ("\n");
  76: } /* End of prtBidSummary */
  77: 
  78: 
  79: int getBid (Boolean haveIt[NPLAYERS][NSUITS][NCARDS],
  80: 			int dealer, int *level, int *trump, int *doubled, int *bidder)
  81: {
  82: 	char	ans[80];
  83: 	int		attemptlevel;
  84: 	int		attemptsuit;
  85: 	char	ch;
  86: 	int		dbl;
  87: 	int		lvl;
  88: 	int		ok;
  89: 	int		passes;
  90: 	int		player;
  91: 	int		suit;
  92: 	int		whobid;
  93: 	
  94: 	passes = -1;	/* Need to have 3 in a row to stop; 4 at beginning */
  95: 	player = dealer;	/* Dealer bids first */
  96: 	lvl = 0;
  97: 	suit = NoSuit;
  98: 	FirstBid = NULL;
  99: 	LastBid = NULL;
 100: 	
 101: 	printf ("\n");
 102: 	while (1)
 103: 	{
 104: 		printf ("Enter bid for %-5s -->", PlayerName[player]);
 105: 		gets (ans);
 106: 		if (ans[0] == '\0')
 107: 		{
 108: 			display (stdout, haveIt, True);
 109: 			printf ("\n");
 110: 			continue;
 111: 		}
 112: 		ch = toupper (ans[0]);
 113: 		ok = 1;
 114: 		if (ch == 'P')			/* Pass */
 115: 		{
 116: 			passes++;
 117: 			addBid (player, 0, 0);
 118: 			if (passes == 3)
 119: 			{
 120: 				if (lvl == 0) return 0;		/* All 4 passed */
 121: 				*level = lvl;
 122: 				*trump = suit;
 123: 				*doubled = dbl;
 124: 				*bidder = whoFirstBid (suit, Team[whobid]);
 125: 				prtBidSummary ();
 126: 				return 1;					/* End of bidding */
 127: 			}
 128: 		}
 129: 		else if (ch == 'D')		/* Double */
 130: 		{
 131: 			if (lvl == 0 || dbl != NoDouble || Team[player] == Team[whobid])
 132: 			{
 133: 				printf ("%s cannot double now\n", PlayerName[player]);
 134: 				ok = 0;
 135: 			}
 136: 			else
 137: 			{
 138: 				dbl = Double;
 139: 				addBid (player, -1, 0);
 140: 				passes = 0;
 141: 			}
 142: 		}
 143: 		else if (ch == 'R')		/* Re-double */
 144: 		{
 145: 			if (lvl == 0 || dbl != Double || Team[player] != Team[whobid])
 146: 			{
 147: 				printf ("%s cannot redouble now\n", PlayerName[player]);
 148: 				ok = 0;
 149: 			}
 150: 			else
 151: 			{
 152: 				dbl = ReDouble;
 153: 				addBid (player, -2, 0);
 154: 				passes = 0;
 155: 			}
 156: 		}
 157: 		else if (ch >= '1' && ch <= '7')
 158: 		{
 159: 			attemptlevel = ch - '0';
 160: 			ch = toupper(ans[1]);
 161: 			for (attemptsuit=0; attemptsuit<NSUITSNT; attemptsuit++)
 162: 			{
 163: 				if (ch == SuitChar[attemptsuit]) break;
 164: 			}
 165: 			if (attemptsuit == NSUITSNT)
 166: 			{
 167: 				printf ("Valid suits are C, D, H, S and N\n");
 168: 				ok = 0;
 169: 			}
 170: 			else if (attemptlevel < lvl || (attemptlevel == lvl &&
 171: 										attemptsuit <= suit))
 172: 			{
 173: 				printf ("%s must bid above %d%c\n",
 174: 						PlayerName[player], lvl, SuitChar[suit]);
 175: 				ok = 0;
 176: 			}
 177: 			else	/* Bid must be ok */
 178: 			{
 179: 				lvl = attemptlevel;
 180: 				suit = attemptsuit;
 181: 				dbl = NoDouble;
 182: 				whobid = player;
 183: 				passes = 0;
 184: 				addBid (player, lvl, suit);
 185: 			}
 186: 		}
 187: 		else
 188: 		{
 189: 			printf ("Invalid bid.  Choices are:\n");
 190: 			printf ("    Pass         or p\n");
 191: 			printf ("    Double       or d\n");
 192: 			printf ("    Redouble     or r\n");
 193: 			printf ("    ns, where n = 1 to 7\n");
 194: 			printf ("        and s = c, d, h, s, or n\n");
 195: 			printf ("    blank to redisplay hands\n");
 196: 			ok = 0;
 197: 		}
 198: 		
 199: 		if (ok) player = LeftOf[player];
 200: 	}
 201: } /* End of getBid */
 202: 

Play.c - source file for playing

   1: #include <string.h>
   2: 
   3: #include "Bridge.h"
   4: 
   5: static int whowon[NCARDS];
   6: static int whichsuit[NCARDS][NPLAYERS];
   7: static int whichcard[NCARDS][NPLAYERS];
   8: 
   9: 
  10: int playHand (int level, int trump, int declarer,
  11: 			Boolean haveIt[NPLAYERS][NSUITS][NCARDS],int *made)
  12: {
  13: 	char	ans[80];
  14: 	int		boss;			/* Which card is winning so far */
  15: 	char	ch;
  16: 	int		leads;			/* Who leads next (changes rapidly) */
  17: 	int		number;			/* Currently played card */
  18: 	int		player;			/* 0 .. 3 */
  19: 	int		randPlay;		/* Want totally random play? */
  20: 	int		suit;			/* Currently played suit */
  21: 	int		suitlead;		/* Which suit was lead? */
  22: 	int		trick;			/* 0 .. 12 */
  23: 	int		trumped;		/* Has anyone trumped yet? */
  24: 	int		who;			/* Whose turn is it? */
  25: 	
  26: 	*made = 0;
  27: 	leads = LeftOf[declarer];
  28: 	randPlay = 0;
  29: 	
  30: 	for (trick=0; trick<NCARDS; trick++)
  31: 	{
  32: 		if (randPlay == 0) printf ("\n");
  33: 		who = leads;
  34: 		for (player=0; player<NPLAYERS; player++)
  35: 		{
  36: 			err:	/* Comes here to ask for bid again */
  37: 			
  38: 			if (randPlay)
  39: 			{
  40: 				/* Might have to follow suit */
  41: 				if (player > 0 && suitLength (haveIt[who][suitlead]) > 0)
  42: 				{
  43: 					suit = suitlead;
  44: 					while (1)
  45: 					{
  46: 						number = random (0, NCARDS);
  47: 						if (haveIt[who][suit][number]) break;
  48: 					}
  49: 				}
  50: 				else	/* Pick any card, any suit */
  51: 				{
  52: 					while (1)
  53: 					{
  54: 						suit = random (0, NSUITS);
  55: 						number = random (0, NCARDS);
  56: 						if (haveIt[who][suit][number]) break;
  57: 					}
  58: 				}
  59: 			}
  60: 			/* If just one card in that suit, don't bother asking */
  61: 			else if (player > 0 && suitLength (haveIt[who][suitlead]) == 1)
  62: 			{
  63: 				number = highestCard (haveIt[who][suitlead]);
  64: 				suit = suitlead;
  65: 				printf ("Select card for %-5s -->%c%c\n",
  66: 						PlayerName[who], CardChar[number], SuitChar[suit]);
  67: 			}
  68: 			else if (trick == NCARDS-1)		/* Last trick? */
  69: 			{
  70: 				for (suit=0; suit<NSUITS; suit++)
  71: 				{
  72: 					number = highestCard (haveIt[who][suit]);
  73: 					if (number != NoCard) break;	/* Last card */
  74: 				}
  75: 				printf ("Select card for %-5s -->%c%c\n",
  76: 						PlayerName[who], CardChar[number], SuitChar[suit]);
  77: 			}
  78: 			else	/* Ask for a card */
  79: 			{
  80: 				printf ("Select card for %-5s -->", PlayerName[who]);
  81: 				gets (ans);
  82: 				if (strcmp (ans, "random") == 0)
  83: 				{
  84: 					randPlay = 1;
  85: 					goto err;
  86: 				}
  87: 				if (ans[0] == '\0')
  88: 				{
  89: 					display (stdout, haveIt, False);
  90: 					printf ("\nContract: %d %s, by %s\n\n", level,
  91: 							(level == 1 ? SuitName[trump] : SuitNames[trump]),
  92: 							PlayerName[declarer]);
  93: 					goto err;
  94: 				}
  95: 				
  96: 				/* Extract card suit and number */
  97: 				ch = toupper (ans[0]);
  98: 				for (number=0; number<NCARDS; number++)
  99: 				{
 100: 					if (ch == CardChar[number]) break;
 101: 				}
 102: 				ch = toupper (ans[1]);
 103: 				if (player > 0 && ch == '\0') suit = suitlead;
 104: 				else
 105: 				{
 106: 					for (suit=0; suit<NSUITS; suit++)
 107: 					{
 108: 						if (ch == SuitChar[suit]) break;
 109: 					}
 110: 				}
 111: 				if (number == NCARDS || suit == NSUITS)
 112: 				{
 113: 					fprintf (stderr, "\nInvalid card: %s", ans);
 114: 					fprintf (stderr, "\n  Example: 7c for the 7 of clubs");
 115: 					fprintf (stderr, "\n  Suit is optional after first card");
 116: 					fprintf (stderr, "\n  Type 'random' for totally random play");
 117: 					fprintf (stderr, "\n  Press return to display the hand\n\n");
 118: 					goto err;
 119: 				}
 120: 				
 121: 				/* Make sure they have the requested card */
 122: 				if (!haveIt[who][suit][number])
 123: 				{
 124: 					fprintf (stderr, "\nSorry, %s does not have the %s of %s\n\n",
 125: 							PlayerName[who], CardName[number], SuitNames[suit]);
 126: 					goto err;
 127: 				}
 128: 				
 129: 				/* Make sure they followed suit, if possible */
 130: 				if (player > 0 && suit != suitlead &&
 131: 						suitLength (haveIt[who][suitlead]) != 0)
 132: 				{
 133: 					fprintf (stderr, "\nSorry, %s must play a %s\n\n",
 134: 							PlayerName[who], SuitName[suitlead]);
 135: 					goto err;
 136: 				}
 137: 			}
 138: 			
 139: 			/* See who won the trick */
 140: 			if (player == 0)
 141: 			{
 142: 				boss = number;
 143: 				trumped = False;
 144: 				leads = who;
 145: 				suitlead = suit;
 146: 			}
 147: 			else if (suit != suitlead && suit == trump)	/* trumped! */
 148: 			{
 149: 				if (!trumped || number > boss)
 150: 				{
 151: 					boss = number;
 152: 					trumped = True;
 153: 					leads = who;
 154: 				}
 155: 			}
 156: 			else if (!trumped && number > boss)	/* followed suit */
 157: 			{
 158: 				boss = number;
 159: 				leads = who;
 160: 			}
 161: 			/* else couldn't have won because someone else trumped it */
 162: 			
 163: 			/* Take it away from their hand */
 164: 			haveIt[who][suit][number] = False;
 165: 			whichcard[trick][player] = number;
 166: 			whichsuit[trick][player] = suit;
 167: 			
 168: 			who = LeftOf[who];
 169: 		}
 170: 		
 171: 		/* See if declarer won the trick */
 172: 		if (Team[leads] == Team[declarer]) (*made)++;	/* Yes */
 173: 		whowon[trick] = leads;
 174: 
 175: 		if (randPlay == 0)
 176: 		{
 177: 			printf ("\n%s wins with the %s", PlayerName[leads], CardName[boss]);
 178: 			if (trumped)
 179: 			{
 180: 				printf (" of %s", SuitNames[trump]);
 181: 			}
 182: 			printf ("  [%s:%d  %s:%d]\n", TeamAbbrev[Team[declarer]], *made,
 183: 					TeamAbbrev[Other[Team[declarer]]], trick+1-*made);
 184: 		}
 185: 	}
 186: 	
 187: 	printf ("\nPlaying Summary (%s made %d tricks):\n",
 188: 					TeamAbbrev[Team[declarer]], *made);
 189: 	leads = LeftOf[declarer];
 190: 	for (trick=0; trick<NCARDS; trick++)
 191: 	{
 192: 		printf ("\n%4d.", trick+1);
 193: 		for (who=0; who<NSUITS; who++)
 194: 		{
 195: 			printf ("  %-5s: %c%c", PlayerName[leads],
 196: 					CardChar[whichcard[trick][who]],
 197: 					SuitChar[whichsuit[trick][who]]);
 198: 			if (whowon[trick] == leads)
 199: 			{
 200: 				printf ("*");	/* Won the trick */
 201: 			}
 202: 			else printf (" ");
 203: 			leads = LeftOf[leads];
 204: 		}
 205: 		leads = whowon[trick];
 206: 	}
 207: 	printf ("\n");
 208: 	return 1;
 209: } /* End of playHand */
 210: 

Score.c - source file for keeping score

   1: #include <string.h>
   2: #include "Bridge.h"
   3: 
   4: score_t *FirstScore, *LastScore;
   5: 
   6: 
   7: void scoreItem (int team, int points, char *msg)
   8: {
   9: 	score_t		*temp;
  10: 	
  11: 	/* printf ("%s %4d for %s.\n", TeamAbbrev[team], points, msg); */
  12: 	
  13: 	temp = (score_t *) malloc (sizeof (score_t));
  14: 	if (!temp) { fprintf (stderr, "\nNo memory\n"); return; }
  15: 	temp->hand = Hand;
  16: 	temp->team = team;
  17: 	temp->points = points;
  18: 	temp->msg = (char *) malloc (sizeof(char)*(strlen (msg)+1));
  19: 	if (!temp->msg) { fprintf (stderr, "\nNo memory\n"); return; }
  20: 	strcpy (temp->msg, msg);
  21: 	temp->next = NULL;
  22: 	
  23: 	if (LastScore) LastScore->next = temp;
  24: 	else FirstScore = temp;
  25: 	LastScore = temp;
  26: } /* End of scoreItem */
  27: 
  28: 
  29: int scoreHand (int level, int trump, int vulnerable, int doubled,
  30: 			int tricks, int team, int *above, int *below, int *oppAbove)
  31: {
  32: 	int		each, extra;	/* For counting points */
  33: 	int		overTricks;		/* if > 0 */
  34: 	char	temp[100];
  35: 	
  36: 	overTricks = tricks - level - BOOK;
  37: 	if (overTricks >= 0)
  38: 	{
  39: 		*oppAbove = 0;
  40: 		switch (trump)
  41: 		{
  42: 			case Clubs		: each = 20;	extra = 0;	break;
  43: 			case Diamonds	: each = 20;	extra = 0;	break;
  44: 			case Hearts		: each = 30;	extra = 0;	break;
  45: 			case Spades		: each = 30;	extra = 0;	break;
  46: 			case NoTrump	: each = 30;	extra = 10;	break;
  47: 			default			: return 0;
  48: 		}
  49: 		
  50: 		switch (doubled)
  51: 		{
  52: 			case NoDouble :
  53: 				*above = each * overTricks;
  54: 				*below = extra + each * level;
  55: 				break;
  56: 				
  57: 			case Double :
  58: 				*above = (vulnerable ? 200 : 100) * overTricks + 50;
  59: 				*below = 2 * (extra + each * level);
  60: 				break;
  61: 				
  62: 			case ReDouble :
  63: 				*above = (vulnerable ? 400 : 200) * overTricks + 50;
  64: 				*below = 4 * (extra + each * level);
  65: 				break;
  66: 			
  67: 			default : return 0;	
  68: 		}
  69: 		
  70: 		if (overTricks > 0) 
  71: 			sprintf (temp, "bidding %d %s, making %d", level,
  72: 					(level == 1 ? SuitName[trump] : SuitNames[trump]),
  73: 					level+overTricks);
  74: 		else sprintf (temp, "making %d %s", level,
  75: 					(level == 1 ? SuitName[trump] : SuitNames[trump]));
  76: 		if (doubled != NoDouble)
  77: 		{
  78: 			if (vulnerable) strcat (temp, ", Vulnerable");
  79: 			if (doubled == Double) strcat (temp, ", Doubled");
  80: 			else /* ReDouble */ strcat (temp, ", Redoubled");
  81: 		}
  82: 		scoreItem (team, *above+*below, temp);
  83: 		
  84: 		/* Bonus for making small slam or grand slam */
  85: 		if (level == 6)
  86: 		{
  87: 			if (vulnerable)
  88: 			{
  89: 				*above += 750;
  90: 				scoreItem (team, 750, "making Small Slam, Vulnerable");
  91: 			}
  92: 			else
  93: 			{
  94: 				*above += 500;
  95: 				scoreItem (team, 500, "making Small Slam");
  96: 			}
  97: 		}
  98: 		if (level == 7)
  99: 		{
 100: 			if (vulnerable)
 101: 			{
 102: 				*above += 1500;
 103: 				scoreItem (team, 1500, "making Grand Slam, Vulnerable");
 104: 			}
 105: 			else
 106: 			{
 107: 				*above += 1000;
 108: 				scoreItem (team, 1000, "making Grand Slam");
 109: 			}
 110: 		}
 111: 	}
 112: 	else /* Didn't make the bid */
 113: 	{
 114: 		*above = 0;
 115: 		*below = 0;
 116: 		switch (doubled)
 117: 		{
 118: 			case NoDouble :
 119: 				*oppAbove = (vulnerable ? -100 : -50) * overTricks;
 120: 				break;
 121: 			
 122: 			case Double :
 123: 				*oppAbove = (vulnerable ? -300 : -200) * overTricks - 100;
 124: 				break;
 125: 			
 126: 			case ReDouble :
 127: 				*oppAbove = (vulnerable ? -600 : -400) * overTricks - 200;
 128: 				break;
 129: 			
 130: 			default : return 0;	
 131: 		}
 132: 		
 133: 		sprintf (temp, "setting %d %s by %d trick%s", level,
 134: 					(level == 1 ? SuitName[trump] : SuitNames[trump]),
 135: 					 -overTricks, (overTricks == -1 ? "" : "s"));
 136: 		if (vulnerable) strcat (temp, ", Vulnerable");
 137: 		if (doubled == Double) strcat (temp, ", Doubled");
 138: 		else if (doubled == ReDouble) strcat (temp, ", Redoubled");
 139: 		scoreItem (Other[team], *oppAbove, temp);
 140: 	}
 141: 	
 142: 	return 1;
 143: } /* End of scoreHand */
 144: 
 145: 
 146: /* Returns NoPlayer if none, else which one got bonus */
 147: int scoreBonus (Boolean haveIt[NPLAYERS][NSUITS][NCARDS],
 148: 				int *pts, int trump)
 149: {
 150: 	int		count, i, j;
 151: 	
 152: 	for (i=0; i<NPLAYERS; i++)
 153: 	{
 154: 		count = 0;
 155: 		if (trump == NoTrump)	 /* Check for all 4 aces */
 156: 		{
 157: 			for (j=0; j<NSUITS; j++)
 158: 			{
 159: 				if (haveIt[i][j][Ace]) count++;
 160: 			}
 161: 			if (count == 4)
 162: 			{
 163: 				*pts = 150;
 164: 				scoreItem (Team[i], 150, "all 4 Aces in No Trump bid");
 165: 				return i;
 166: 			}
 167: 			if (count > 0) break;	/* Don't bother checking other guys */
 168: 		}
 169: 		else /* must be a suit -- check for A-K-Q-J-T */
 170: 		{
 171: 			for (j=Ten; j<=Ace; j++)
 172: 			{
 173: 				if (haveIt[i][trump][j]) count++;
 174: 			}
 175: 			if (count == 4)
 176: 			{
 177: 				*pts = 100;
 178: 				scoreItem (Team[i], 100, "4 of 5 honors in Trump");
 179: 				return i;
 180: 			}
 181: 			if (count == 5)
 182: 			{
 183: 				*pts = 150;
 184: 				scoreItem (Team[i], 150, "all 5 honors in Trump");
 185: 				return i;
 186: 			}
 187: 			if (count > 1) break;	/* Don't bother checking other guys */
 188: 		}
 189: 	}
 190: 	
 191: 	return NoPlayer;
 192: } /* End of scoreBonus */
 193: 
Email: steve@oharasteve.com