DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T b

⟦1068d8279⟧ TextFile

    Length: 14933 (0x3a55)
    Types: TextFile
    Names: »blackjack.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/General/Bj1/blackjack.c« 

TextFile

/*
 *  Blackjack
 *  Copyright (C) 1988 Scott R. Turner (srt@cs.ucla.edu).
 *
 * ----------------------------------------------------------------------
 *                 LICENSE AGREEMENT
 *
 * You may copy and distribute copies or portions of this program
 * as you receive it, in any medium, provided that you conspicuously and
 * appropriately publish on each copy a valid copyright notice "Copyright
 * (C) 1988 Scott R. Turner" (or with whatever year is appropriate) and keep 
 * intact the notices on all files that refer to this License Agreement.
 * You may not charge a fee for distribution or copying of this
 * program or any program which contains this program in whole or part.
 * ----------------------------------------------------------------------
 *  
 *  Author's Notes
 *  
 *  Much as I hate to write a Blackjack program, there don't seem to be any
 *  really good ones available.  Hence this program.
 *
 *  This version allows:
 *
 *  (1) Hit, Stand, Double Down, Splitting
 *  (2) Advice (Basic Strategy)
 *
 *  As distributed, this program plays a 2 deck game using Las Vegas 
 *  downtown rules (hit soft 17).  These parameters can be easily 
 *  modified.
 *
 *  You can hit (h), stand, (space), double down (d), or split (s).
 *
 *  There is currently no differential betting or count.
 *
 *  The program will beep and advise you of incorrect plays according
 *  to the basic blackjack strategy.
 *
 *  Program Notes
 *
 *  To change the dealer rules, see the play_dealer routine.
 *
 *  To change the # of decks (to a maximum of 4), change the value
 *  of numcards in main to the appropriate number.  To play more than
 *  4 decks you'll also have to change some declarations.
 *
 *  Cards are represented as integers from 1-52.  N mod 13 gives the
 *  rank of the card.  N mod 4 gives the suit.
 *
 *  Cards are shuffled by exchange.  The number of exchanges is set 
 *  in NUMEXCHANGE.  Currently 2000.
 *
 *  Note various timing "delay"s in the code; these can be modified to 
 *  suit your own machine.  LONGSLEEP and SHORTSLEEP for Unix-y.
 * 
 *  Correct_play encapsulates the "basic strategy" and determines whether
 *  the player's action was correct.
 */
#include <ctype.h>
#include <stdio.h>
#include <curses.h>

#define NUMEXCHANGE 2000 
#define MESSAGES 7
#define STATUS 8
#define DEALER 3
#define DEALERLINE 2
#define PLINE1 10
#define PLINE2 18
#define LONGSLEEP 20000
#define SHORTSLEEP 5000

int cards[209];  /* Maximum # of cards in 4 decks.  */
int numcards;	 /* Number of cards (decks * 52)    */
int top;  	 /* Top card in the deck.           */
int player[2][21];	 /* 21 is the maximum # of cards in a hand. */
int dealer[21];
int pnum[2],
    dnum;	 /* Number actually in the hand. */
int ptot[2], dtot;	 /* Totals (?) */
int bet[2];
int money;
int ddown[2];
int stand[2];
int split;	 /* Split flag. */
int quit;
char suitc[]={0,'C','D','H','S'};	/*  Suits */

/* Session Statistics */

int numhands, numbust, numbj, nummp;

/*
 *  init_hand initializes all the global variables
 *  pertinent to the beginning of a new hand.
 *
 */
 
void init_hand()
{
	pnum[0] = pnum[1] = dnum = 0;
	ptot[0] = ptot[1] = dtot = 0;
	bet[0] = bet[1] = 2;
	ddown[0] = ddown[1] = 0;
	stand[0] = stand[1] = 0;
	split = 0;
};

/*
 *  Shuffle initializes the deck and shuffles it up.
 *
 */

void shuffle()
{
    int i,j,tmp;
    
    for(i=1;i<=numcards;i++)
        cards[i] = i;
    top = 1;
	
    /*
     *  Exchange.
     *
     */
    for(i=0;i<=NUMEXCHANGE;i++) {
#ifdef TURBOC      
        j = random(numcards)+1;
#else
	j = (random()%numcards)+1;
#endif	
	tmp = cards[j];
	cards[j] = cards[1];
	cards[1] = tmp;
    };
    
};
			
/*
 *  Rank returns the rank of a card.
 *
 */
 
int rank(i)
    int i;
{	
    return((i % 13) + 1);
};

/*
 *  value returns the value of a hand closest
 *  to 21.
 *
 */
 
int value(h,s)
    int *h,s;
{
    int tot, aces, i, r;
    
    tot = aces = 0;
    
    for(i=0;i<s;i++) {
        r = rank(h[i]);
	if (r == 1) aces++;
	if (r > 10) r = 10;
	tot += r;
    };
    
    while (tot < 12 && aces) {
        aces--;
	tot += 10;
    };
    
    return(tot);
};

/*
 *  Bust is similar to value, except it returns 0/1 for bust.
 *
 */
 
int bust(h,s)
    int *h,s;
{
    int tot, i, r;
    
    tot = 0;
    
    for(i=0;i<s;i++) {
        r = rank(h[i]);
	if (r > 10) r = 10;
	tot += r;
    };

    if (tot > 21) return(1);
    else return(0);
    
};

/*
 *  My front end to getc.
 *
 */
 
char mgetc(allowed)
    char *allowed;
{
    char c;

    do {
      c = getch();
      if (islower(c)) c = toupper(c);
      if (c == 'Q') {
         clear();
         move(10,0);
	 printw("Session Statistics");
	 move(12,0);
	 printw("   Hands played: %d.",numhands-1);
	 move(13,0);
	 printw("   Hands misplayed: %d.", nummp);
	 move(14,0);
	 printw("   Hands busted: %d.",numbust);
	 move(15,0);
	 printw("   Blackjacks: %d.",numbj);
	 move(16,0);
	 printw("   Winnings: $%d.",money);
	 move(20,0);
	 refresh();
         nocrmode();
	 /**
	 quit = 1;
	 break;
	 **/
      	 exit(1);
      	};
    } while (!strchr(allowed,c));
    return(c);
    
};

/*
 *  determine_results figures out what happened with 
 *  the bets.
 *
 */
 
void determine_results()
{
    int i;
    
    for(i=0;i<=split;i++) {
	move(MESSAGES,0);
	clrtoeol();
        /*  First, if you bust, you lose.  */
        if (bust(player[i],pnum[i])) {
	    printw("Bust!  You lose $%d.",bet[i]);
	    money -= bet[i];
	} else if (bust(dealer,dnum)) {
	    printw("Dealer busts.  You win $%d.",bet[i]);
	    money += bet[i];
	} else if (value(dealer,dnum) == value(player[i],pnum[i])) {
            printw("Push.");	
	} else if (value(dealer,dnum) > value(player[i],pnum[i])) {
	    printw("Dealer has %d.  You lose $%d.",value(dealer,dnum),bet[i]);
	    money -= bet[i];
	} else {
	    printw("Dealer had %d.  You win $%d.",value(dealer,dnum),bet[i]);
	    money += bet[i];
	};
	move(STATUS,0);
	clrtoeol();
	printw("Stake $%d",money);
	refresh();
#ifdef TURBOC	
	delay(1500);
#else
	usleep(LONGSLEEP);
#endif
    };
};

/*
 *  display_card prints the card on the screen.
 *
 */
 
void display_card(hand,num,line)
    int *hand, num, line;
{
    int r,suit,start,tot;
    
    r = (hand[num-1] % 13) + 1;
    if (r<1 || r>13) {
    	move(MESSAGES,0);
	printw("Weird value: %d.\n",r);
	refresh();
	mgetc(" ");
    };
    suit = (hand[num-1] - 1 / 13)%4;
    start = 5 * (num - 1);
    move(line, start);
    printw("+----+");
    move(line + 1,start);
    printw("|    |");
    move(line + 2,start);
    printw("|    |");
    move(line + 3,start);
    printw("+----+");
    
    if (line == DEALERLINE && num == 1) {
      /* Special - hide this card. */
      move(line+1,start+1);
      printw("####");
      move(line+2,start+1);
      printw("####");
      return;
    };

    move(line + 1,start+1);
    switch(r) {
        case 1: printw("A"); break;
	case 10: printw("10"); break;
        case 11: printw("J"); break;
	case 12: printw("Q"); break;
	case 13: printw("K"); break;
	default: printw("%d",r); break;
    };
    
    printw("%c",suitc[suit+1]);
};

/*
 *  Deal deals a card to the indicated hand or player, 
 *  also displaying it on the screen at the appropriate
 *  spot.
 */
 
void deal(who)
    int who;
{
    if (who == DEALER) {
    	dealer[dnum++] = cards[top++];
	dtot = value(dealer,dnum);
	display_card(dealer,dnum,DEALERLINE);
    } else {
        player[who][pnum[who]++] = cards[top++];
	ptot[who] = value(player[who],pnum[who]);
	if (!who) {
	    display_card(player[who],pnum[who],PLINE1);
	    move(PLINE1+2,(5*pnum[who]+2));
	    printw("(%d)",ptot[who]);
        } else {
	    display_card(player[who],pnum[who],PLINE2);
	    move(PLINE2+2,(5*pnum[who]+2));
	    printw("(%d)",ptot[who]);
	};
    };
    refresh();
#ifdef TURBOC    
    delay(100);
#else
    usleep(SHORTSLEEP);
#endif
};

/* 
 *  play_dealer plays the dealers hand according to the
 *  standard rules.
 *
 *  Downtown (hit soft 17) rules.
 */
 
void play_dealer()
{   
    while (dtot < 17 || (dtot == 17 && soft(dealer,dnum))) {
        deal(DEALER);
    };
};

/*
 *  Reveal the dealer's card.
 *
 */
 
void reveal()
{
    int r,suit,start,line;
    
    r = (dealer[0] % 13) + 1;
    suit = (dealer[0] - 1 / 13)%4;
    start = 0;
    line = DEALERLINE;
    /* Special - unhide this card. */
    move(line+1,start+1);
    printw("    ");
    move(line+2,start+1);
    printw("    ");
    move(line + 1,start+1);
    switch(r) {
        case 1: printw("A"); break;
	case 10: printw("10"); break;
        case 11: printw("J"); break;
	case 12: printw("Q"); break;
	case 13: printw("K"); break;
	default: printw("%d",r); break;
    };
    
    printw("%c",suitc[suit+1]);
    refresh();
};

/*
 *  True if a hand is "soft".
 *
 */
 
int soft(h,s)
    int *h,s;
{
    int tot, aces, i, r;
    
    tot = aces = 0;
    
    for(i=0;i<s;i++) {
        r = rank(h[i]);
	if (r == 1) aces++;
	if (r > 10) r = 10;
	tot += r;
    };
    
    if (aces && tot < 12) return(1);
    return(0);
};

char correct_play(h,z)
    int *h,z;
{
    int s,t,u,r;
    
    s = soft(h,z);
    t = value(h,z);
    u = rank(dealer[1]);
    if (u > 10) u = 10;
    
    if (t < 9) return('H');
    
    /*
     *  Splitting.
     *
     */
    
    if (rank(h[0]) == rank(h[1]) && z == 2) {
        r = rank(h[0]);
        if (r == 1 || r == 8 || (r == 9 && u != 7 && u != 10 && u != 1) ||
            (r == 7 && u < 8) || (r == 6 && u < 7 && u > 2) ||
            (r == 2 && u > 3 && u < 8) ||
            (r == 3 && u > 3 && u < 8)) {
                return('S');
	};
    };
    
    /*
     *  Doubling
     *
     */

    /*  Soft  */    
    if (s && z == 2 &&
    	(((t == 18 || t == 17) && u > 2 && u < 7) ||
         ((t == 16 || t == 15) && u > 3 && u < 7) ||
         ((t == 14 || t == 13) && u > 4 && u < 7))) {
            	return('D');
    }
    /*  Hard */
    if (!s && z == 2 &&
        (t == 11 && u != 1) ||
        (t == 10 && u != 1 && u != 10) ||
        (t == 9 && u > 2 && u < 7)) {
                return('D');
    }
    
    /*
     * Hit or Stand.
     *
     */
    
    if (!s) {
        /*  Hard hand. */
	if (t > 16) {
	    return(' ');
	} else if (t == 12 && (u == 2 || u == 3)) {
	    return('H');
	} else if (u < 7 && u != 1) {
	    return(' ');
	} return('H');
    } else {
        /*  Soft hand. */
        if (t < 18) {
            return('H');
	} else if (t == 18 && (u > 8 || u == 1)) {
	    return('H');
	} else return(' ');
    };
};

    

main()
{
    /*
     *  Logic
     *
     *  (1) Shuffle if necessary.
     *  (2) Initialize players.
     *  (3) Deal two cards to each player.
     *      (a) blackjack check.
     *  (4) Enter play loop.
     *      For each hand:
     *      (a) ask player what to do.
     *      (b) do it, if legal.
     *      (c) check for bust.
     *  (5) Play dealer's hand.
     *  (6) Determine results.
     *  (7) Repeat
     *
     */
     
    int i;
    char c,correct;

#ifdef TURBOC    
    randomize();
#else
    srandom((int) time(0));
#endif
    quit = 0;
    numhands = 0;
    numbust = 0;
    numbj = 0;
    nummp = 0;

    /*
     *  Curses initialization.
     *
     */
    initscr();
    crmode();
    noecho();
    move(0,20);
    printw("*B*L*A*C*K*J*A*C*K*");
    top = 300;
    numcards = 104;  /* 2 deck game */

    while(!quit) {
        
       /* Shuffle check. */
       if (top >= (numcards * .60)) {
            move(MESSAGES,0);
	    clrtoeol();
	    printw("Shuffling...          ");
	    refresh();
#ifdef TURBOC	    
	    delay(250);
#else
	    usleep(SHORTSLEEP);
#endif
	    shuffle();
	};

        /* Initialize. */
	
        init_hand();
	
	/* Clear appropriate parts of the screen. */
	for(i=0;i<=4;i++) {
	    move(DEALERLINE+i,0);
	    clrtoeol();
	    move(PLINE1+i,0);
	    clrtoeol();
	    move(PLINE2+i,0);
	    clrtoeol();
	    move(STATUS,0);
	    clrtoeol();
	    move(STATUS+1,0);
	    clrtoeol();
	};
	
	/* Deal two cards to each. */

	deal(DEALER);	
	deal(DEALER);
	deal(0);
	deal(0);
	numhands++;
	
	/*  Blackjacks? */
	
	if (dtot == 21 && ptot[0] == 21) {
	    reveal();
	    move(MESSAGES,0);
	    clrtoeol();
	    printw("Double Blackjack!  Push.");
	    refresh();
#ifdef TURBOC	    
	    delay(1000);
#else
	    usleep(LONGSLEEP);
#endif
	    continue;
	} else if (dtot == 21) {
	    reveal();
	    move(MESSAGES,0);
	    clrtoeol();
	    printw("Dealer Blackjack!  You lose $%d.",bet[0]);
	    money -= bet[0];
	    move(STATUS,0);
	    clrtoeol();
	    printw("Stake $%d",money);
	    refresh();
#ifdef TURBOC	    
	    delay(1000);
#else
	    usleep(LONGSLEEP);
#endif
	    continue;
	} else if (ptot[0] == 21) {
	    reveal();
	    move(MESSAGES,0);
	    clrtoeol();
	    printw("Blackjack!  You win $%d.",(bet[0]*1.5));
	    money += bet[0]*1.5;
	    move(STATUS,0);
	    clrtoeol();
	    printw("Stake $%d",money);
	    refresh();
#ifdef TURBOC	    
	    delay(1000);
#else
	    usleep(LONGSLEEP);
#endif
	    numbj++;
	    continue;
	};

        /*  Play loop. */
	
	while (!stand[0] || (split && !stand[1])) {
	    
	   again:
	    
	    for(i=0;i<=split;i++)
	        if (!stand[i]) {
		    
		    /* Go to the proper spot. */
		    
		    if (i == 0) move(PLINE1+2,(5*pnum[0]+6));
		    else move(PLINE2+2,(5*pnum[1]+6));
		    refresh();
	            
	            /* Ask him what to do. */
		    c = mgetc(" HSD");
		    correct = correct_play(player[i],pnum[i]);
		    
		    /* Beep to annoy him. */
		    if (c != correct) {
#ifdef TURBOC
		       sound(75);
		       delay(100);
		       sound(35);
		       delay(50);
		       nosound();
#else
#endif
		       move(STATUS+1,0);
		       printw("Correct play was '%c'.",correct);
		       refresh();
		       nummp++;
		    };
		    
	            /* Do it. */
		    switch(c) {
			case 'Q':
			/* quit */
			break;

		        case ' ':
		        /*  Stand. */
			stand[i] = 1;
			break;
			
			case 'H':
			/*  Hit. */
			deal(i);
			break;
			
			case 'S':
			/*  Split.  */
			if (!split && pnum[0] == 2 &&
			    rank(player[0][0]) == rank(player[0][1])) {
			    split = 1;
			    player[1][0] = player[0][1];
			    pnum[0] = 1;
			    display_card(player[0],1,PLINE1);
			    deal(0);
			    display_card(player[1],1,PLINE2);
			    pnum[1] = 1;
			    deal(1);
			    /*  Only one card after splitting aces. */
			    if (rank(player[0][0]) == 1) {
			    	stand[0] = 1;
				stand[1] = 1;
			    };
			    goto again;
			};
			break;
			
			case 'D':
			/*  Double Down.  */
			if (pnum[i] == 2) {
			    bet[i] *= 2;
			    deal(i);
			    stand[i] = 1;
			};
			break;
			
		};
		
		/*  Bust check.  */
		
		if (bust(player[i],pnum[i])) {
		    move(MESSAGES,0);
		    clrtoeol();
		    printw("Bust!");
		    stand[i] = 1;
		    refresh();
		    numbust++;
		};
	    };
	};
	
	/*  Play dealers hand. */

        reveal();
	play_dealer();


        /*  Determine Results. */
	
	determine_results();

    };
    
};