|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T b
Length: 14933 (0x3a55) Types: TextFile Names: »blackjack.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/General/Bj1/blackjack.c«
/* * 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(); }; };