|
|
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();
};
};