/********************************************************** * PROGRAM: Spades * * AUTHOR: Gregory M. Stelmack * * COMPILER: Lattice C V5.04 * * Copyright (C) 1988 Lattice, Inc. * * VESRION DATES: * * Version 1.0 -- February 5, 1990 * * Version 1.1 -- April 28, 1990 * * Images used for cards -- file "Spades.images" * * must be in current directory to run. * * Title graphics added. New routine for * * choosing dealer. * * Tab stops set to 2,4,6,8,... for this listing. * **********************************************************/ /* Include files */ #include #include #include #include #include #include #include #include #include #include /* Structures needed for libraries */ struct IntuitionBase *IntuitionBase; struct GfxBase *GfxBase; struct Library *DiskfontBase; /* Intuition Structures */ struct Screen *CustScr; struct Window *Wdw; struct Viewport *WVP; struct IntuiMessage *Message; /************** Program Constants **************/ #define RP Wdw->RPort /* Raster Port for Graphics Routines */ #define PENS 8 /* Number of Pens */ #define DEPTH 3 /* Number of BitPlanes */ #define MLEFT 1 /* Left Mouse Button Pressed */ #define MRIGHT 2 /* Right Mouse Button Pressed */ #define DIAMONDS 0 /* Suit Definitions */ #define CLUBS 1 #define HEARTS 2 #define SPADES 3 #define WHITE 0xFFF /* Palette Data */ #define RED 0xF00 #define GREEN 0x0F0 #define BLUE 0x00F #define CYAN 0x0FF #define PURPLE 0xF0F #define YELLOW 0xFF0 #define BLACK 0x000 /************** Color Map Data *****************/ static USHORT colormap [PENS] = { BLUE, /* Pen 0 */ BLACK, /* Pen 1 */ RED, /* Pen 2 */ GREEN, /* Pen 3 */ WHITE, /* Pen 4 */ YELLOW, /* Pen 5 */ PURPLE, /* Pen 6 */ CYAN /* Pen 7 */ }; #define BLUP 0 #define BLKP 1 #define REDP 2 #define GRNP 3 #define WHTP 4 #define YELP 5 #define PURP 6 #define CYNP 7 /************** Text Structure *****************/ struct TextAttr StdFont = { "topaz.font", TOPAZ_EIGHTY, FS_NORMAL, FPF_ROMFONT, }; /*********** NewScreen Structure **********/ struct NewScreen NewCustScr = { 0,0, /* Left Edge, Top Edge */ 320,200,DEPTH, /* Width, Height, Depth */ WHTP,BLUP, /* Detail Pen, Block Pen */ NULL, /* View Mode */ CUSTOMSCREEN, /* Screen Type */ &StdFont, /* Pointer to Font */ NULL, /* Pointer to Title Text */ NULL, /* Pointer to Screen Gadgets */ NULL, /* Pointer to CustomBitMap */ }; /*********** NewWindow Structure **********/ struct NewWindow NewWdw = { 0,0, /* Left Edge, Top Edge */ 320,200, /* Width, Height */ BLKP,WHTP, /* Block Pen, Detail Pen */ MOUSEBUTTONS | CLOSEWINDOW, /* IDCMP Flags */ SMART_REFRESH | ACTIVATE | GIMMEZEROZERO | RMBTRAP | WINDOWCLOSE, NULL, /* Pointer to First Gadget */ NULL, /* Pointer to Check Mark image */ "Spades, by Greg Stelmack", /* Title */ NULL, /* Pointer to Screen structure */ NULL, /* Pointer to custom Bit Map */ 0,0, /* Minimum Width, Height */ 0,0, /* Maximum Width, Height */ CUSTOMSCREEN /* Type of Screen it resides on */ }; /************************* Image Data *************************/ struct Image CardImage = { 0, 0, /* LeftEdge, TopEdge */ 42, 42, 3, /* Width, Height, Depth */ NULL, /* Image Data */ 7, 0, /* PlanePick, PlaneOnOff */ NULL /* *NextImage */ }; #include "Spades.h" /*************************** Arrays ***************************/ /*************************************** * Deck: status of cards. * * 0 = Undealt or played. * * 1 thru 4 = Player who holds card. * ***************************************/ int Deck[52] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /*************************************** * Hand: cards in each player's hand. * * 0 = Played. * * 1 thru 52 = Card number. * ***************************************/ int Hand[4][13] = { {0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0} }; /******************************************** * Bid: number of tricks bid by each player. * ********************************************/ int Bid[4] = {0,0,0,0}; /******************************************** * Mode: aggressiveness of each player. * * The number in this array is added to * * the strength of the hand to determine * * the number of tricks to bid. Higher * * number equals more tricks. * ********************************************/ int Mode[4] = {0,0,0,0}; /******************************************** * SuitPoints: how many points are added to * * the strength of a hand depending on the * * number of cards in each suit in the * * hand. The first row is for non-spades, * * the second for spades. * ********************************************/ int SuitPoints[2][14] = { {6,3,1,0,0,0,-2,-4,-6,-8,-10,-12,-20,-50}, {-4,-2,-1,0,0,+1,+2,+5,+8,+10,+12,+20,+50} }; /******************************************** * HighCardLeft: the highest unplayed card * * in each suit. * ********************************************/ int HighCardLeft[4] = {0,0,0,0}; /******************************************** * Card: the card played in a trick by each * * player. * ********************************************/ int Card[4] = {0,0,0,0}; /******************************************** * Value: the point value of each card held * * in a hand. Used by computer to determine* * which card to play. * ********************************************/ int Value[13] = {0,0,0,0,0,0,0,0,0,0,0,0,0}; /******************************************** * SuitNumber: the number of cards in each * * suit held by a player. * ********************************************/ int SuitNumber[4] = {0,0,0,0}; /******************************************** * CardX & CardY: The X and Y positions for * * the played card for each player. * * MsgX & MsgY: The X and Y positions for * * single character messages for each * * player. * ********************************************/ int CardX[4] = {100,1,100,209}; int CardY[4] = {99,60,1,60}; int MsgX[4] = {116,45,116,195}; int MsgY[4] = {96,84,50,84}; /******************************************** * OutOfSuit: Whether or not a player is out * * of a suit. * ********************************************/ BOOL OutOfSuit[4][4] = { {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0} }; /******************** Other Global Variables ******************/ char *String = " "; /* Temporary String Storage */ int PlayerScore=0, CompScore=0, PlayerTricks=0, CompTricks=0; int HandLead=0, Button=0, TrickLead=0, PlayerBid=0, CompBid=0; int ShortSuit=0, LongSuit=0, HighCard=0, Winner=0; BOOL SpadePlayed=FALSE, AllDone=FALSE; char *CardData; SHORT Mx=0, My=0; /* Mouse Coordinates */ /******************** Function Declarations *******************/ void Spades(), SetUpScreen(), DealCards(), ShowHand(), DrawCard(); int CalcBid(),GetPlayerBid(), TakeTrick(), GetPlayerCard(); int GetCompCard(),FindDealer(); BOOL ValidCard(); void itoa(), PrintBids(), PrintScore(), PrintTricks(), GetBids(); void ReadMouse(), PlayHand(), InitVars(), CalcLead(), CalcFollow(); void FinishRoutine(), WrapUp(), SuggestCard(), CountCards(); void Title(); /********************* Program Begins Here ********************/ /********************************************************** * Function: main * * Purpose: Open everything, play the game, close * * everything. * **********************************************************/ main() { int fh; unsigned int count=0; unsigned int length=0; /* Open the Intuition and Graphics libraries. */ IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",LIBRARY_VERSION); if (IntuitionBase == NULL) { printf("Can't open Intuition Library"); WrapUp(); } GfxBase = (struct GfxBase *) OpenLibrary("graphics.library",LIBRARY_VERSION); if (GfxBase == NULL) { printf("Can't open Graphics Library"); WrapUp(); } /* Open the screen and window */ if ((NewWdw.Screen = CustScr = (struct Screen *)OpenScreen(&NewCustScr)) == NULL) { printf("Can't open new screen"); WrapUp(); } if (( Wdw = (struct Window *)OpenWindow(&NewWdw)) == NULL) { printf("Can't open new window"); WrapUp(); } /* Find the viewport and load color map */ WVP = (struct ViewPort *)ViewPortAddress(Wdw); LoadRGB4(WVP,&colormap,PENS); /* Seed random number generator with TIMER */ srand(time(NULL)); /* Load Graphic Images */ length=52*126*2*3; CardData = (char *)AllocMem(length,MEMF_CHIP); if (!CardData) { printf("Could not allocate image memory!"); WrapUp(); } fh = open("Spades.images",O_RDONLY,0); if (fh==-1) { printf("Can't open images file!"); WrapUp(); } count = read(fh,CardData,length); if (count==-1) { printf("Error reading images file!"); WrapUp(); } /* Start Game */ Spades(); /* Close Everything */ WrapUp(); } /********************************************************** * Function: WrapUp * * Parameters: none * * Return Values: none * * Purpose: close everything and exit * **********************************************************/ void WrapUp() { if (CardData) FreeMem((char*)CardData,52*126*2); if (Wdw) CloseWindow(Wdw); if (CustScr) CloseScreen(CustScr); if (GfxBase) CloseLibrary(GfxBase); if (IntuitionBase) CloseLibrary(IntuitionBase); exit(0); } /********************************************************** * Function: Spades * * Parameters: None * * Return Values: None * * Purpose: Play a game of spades. Loop until someone * * scores 500. * **********************************************************/ void Spades() { Title(); AllDone=FALSE; /* Loop until player no longer wants to play. */ while (!AllDone) { PlayerScore=CompScore=0; HandLead=FindDealer(); /* Loop until someone reaches 500 and there is no tie. */ while (((PlayerScore<500)&&(CompScore<500))||(PlayerScore==CompScore)) { SetUpScreen(); InitVars(); PrintScore(); DealCards(); GetBids(); PrintBids(); PlayHand(); } FinishRoutine(); } } /********************************************************** * Function: Title * * Parameters: none * * Return Values: none * * Purpose: draw title graphics. * **********************************************************/ void Title() { int i=0; SetRast(RP,BLUP); /* Clear screen */ SetAPen(RP,YELP); SetBPen(RP,BLUP); /* Draw card backs */ for (i=0; i<6 ; i++) { DrawImage(RP,&Image25,(i*50)+15,65); } /* Flip S */ Delay(5); DrawImage(RP,&Image24,15,65); Delay(5); DrawImage(RP,&Image23,15,65); Delay(5); DrawImage(RP,&Image22,15,65); Delay(5); DrawImage(RP,&Image21,15,65); Delay(5); DrawImage(RP,&Image17,15,65); Delay(5); DrawImage(RP,&Image18,15,65); Delay(5); DrawImage(RP,&Image19,15,65); Delay(5); DrawImage(RP,&Image20,15,65); /* Flip P */ Delay(5); DrawImage(RP,&Image24,65,65); Delay(5); DrawImage(RP,&Image23,65,65); Delay(5); DrawImage(RP,&Image22,65,65); Delay(5); DrawImage(RP,&Image21,65,65); Delay(5); DrawImage(RP,&Image13,65,65); Delay(5); DrawImage(RP,&Image14,65,65); Delay(5); DrawImage(RP,&Image15,65,65); Delay(5); DrawImage(RP,&Image16,65,65); /* Flip A */ Delay(5); DrawImage(RP,&Image24,115,65); Delay(5); DrawImage(RP,&Image23,115,65); Delay(5); DrawImage(RP,&Image22,115,65); Delay(5); DrawImage(RP,&Image21,115,65); Delay(5); DrawImage(RP,&Image9,115,65); Delay(5); DrawImage(RP,&Image10,115,65); Delay(5); DrawImage(RP,&Image11,115,65); Delay(5); DrawImage(RP,&Image12,115,65); /* Flip D */ Delay(5); DrawImage(RP,&Image24,165,65); Delay(5); DrawImage(RP,&Image23,165,65); Delay(5); DrawImage(RP,&Image22,165,65); Delay(5); DrawImage(RP,&Image21,165,65); Delay(5); DrawImage(RP,&Image5,165,65); Delay(5); DrawImage(RP,&Image6,165,65); Delay(5); DrawImage(RP,&Image7,165,65); Delay(5); DrawImage(RP,&Image8,165,65); /* Flip E */ Delay(5); DrawImage(RP,&Image24,215,65); Delay(5); DrawImage(RP,&Image23,215,65); Delay(5); DrawImage(RP,&Image22,215,65); Delay(5); DrawImage(RP,&Image21,215,65); Delay(5); DrawImage(RP,&Image1,215,65); Delay(5); DrawImage(RP,&Image2,215,65); Delay(5); DrawImage(RP,&Image3,215,65); Delay(5); DrawImage(RP,&Image4,215,65); /* Flip S */ Delay(5); DrawImage(RP,&Image24,265,65); Delay(5); DrawImage(RP,&Image23,265,65); Delay(5); DrawImage(RP,&Image22,265,65); Delay(5); DrawImage(RP,&Image21,265,65); Delay(5); DrawImage(RP,&Image17,265,65); Delay(5); DrawImage(RP,&Image18,265,65); Delay(5); DrawImage(RP,&Image19,265,65); Delay(5); DrawImage(RP,&Image20,265,65); /* Prompt for pause */ Move(RP,50,180); Text(RP,"Click any mouse button...",25); ReadMouse(); /* Pause for click */ } /********************************************************** * Function: FindDealer * * Parameters: none * * Return Values: the player determined to initially deal. * * Purpose: find out who deals first in a game. * **********************************************************/ int FindDealer() { int player=0, card=0, i; BOOL done=FALSE; SetRast(RP,BLUP); /* Clear Screen */ SetAPen(RP,YELP); SetBPen(RP,BLUP); for (i=0 ; i<52 ; i++) Deck[i]=0; /* Set deck to undealt */ Move(RP,70,70); /* Warn player of what's happening */ Text(RP,"Ace of Spades",13); Move(RP,98,78); Text(RP,"deals",5); while(!done) /* Loop until dealer found */ { while(Deck[card=rand()%52]) ; /* Find undealt card */ Deck[card]=1; /* Mark card as dealt */ DrawCard(CardX[player],CardY[player],card); /* Draw card */ Delay(10); /* Pause */ if (card==51) /* Ace of Spades */ { done=TRUE; Move(RP,MsgX[player],MsgY[player]); Text(RP,"*",1); } player=(++player)%4; /* Increment player */ } Move(RP,200,150); /* Wait for player */ Text(RP,"Click mouse",11); ReadMouse(); SetRast(RP,BLUP); return((++player)%4); /* Must return player 2 to left of */ /* dealer. Program will later */ /* decrement player to find lead */ /* who should be to left of dealer */ } /********************************************************** * Function: SetUpScreen * * Parameters: none * * Return Values: none * * Purpose: gets the screen ready for a new hand. * **********************************************************/ void SetUpScreen() { /* Clear the Screen */ SetRast(RP,BLUP); /* Draw the Score Box */ SetAPen(RP,YELP); SetBPen(RP,BLKP); Move(RP,224,6); Text(RP," YOU CMP ",11); Move(RP,224,14); Text(RP,"SCORE SCORE",11); Move(RP,224,22); Text(RP," ",11); Move(RP,224,30); Text(RP," BID BID ",11); Move(RP,224,38); Text(RP," ",11); Move(RP,224,46); Text(RP,"TRICK TRICK",11); Move(RP,224,54); Text(RP," ",11); SetAPen(RP,WHTP); Move(RP,224,7); Draw(RP,312,7); Move(RP,267,0); Draw(RP,267,55); } /********************************************************** * Function: InitVars * * Parameters: none * * Return Values: none * * Purpose: Initialize variables and arrays for a new hand.* **********************************************************/ void InitVars() { int i; /* Set Leader */ HandLead=(--HandLead+4)%4; TrickLead=HandLead; /* Reset HighCardLeft */ HighCardLeft[0]=12; HighCardLeft[1]=12; HighCardLeft[2]=12; HighCardLeft[3]=12; /* Reset OutOfSuit */ for (i=0 ; i<4 ; i++) { OutOfSuit[i][DIAMONDS]=FALSE; OutOfSuit[i][CLUBS] =FALSE; OutOfSuit[i][HEARTS] =FALSE; OutOfSuit[i][SPADES] =FALSE; } /* Determine Modes */ for (i=0 ; i<4 ; i++) { Mode[i]=0; if (i==HandLead) Mode[i]+=2; /* Leader should bid higher */ if (i==0||i==2) /* Human players -- check score */ { if ((PlayerScore>400)&&(CompScore<350)) Mode[i]-=1; if (PlayerScore<(CompScore-100)) Mode[i]+=1; if (PlayerScore<(CompScore-200)) Mode[i]+=1; if (PlayerScore>(CompScore+100)) Mode[i]-=1; } if (i==1||i==3) /* Computer players -- check score */ { if ((CompScore>400)&&(PlayerScore<350)) Mode[i]-=1; if (CompScore<(PlayerScore-100)) Mode[i]+=1; if (CompScore<(PlayerScore-200)) Mode[i]+=1; if (CompScore>(PlayerScore+100)) Mode[i]-=1; } } } /********************************************************** * Function: DealCards * * Parameters: none * * Return Values: none * * Purpose: Shuffle & deal the deck to the players. * **********************************************************/ void DealCards() { int i,j,player,cardnum[4]; for (i=0 ; i<4 ; i++) cardnum[i]=0; /* Reset cards for each player */ for (i=0 ; i<52 ; i++) Deck[i]=0; /* Set whole deck to undealt */ /* Shuffle and Deal Deck */ for (i=0 ; i<52 ; i++) { while(Deck[j=rand()%52]) ; /* Find undealt card */ Deck[j]=((i/13)+1); /* Store owning player */ } /* Transfer cards to player hands */ for (i=0 ; i<52 ; i++) { player=Deck[i]-1; /* Get owning player */ Hand[player][cardnum[player]++]=i+1; /* Store card, increment counter */ } } /********************************************************** * Function: ShowHand * * Parameters: none * * Return Values: none * * Purpose: To display the player's hand. * **********************************************************/ void ShowHand() { int i; /* Erase old hand */ SetAPen(RP,BLUP); SetOPen(RP,BLUP); RectFill(RP,21,145,183,186); /* Draw each card, overlaying part of the previous one */ for (i=0 ; i<13 ; i++) { if (Hand[0][i]) /* Only draw if card hasn't been played */ DrawCard(((i*10)+21),145,((Hand[0][i])-1)); } } /********************************************************** * Function: GetBids * * Parameters: none * * Return values: none * * Purpose: Get each player's bid. * **********************************************************/ void GetBids() { int i; for (i=0 ; i<4 ; i++) Bid[i]=0; /* Reset bids for each player */ /* Loop through each player */ i=HandLead; do { if (i) Bid[i]=CalcBid(i); /* Computer Player */ else Bid[i]=GetPlayerBid(); /* Human Player */ i=(++i)%4; } while (i!=HandLead); /* Calculate team contracts */ PlayerBid=Bid[0]+Bid[2]; CompBid=Bid[1]+Bid[3]; /* Pause for click */ ReadMouse(); /* Erase Bids */ SetBPen(RP,BLUP); for (i=0 ; i<4 ; i++) { Move(RP,MsgX[i],MsgY[i]); Text(RP," ",1); } } /********************************************************** * Function: GetPlayerBid * * Parameters: none * * Return Values: bid -- number of tricks bid * * Purpose: Get the human player's bid. Could use gadgets, * * but this is easier to program. * **********************************************************/ int GetPlayerBid() { int bid=1,length; BOOL havebid=FALSE; ShowHand(); /* Draw input box */ SetAPen(RP,YELP); SetBPen(RP,BLKP); Move(RP,258,142); Text(RP,"BID",3); Move(RP,250,150); Text(RP," + ",5); Move(RP,250,158); Text(RP," OK",5); Move(RP,250,166); Text(RP," - ",5); /* Loop until OK is clicked */ while(!havebid) { /* Draw Current Bid */ SetAPen(RP,GRNP); SetBPen(RP,BLKP); Move(RP,250,158); Text(RP," ",2); itoa(bid,String); length=strlen(String); Move(RP,(258-(4*length)),158); Text(RP,String,length); /* Wait for Mouse input */ ReadMouse(); if (Button==MLEFT) /* Left Button Pressed */ { if ((Mx>265)&&(Mx<274)&&(My>143)&&(My<152)) bid++; /* plus sign */ if ((Mx>273)&&(Mx<290)&&(My>151)&&(My<160)) havebid=TRUE; /* OK */ if ((Mx>265)&&(Mx<274)&&(My>159)&&(My<168)) bid--; /* minus sign */ } if (Button==MRIGHT) /* Right Button Pressed */ { bid=CalcBid(0); /* Suggest a Bid */ } /* Make sure bid is valid */ if (bid<1) bid=1; if (bid>12) bid=12; } /* Erase Input Box */ SetAPen(RP,BLUP); SetOPen(RP,BLUP); RectFill(RP,250,135,291,168); /* Display the bid */ SetAPen(RP,YELP); SetBPen(RP,BLUP); itoa(bid,String); Move(RP,MsgX[0],MsgY[0]); Text(RP,String,strlen(String)); /* Send the bid back */ return(bid); } /********************************************************** * Function: CalcBid * * Parameters: player -- number of player to calculate for * * Return Values: bid -- number of tricks * * Purpose: To calculate the number of tricks bid by a * * player. * **********************************************************/ int CalcBid(player) int player; { int i,j,numsuit,points,suit,bid; points=0; /* Add up points for the non-spades suits */ for (i=DIAMONDS ; i13) bid=13-Bid[i]; /* Display Bid */ itoa(bid,String); SetAPen(RP,YELP); SetBPen(RP,BLUP); Move(RP,MsgX[player],MsgY[player]); Text(RP,String,strlen(String)); /* Send bid back */ return(bid); } /********************************************************** * Function: PlayHand * * Parameters: none * * Return Values: none * * Purpose: Play out a hand until all 13 tricks are taken. * **********************************************************/ void PlayHand() { int i; /* Initialize */ PlayerTricks=CompTricks=0; SpadePlayed=FALSE; PrintTricks(); /* Loop through all 13 tricks */ for (i=0 ; i<13 ; i++) { TrickLead=TakeTrick(); /* Play a trick */ if ((TrickLead==0)||(TrickLead==2)) /* Who won? */ PlayerTricks++; else CompTricks++; PrintTricks(); /* Display new trick total */ /* Indicate who won with an '*' */ SetAPen(RP,YELP); SetBPen(RP,BLUP); Move(RP,MsgX[TrickLead],MsgY[TrickLead]); Text(RP,"*",1); /* Pause for click */ ReadMouse(); /* Erase winner indicator */ Move(RP,MsgX[TrickLead],MsgY[TrickLead]); Text(RP," ",1); } /* Calculate new score */ if (PlayerTricks=PlayerBid) PlayerScore+=((10*PlayerBid)+(PlayerTricks-PlayerBid)); if (CompTricks>=CompBid) CompScore+=((10*CompBid)+(CompTricks-CompBid)); /* Pause for click */ ReadMouse(); } /********************************************************** * Function: TakeTrick * * Parameters: none * * Return Values: winner of trick * * Purpose: Each player plays a card, then determine trick * * winner. * **********************************************************/ int TakeTrick() { int i,j,leadsuit,suit,value; /* Clear previously played cards */ SetAPen(RP,BLUP); SetOPen(RP,BLUP); for (i=0 ; i<4 ; i++) RectFill(RP,CardX[i],CardY[i],(CardX[i]+41),(CardY[i]+41)); /* Get played cards */ i=TrickLead; do { if (!i) Card[i]=GetPlayerCard(); else Card[i]=GetCompCard(i); if (i==TrickLead) /* First card played wins so far */ { HighCard=Card[i]; leadsuit=Card[i]/13; Winner=i; } else { suit=Card[i]/13; /* See if this card is the new winner */ if (((suit==leadsuit)||(suit==SPADES))&&(Card[i]>HighCard)) { HighCard=Card[i]; Winner=i; } /* Was player out of the lead suit ? */ if (suit!=leadsuit) OutOfSuit[i][leadsuit]=TRUE; } i=(++i)%4; } while (i!=TrickLead); ShowHand(); /* Set highest card played in each suit */ for (i=0 ; i<4 ; i++) { for (j=0 ; j<4 ; j++) /* Need two loops to make sure we get all */ { value=Card[j]%13; suit=Card[j]/13; if (value==HighCardLeft[suit]) HighCardLeft[suit]=value-1; } } /* Send back trick winner */ return(Winner); } /********************************************************** * Function: GetPlayerCard * * Parameters: none * * Return Values: card picked to play * * Purpose: Allow player to pick card to play. * **********************************************************/ int GetPlayerCard() { int i,x,card; /* Let player know that it's his/her turn */ SetBPen(RP,BLUP); SetAPen(RP,YELP); Move(RP,200,150); Text(RP,"PLAY A CARD",11); /* Loop until we get a good card */ FOREVER { ReadMouse(); /* Wait for mouse click */ if (Button==MRIGHT) SuggestCard(); /* Player wants a suggestion */ if (Button==MLEFT) /* Did player pick a card ? */ { for (i=12 ; i>=0 ; i--) /* Check from right to left */ { x=(i*10)+21; /* Set left corner for card */ /* See if clicked inside this card and if card is still unplayed */ if ((My<187)&&(My>144)&&(Mx<(x+42))&&(Mx>=x)&&(Hand[0][i])) { if (ValidCard(i)) /* Was this a playable card ? */ { card=Hand[0][i]-1; Hand[0][i]=0; /* Mark card as played */ if ((card/13)==SPADES) SpadePlayed=TRUE; /* Spades have been broken */ /* Erase suggestion '*' */ SetAPen(RP,BLUP); SetOPen(RP,BLUP); RectFill(RP,21,136,170,144); DrawCard(CardX[0],CardY[0],card); /* Draw played card */ /* Erase prompt message */ SetBPen(RP,BLUP); Move(RP,200,150); Text(RP," ",11); /* Send back played card */ return(card); } else /* if chosen card was not valid, need a new card */ i=-1; } } } } } /********************************************************** * Function: ValidCard * * Parameters: card -- card in player's hand to check * * Return Values: was card valid or not? * * Purpose: To determine if the card chosen by the player * * was valid or not. * **********************************************************/ BOOL ValidCard(card) int card; { int i,suit,leadsuit; SuitNumber[DIAMONDS]=0; SuitNumber[CLUBS] =0; SuitNumber[HEARTS] =0; SuitNumber[SPADES] =0; /* Count number of cards player has in each suit */ for (i=0 ; i<13 ; i++) { if (Hand[0][i]) SuitNumber[(Hand[0][i]-1)/13]++; } suit=(Hand[0][card]-1)/13; /* Find suit of played card */ if (!TrickLead) /* Player is leading */ { /* If he didn't lead a spade, it was a good play */ if (suit!=SPADES) return(TRUE); /* If he only has spades, he has no choice */ if ((!SuitNumber[0])&&(!SuitNumber[1])&&(!SuitNumber[2])) return(TRUE); /* If spades have been played, he can lead anything */ if (SpadePlayed) return(TRUE); /* Must have lead a spade when it was illegal to */ return(FALSE); } /* Player doesn't lead */ leadsuit=Card[TrickLead]/13; /* Find suit that was lead */ /* If he played the suit that was lead, he is OK */ if (suit==leadsuit) return(TRUE); /* If he didn't have any, he's OK */ if (!SuitNumber[leadsuit]) return(TRUE); /* Must have had some but didn't play them */ return(FALSE); } /********************************************************** * Function: CountCards * * Parameters: none * * Return Values: none * * Purpose: Count cards in each suit for a player. * * Determine short and long suits. * **********************************************************/ void CountCards(player) int player; { int i,card,suit,maximum,minimum; /* Initialization */ SuitNumber[DIAMONDS]=0; SuitNumber[CLUBS] =0; SuitNumber[HEARTS] =0; SuitNumber[SPADES] =0; /* Loop through all cards in the player's hand */ for (i=0 ; i<13 ; i++) { if (Hand[player][i]) /* Make sure card hasn't been played */ { card=Hand[player][i]-1; suit=card/13; Value[i]=6-(card%13); /* Give lower cards a slight priority */ SuitNumber[suit]++; /* Count Number of Suit held */ } else Value[i]=-10000; /* Don't throw previously played cards */ } /* Find short and long suits */ minimum=14; maximum=0; ShortSuit=LongSuit=3; for (i=DIAMONDS ; i0)) { minimum=SuitNumber[i]; ShortSuit=i; } if (SuitNumber[i]>maximum) { maximum=SuitNumber[i]; LongSuit=i; } } } /********************************************************** * Function: SuggestCard * * Parameters: none * * Return Values: none * * Purpose: Suggest a card for player to play. * **********************************************************/ void SuggestCard() { int i,pick,maximum; CountCards(0); /* Go to appropriate point calculating routine */ if (!TrickLead) CalcLead(0); else CalcFollow(0); /* Find best card (the one with the most points) */ pick=0; maximum=Value[0]; for (i=1 ; i<13 ; i++) { if (Value[i]>maximum) { maximum=Value[i]; pick=i; } } /* Display an '*' over suggested card */ SetAPen(RP,YELP); SetBPen(RP,BLUP); Move(RP,((pick*10))+22,142); Text(RP,"*",1); } /********************************************************** * Function: GetCompCard * * Parameters: player -- player to play * * Return Values: card played * * Purpose: Determine which card a computer-controlled * * player will play. * **********************************************************/ int GetCompCard(player) int player; { int i,pick,card,maximum; CountCards(player); /* Go to appropriate point calculating routine */ if (player==TrickLead) CalcLead(player); else CalcFollow(player); /* Find best card (the one with the most points) */ pick=0; maximum=Value[0]; for (i=1 ; i<13 ; i++) { if (Value[i]>maximum) { maximum=Value[i]; pick=i; } } card=Hand[player][pick]-1; if ((card/13)==3) SpadePlayed=TRUE; /* Mark that spades have been broken */ Hand[player][pick]=0; /* Card has now been played */ DrawCard(CardX[player],CardY[player],card); /* Draw the played card */ return(card); /* Send the played card back */ } /********************************************************** * Function: CalcLead * * Parameters: player -- whose hand to calculate * * Return Values: none * * Purpose: To calculate the value of each card in a hand * * to determine which card should be played if * * the hand is leading. * **********************************************************/ void CalcLead(player) int player; { int i,card,suit,value; BOOL opponentsout=FALSE, partnerout=FALSE; /* Loop through all cards in hand */ for (i=0 ; i<13 ; i++) { if (Hand[player][i]) /* Make sure card hasn't been played */ { /* Find suit and face value */ card=Hand[player][i]-1; suit=card/13; value=card%13; if ((OutOfSuit[(player+1)%4][suit])||(OutOfSuit[(player+3)%4][suit])) opponentsout=TRUE; if (OutOfSuit[(player+2)%4][suit]) partnerout=TRUE; if (value==HighCardLeft[suit]) /* Card is highest left in a suit */ { if (suit==SPADES) /* Spades don't matter if someone is */ Value[i]+=50; /* out. */ else { if (opponentsout) /* If opponents are out, don't waste */ Value[i]-=50; /* high cards. */ else Value[i]+=50; } } /* If player holds spades, get rid of short suit */ if ((SuitNumber[SPADES])&&(suit==ShortSuit)) Value[i]+=250; /* If player doesn't hold spades, get rid of long suit */ if ((!SuitNumber[SPADES])&&(suit==LongSuit)) Value[i]+=250; /* If spades aren't broken, they can't be lead */ if ((suit==SPADES)&&(!SpadePlayed)) Value[i]-=5000; /* Lead suits your partner is out of */ if ((suit!=SPADES)&&(partnerout)&&(!opponentsout)) Value[i]+=300; } } } /********************************************************** * Function: CalcFollow * * Parameters: player -- whose hand to calculate * * Return Values: none * * Purpose: To calculate the value of each card in a hand * * to determine which card should be played if * * the hand is not leading. * **********************************************************/ void CalcFollow(player) int player; { int i,card,suit,value,leadsuit; BOOL alreadywon; leadsuit=Card[TrickLead]/13; /* Calculate the suit that was lead */ /* See if partner has already won the trick */ alreadywon=FALSE; /* See if win is guaranteed (player is last to play) */ if ((Winner==((player+2)%4))&&(TrickLead==((player+1)%4))) alreadywon=TRUE; /* See if win is probable (player is next to last to play) */ if ((Winner==TrickLead)&&(TrickLead==((player+2)%4))) { value=Card[TrickLead]%13; if ((value==HighCardLeft[leadsuit])&&(value>9)) alreadywon=TRUE; } /* Loop through all cards in hand */ for (i=0 ; i<13 ; i++) { if (Hand[player][i]) /* Make sure card hasn't been played */ { /* Find suit and face value of card */ card=Hand[player][i]-1; suit=card/13; value=card%13; if (suit==leadsuit) /* Card is of lead suit */ { Value[i]+=5000; /* If it is the highest one left in that suit, throw it */ if ((value==HighCardLeft[suit])&&(TrickLead!=((player+1)%4))&&(card>HighCard)) Value[i]+=70; /* See if card will beat those previously played */ if (card>HighCard) { if (!alreadywon) /* Team hasn't won yet */ { if (TrickLead==((player+1)%4)) /* Can definitely take trick */ Value[i]+=100; else Value[i]+=10; /* Maybe take trick */ } else Value[i]-=75; /* If the team has one, hold high cards */ } /* If team has already one the trick, throw low cards */ if ((cardHighCard)) { if (!alreadywon) Value[i]+=10; /* If team hasn't won, throw the spade */ else Value[i]-=1000; /* If team has won, hold high spades */ } if ((suit==SPADES)&&(cardUserPort)) == NULL) { Wait(1L<UserPort->mp_SigBit); continue; } /* Interpret Message */ class = Message->Class; code = Message->Code; Mx=((SHORT) Message->MouseX) - 4; /* Adjustments for */ My=((SHORT) Message->MouseY) - 12; /* GIMMEZEROZERO Window */ /* See if Window Close Box clicked */ if (class & CLOSEWINDOW) WrapUp(); /* Otherwise, make sure Message was caused by mouse */ if (class & MOUSEBUTTONS) { switch(code) { /* Left Button Released */ case SELECTUP: Button=MLEFT; gotmouse=TRUE; break; /* Right Button Released */ case MENUUP: Button=MRIGHT; gotmouse=TRUE; break; /* Other Input */ default: gotmouse=FALSE; } } ReplyMsg(Message); } } /********************************************************** * Function: DrawCard * * Parameters: x -- x coordinate of top left corner * * y -- y coordinate of top left corner * * card -- number of card to draw * * Return Values: none * * Purpose: Draw a card. * **********************************************************/ void DrawCard(x, y, card) int x, y, card; { CardImage.ImageData = (UWORD *)(CardData+card*126*6); DrawImage(RP, &CardImage, x, y); } /********************************************************** * Function: FinishRoutine * * Parameters: none * * Return Values: none * * Purpose: Display final score, ask to play again. * **********************************************************/ void FinishRoutine() { BOOL haveinput; SetRast(RP,BLUP); SetAPen(RP,WHTP); SetBPen(RP,BLUP); Move(RP,112,56); Text(RP,"FINAL SCORE:",12); Move(RP,80,72); Text(RP,"YOU:",4); Move(RP,184,72); Text(RP,"ME:",3); SetAPen(RP,YELP); itoa(PlayerScore,String); Move(RP,116,72); Text(RP,String,strlen(String)); itoa(CompScore,String); Move(RP,212,72); Text(RP,String,strlen(String)); Move(RP,112,96); Text(RP,"PLAY AGAIN ?",12); SetAPen(RP,BLKP); SetBPen(RP,WHTP); Move(RP,112,112); Text(RP,"YES",3); Move(RP,188,112); Text(RP,"NO",2); haveinput=FALSE; while (!haveinput) { ReadMouse(); if ((Mx>111)&&(Mx<136)&&(My>105)&&(My<114)) { haveinput=TRUE; AllDone=FALSE; } if ((Mx>187)&&(Mx<204)&&(My>105)&&(My<114)) { haveinput=TRUE; AllDone=TRUE; } } } /********************************************************** * Function: itoa * * Parameters: n -- number to convert * * s -- pointer to result string * * Return Values: none * * Purpose: Convert an integer to a string so it can be * * used by the Text function. Lattice does not * * have one. * **********************************************************/ void itoa(n,s) char *s; int n; { int i=0; BOOL sign=FALSE; if (n<0) { sign=TRUE; n=-n; } do { s[i++]=n%10+'0'; } while((n/=10)>0); if (sign) s[i++]='-'; s[i]='\0'; strrev(s); }