Atlantic City blackjack v1.0
charles spell
cs00chs at unccvax.uncc.edu
Fri Oct 12 09:37:03 AEST 1990
Here is an Atlantic city blackjack game I hacked together one weekend before
going to Atlantic City. To compile (System V only):
cc bj.c -o bj -lcurses
A small contribution will be appreciated...I will send out fixes/enhancements
if there is enough monetary interest...
---cut here---cut here---cut here---cut here---cut here---cut here---cut here-
#include <curses.h>
#include <ctype.h>
#include <signal.h>
/*****************************************************************************
* You may freely distribute this file as long as the contents of this file
* have not been altered in any way or form. If you decide that you would like
* to re-distribute a change, please send to me for testing first - this keeps
* one current tested version out there...
*
* If you enjoy or find the program (in part or whole) useful,
* please send a contribution to:
* John J. Ribera, Jr.
* 9505-J University Terrace Dr.
* Charlotte, NC 28262
* Voice: (704) 549-5571
* Please send suggestions, comments, complaints, ideas, etc... to the author
* at the address above or e-mail : uunet!mcnc!unccvax!cs00chs
*/
/*****************************************************************************
* NAME Oct 90
* bj - a blackjack program
*
* SYNOPSIS
* bj
*
* DESCRIPTION
* This is an eight-deck Atlantic City blackjack game for system V. Splits and
* double downs are supported. No insurance. Use the Spacebar to Hit and CR to
* stand if desired. A redeal will occur when half of the all decks are used.
* bj uses terminfo GRAPHICS capablities - iff they are activated.
*
* NOTE
* The program looks much nicer if you have the smacs=, rmacs= and acsc=
* capabilities in your terminfo database...but it will still work
* without them...
*
* How to add graphics capabilities for vt100, vt101 and vt102 emulators:
* Type the following commands (re-start here if anything goes wrong):
* csh> setenv TERM vt100 # vt100 is an example-use TERM name youre that
* csh> mkdir ~/term # emulates a vt10[012] (in terminfo database)
* csh> infocmp > ~/term/info # this will create a terminfo source file.
* csh> setenv TERMINFO ~/term # Tell curses to use the database in ~/term
* csh> tic ~/term/info # Ignore warnings (if any)...
* Edit the ~/term/info file and add the following line to the proper entry:
* -go to the entry that emulates vt100 (eg. vt100,vt101, vt102)
* -add the following line to it...
* smacs=\E(0\E)0, rmacs=\E(B\E)B, acsc=jjkkllmmnnqqssttuuvvww++\,\,,
* -save it and type the following command:
* csh> tic ~/term/info
*
* For non vt100 emulators you must read your terminal reference manual and
* terminfo(5) to set it up properly. Some old terminals do not have a text
* graphics mode - i.e. you cannot see the pretty graphics.
*
* BUGS
* There are a few bugs. These will be fixed on the next version iff there is
* enough mmonetary interest. The dealer continues to deal to himself even
* after the outcome of a score is certain. No insurance. After the first
* shuffle, the WIN-LOSE is not displayed properly.
*
* AUTHOR
*
* (E-mail: uunet!mcnc!unccvax!cs00chs)
* John J. Ribera, Jr.
* 9505-J University Terrace Dr.
* Charlotte, NC 28262
* Voice: (704) 549-5571
*
* If you find this program or any part of it useful please send a
* contribution to the above address. This will allow you to receive
* the most recent fixes and versions. Make checks payable to
* John J. Ribera, Jr.
*/
/* flags for get_str() and get_chr()... */
#define CLR_FLD 0x0001
#define INIT_ONKEY 0x0010
#define MAP_UPPER 0x0002
#define MAP_LOWER 0x0004
#define AUTO_RET 0x0008
#define NOPAD 0x0020
#define NOECHO 0x0040
#define BEEP 0x0080
/* keystroke defines for readablity.... */
#define ESC 0x1b
#define CR '\r'
#define NL '\n'
#define BS '\b'
#define MAX_HANDS 3
#define DECKS 8
#define DEALER 0
#define DOWN 0
#define UP 1
#define WIN 0x0001
#define LOSE 0x0002
#define PUSH 0x0004
#define BJ 0x0008
#define GETCNT(i) (short) abs((int) (getcnt(i)))
typedef struct
{
short amt;
short bet;
short cnt;
short cards[13];
char name[9+1];
WINDOW *win;
} HAND;
HAND Hand[MAX_HANDS];
short Hands = 2;
short *Cards;
short Cur_card;
main()
{
short i, n, cnt, pcnt, dcnt;
short decks, cmp, bet;
short *cards, *shuffle();
short getcnt(), bj(), getbet();
char *cardtype();
char input[3], *ptr;
void done();
void inithand(), disphand();
signal(SIGINT, done);
initscr();
noecho();
crmode();
for (n = 0; n < MAX_HANDS; n++)
inithand(n);
srand(time((long *) 0));
while (TRUE)
{
clearok(stdscr, TRUE);
refresh();
for (i = 0; i < Hands; i++)
disphand(i);
wstandout(Hand[DEALER].win);
mvwprintw(Hand[DEALER].win, 0, 1, " B L A C K J A C K ");
wstandend(Hand[DEALER].win);
wprintw(Hand[DEALER].win, " by clt2!jjr... (press DEL to quit)");
mvwprintw(Hand[DEALER].win, 5, 1, "Shuffle...");
wrefresh(Hand[DEALER].win);
sleep(2);
Cards = shuffle((decks = DECKS));
Cur_card = 0;
while (Cur_card < decks * 52 / 2)
{
for (i = 1;Hands > 2; Hands--, i++)
werase(Hand[i+1].win), wrefresh(Hand[i+1].win);
Hands = 2;
for (n = 1; n < Hands; n++)
{
if (!getbet(n))
done();
Hand[n].cnt = 0;
disphand(n);
}
Hand[DEALER].cnt = 0;
disphand(DEALER);
getcard(1); getcard(DEALER);
getcard(1); getcard(DEALER);
getcard(1);
if (Hands > 2)
{
getcard(2);
getcard(2);
}
getcard(DEALER);
for (dcnt = GETCNT(DEALER), i = 1; i < Hands; i++)
{
if ((pcnt = GETCNT(i)) > 21 || dcnt > 21)
cmp = (pcnt > 21) ? LOSE : WIN;
else if (pcnt == dcnt)
cmp = (bj(i)) ? BJ : PUSH;
else
cmp = (pcnt > dcnt) ? (bj(i) ? BJ : WIN) : LOSE;
switch (cmp)
{
case WIN:
Hand[i].amt += Hand[i].bet;
Hand[DEALER].amt -= Hand[i].bet;
ptr = " WIN ";
break;
case BJ:
Hand[i].amt += Hand[i].bet + (Hand[i].bet / 2);
Hand[DEALER].amt -= (Hand[i].bet + Hand[i].bet / 2);
ptr = " WIN ";
break;
case PUSH:
ptr = " PUSH ";
break;
case LOSE:
Hand[DEALER].amt += Hand[i].bet;
Hand[i].amt -= Hand[i].bet;
ptr = " LOSE ";
break;
}
dispbet(i);
dispbet(DEALER);
wrefresh(Hand[i].win); wrefresh(Hand[0].win);
wstandout(Hand[i].win); mvwprintw(Hand[i].win, 2, 20, ptr);
wstandend(Hand[i].win); wrefresh(Hand[i].win);
}
}
promptfor("New deck...press return to continue...", ptr, 1, "", CLR_FLD);
}
}
void
inithand(n)
short n;
{
Hand[n].win = newwin((n == DEALER) ? 7 : 5,0,(n == DEALER) ? 0 : n * 5 + 2, 0);
Hand[n].amt = (DEALER == n ) ? 0 : 1000;
Hand[n].bet = 0L;
Hand[n].cnt = 0;
strcpy(Hand[n].name, getlogin());
strcpy(Hand[DEALER].name, "Dealer");
}
/*******************************************************************************
* shuffle will return a static pointer to an array of random shorts with a range
* of 0 to 52 * 'decks'. If 'decks' is > 10, then 10 decks will be returned.
* If 'decks' is < 1 then one shuffled deck will be returned.
*/
short *
shuffle(decks)
short decks;
{
static short deck[52 * 10 + 1];
short mark[52 * 10 + 1];
short card;
short cnt = 0;
memset(mark, '\0', sizeof(mark));
memset(deck, '\0', sizeof(deck));
decks = (decks < 1) ? 1 : ((decks > 10) ? 10 : decks);
while (cnt < 52 * decks)
if ((card = (short) rand() % (52 * decks)) >= 0 && !mark[card])
deck[cnt++] = card, mark[card] = 1;
deck[cnt] = -1;
return(deck);
}
/******************************************************************************
* cardtype will return a 3 character string that specifies which card 'card'
* represents. Character [1] of the returned string specifies the cardinality
* of 'card' and character [2] specifies the suit of 'card'.
*/
char *
cardtype(card)
short card;
{
static char value[27] = " A 2 3 4 5 6 7 8 910 J Q K";
static char suit[4] = "SHCD";
static char type[4];
strncpy(type, &value[((card % 52) / 4) << 1], 2);
type[2] = suit[card & 3];
type[3] = 0;
return(type);
}
int
boxit(win, rows, cols, brow, bcol)
WINDOW *win;
short rows;
short cols;
short brow;
short bcol;
{
short i;
wrefresh(win);
wattron(win, A_ALTCHARSET);
mvwaddch(win, brow, bcol, ACS_ULCORNER);
mvwaddch(win, brow+rows-1, bcol, ACS_LLCORNER);
for (i=bcol+1; i < bcol+cols-1; i++)
{
mvwaddch(win, brow, i, ACS_HLINE);
mvwaddch(win, brow+rows-1, i, ACS_HLINE);
}
mvwaddch(win, brow, i, ACS_URCORNER);
mvwaddch(win, brow+rows-1, i, ACS_LRCORNER);
for (i=brow+1; i < rows-1; i++)
{
mvwaddch(win, i, bcol, ACS_VLINE);
mvwprintw(win, i, bcol+1, "%*.*s", cols-2, cols-2, "");
mvwaddch(win, i, bcol+cols-1, ACS_VLINE);
}
wrefresh(win);
wattroff(win, A_ALTCHARSET);
}
void
getcard(hand)
short hand;
{
char c, getact();
char *sel, *cardtype();
char ctype1[5], ctype2[5];
short getcard();
void dispcard();
void dispbet();
if (Hand[hand].cnt < 2)
{
Hand[hand].cards[Hand[hand].cnt++] = nextcard();
dispcard(hand, Hand[hand].cnt-1, (hand==DEALER&&Hand[0].cnt==2)?DOWN:UP);
return;
}
if (hand == DEALER)
{
dispcard(DEALER, 1, UP);
while (GETCNT(DEALER) < 17 || getcnt(DEALER) < 0 && GETCNT(DEALER) == 17)
{
Hand[DEALER].cards[Hand[DEALER].cnt++] = nextcard();
dispcard(DEALER, Hand[DEALER].cnt-1, UP);
}
return;
}
if (GETCNT(hand) == 21)
return;
strcpy(ctype1, cardtype(Hand[hand].cards[0]));
strcpy(ctype2, cardtype(Hand[hand].cards[1]));
sel = (Hands < MAX_HANDS && ctype1[1]==ctype2[1]) ? "HSDP0123 " : "HSD123 ";
if ((c = getact(hand, sel)) == 'S')
return;
if (c == 'P')
{
Hands++;
Hand[hand].cnt--;
Hand[hand+1].bet = Hand[hand].bet;
Hand[hand+1].cards[0] = Hand[hand].cards[1];
Hand[hand+1].cnt = 1;
Hand[hand+1].bet = Hand[hand].bet;
Hand[hand+1].amt = 0L;
dispbet(hand);
disphand(hand + 1);
dispcard(hand + 1, 0, UP);
}
Hand[hand].cards[Hand[hand].cnt++] = nextcard();
dispcard(hand, Hand[hand].cnt-1, UP);
/*
if (GETCNT(hand) >= 21)
return;
*/
if (c == 'P')
{
if (getact(hand, "^HSD123 ") == 'S')
return;
Hand[hand].cards[Hand[hand].cnt++] = nextcard();
dispcard(hand, Hand[hand].cnt-1, UP);
}
if (c == 'D')
{
Hand[hand].bet *= 2;
dispbet(hand);
dispbet(DEALER);
return;
}
while (GETCNT(hand) < 21)
{
if ((c=getact(hand, "^HS12 ")) == 'S')
return;
Hand[hand].cards[Hand[hand].cnt++] = nextcard();
dispcard(hand, Hand[hand].cnt-1, UP);
}
return;
}
short
getcnt(hand)
short hand;
{
char *type;
char *strchr();
short cnt, acecnt;
short i;
for (i = 0, cnt = acecnt = 0; i < Hand[hand].cnt; i++)
{
type = cardtype(Hand[hand].cards[i]);
if (strchr("KQJ0", type[1]))
cnt += 10;
else if (strchr("23456789", type[1]))
cnt += type[1] - '0';
else
cnt += 11, acecnt++;
}
while (acecnt--)
if (cnt > 21)
cnt -= 10;
return(acecnt>0 ? -cnt : cnt);
}
char
getact(hand, valact)
short hand;
char *valact;
{
char prompt[80];
char choice[2];
char sel[5];
strcpy(sel, "PHSD");
sprintf(prompt, "Enter choice %s (Hit, Stand", Hand[hand].name);
if (strchr(valact, 'D'))
strcat(prompt, ", Double");
if (strchr(valact, 'P'))
strcat(prompt, ", sPlit");
strcat(prompt, "): ");
strcpy(choice, "S");
promptfor(prompt, choice, 1, valact, MAP_UPPER|AUTO_RET);
if (strchr("0123", choice[0]))
choice[0] = sel[choice[0] - '0'];
return(choice[0]);
}
short
getbet(hand)
short hand;
{
char prompt[80];
char bet[9];
int atoi();
if (Hand[hand].bet > 500)
Hand[hand].bet = 500;
sprintf(prompt, "Enter bet %s: ($2 - $500, 0 to quit) ", Hand[hand].name);
do
{
sprintf(bet, "%hd", Hand[hand].bet);
promptfor(prompt, bet, 5, "0123456789", INIT_ONKEY);
Hand[hand].bet = (long)atoi(bet);
if (!Hand[hand].bet)
return((short) 0);
} while (Hand[hand].bet % 2 || Hand[hand].bet > 500);
dispbet(hand);
return(Hand[hand].bet);
}
long
dispbet(hand)
short hand;
{
short i;
if (hand == DEALER)
for (i = 1, Hand[DEALER].bet = 0; i < Hands; i++)
Hand[DEALER].bet += Hand[i].bet;
mvwprintw(Hand[hand].win,2,1,"stakes : %5hd", Hand[hand].bet);
mvwprintw(Hand[hand].win,3,1,"credit : %+5hd", Hand[hand].amt);
wrefresh(Hand[hand].win);
return(Hand[hand].bet);
}
void
dispcard(hand, card, up)
short hand;
short card;
short up;
{
short bcol, val;
short bj();
char c,type[5];
bcol = 40 + (card - 2) * 3;
wstandout(Hand[hand].win);
boxit(Hand[hand].win, (short) 5, (short) 5, (short) 0, (short) bcol);
if (up)
{
strcpy(type, cardtype(Hand[hand].cards[card]));
c = type[2]; type[2] = 0;
mvwprintw(Hand[hand].win, 1, bcol+1, &type[(type[0] == ' ') ? 1 : 0]);
mvwprintw(Hand[hand].win, 2, bcol+2, "%c", c);
mvwprintw(Hand[hand].win, 3, bcol+2, type);
wrefresh(Hand[hand].win);
wstandend(Hand[hand].win);
wrefresh(Hand[hand].win);
mvwprintw(Hand[hand].win, 1, 13, "%5hd", (val = GETCNT(hand)));
if (GETCNT(hand) > 21)
mvwprintw(Hand[hand].win, 1, 21, "BUST ");
if (bj(hand))
mvwprintw(Hand[hand].win, 1, 21, "BLACKJACK! ");
}
wstandend(Hand[hand].win);
wrefresh(Hand[hand].win);
}
void
disphand(hand)
short hand;
{
short i;
for (i = 0; i < 5; i++)
wmove(Hand[hand].win, i, 1), wclrtoeol(Hand[hand].win);
mvwprintw(Hand[hand].win, 1, 1, "%-10.10s: ", Hand[hand].name);
if (hand < 2)
dispbet(hand);
wrefresh(Hand[hand].win);
}
void
promptfor(prompt, input, max, vchrs, flags)
char *prompt;
char *input;
short max;
long flags;
{
char *strchr();
wmove(Hand[DEALER].win, 5, 1);
while (*prompt)
if (strchr(vchrs, *prompt) && *prompt != ' ')
{
wstandout(Hand[DEALER].win);
waddch(Hand[DEALER].win, *prompt++);
wstandend(Hand[DEALER].win);
}
else
waddch(Hand[DEALER].win, *prompt++);
waddch(Hand[DEALER].win, ' ');
get_str(Hand[DEALER].win, input, max, vchrs, flags);
wmove(Hand[DEALER].win, 5, 1); wclrtoeol(Hand[DEALER].win);
wrefresh(Hand[DEALER].win);
}
short
nextcard()
{
return(Cards[Cur_card++]);
}
short
bj(hand)
short hand;
{
if (GETCNT(hand) != 21)
return((short)0);
if (Hand[hand].cnt == 2)
return((short)1);
return((short)0);
}
/******************************************************************************
* get a string through curses...how many times has this been re-written?
* Returns: key that caused get_str to return.
* Side Effects: _str_ holds a space padded array of characters entered by user.
* _win_ will be changed by the contents of string
* Note: wattron before call to get_str for pretty display of input box...
* noecho() should be enabled...
*/
short
get_str(win, str, max, vchrs, flags)
WINDOW *win; /* input window */
char *str; /* changed by side effect */
short max; /* stop when this is reached */
char *vchrs; /* valid keystrokes... */
short flags; /* all kinds of options... */
{
short sr, sc; /* save row save column -restored on ret*/
short ofs =0; /* current offset from beginning of str */
short ret =0; /* return status != when return desired */
short c; /* each input char is put into this var */
short first=TRUE; /* first time through the main loop? */
char save[256]; /* max better be less than 256 chars */
wrefresh(win); /* dump any changes */
getyx(win, sr, sc); /* get logical cursor location*/
if (flags & CLR_FLD) /* initialize field from beginning? */
sprintf(str, "%*.*s", max, max, "");
strcpy(save, str); /* save in case of an ESC... */
sprintf(str, "%-*.*s", max, max, save); /* left justified...pad for now... */
if (~flags & NOECHO) /* if we want to echo string... */
waddstr(win, str);
wmove(win, sr, sc+ofs);
while (!ret)
{
if (isprint((c = get_chr(win, vchrs, flags))))
{ /* clear the input string on first */
if (ofs == max) /* dont write over the terminating */
ofs--; /* null character... */
if (first && flags & INIT_ONKEY)/* clear on first printable char... */
sprintf(str, "%*.*s", max, max, "");
str[ofs++] = (char) c;
if (ofs == max) /* if at end of string already... */
if (flags & AUTO_RET) /* and AUTO_RET flag ON then... */
ret = CR; /* pretend CR was pressed... */
}
else
switch (c)
{
case CR:
case NL:
case KEY_UP:
case KEY_DOWN:
ret = c;
break;
case ESC:
strcpy(str, save);
ret = c;
break;
case KEY_RIGHT:
if (ofs < max)
str[ofs++] = ' ';
break;
case KEY_LEFT:
case BS:
if (ofs)
ofs--;
break;
default:
ret = c;
break;
}
if (~flags & NOECHO) /* if NOECHO is OFF then disp str...*/
mvwaddstr(win, sr, sc, str); /* (display after each character) */
wmove(win, sr, sc+ofs);
wrefresh(win);
first = FALSE; /* we have been around the loop... */
}
if (flags & NOPAD)
for (ofs = 0; ofs < max; ofs++)
if (str[ofs] == ' ')
c = ofs;
return(ret);
}
short
get_chr(win, vchrs, flags)
WINDOW *win;
char *vchrs;
short flags;
{
short c;
wrefresh(win);
while ((c = wgetch(win)) == ERR)
if (isprint(c) && strchr(vchrs, c))
break;
else if (flags & BEEP)
beep();
if (flags & MAP_UPPER)
if (c >= 'a' && c <= 'z')
c = toupper(c);
if (flags & MAP_LOWER)
if (c >= 'A' && c <= 'A')
c = tolower(c);
return(c);
}
void
done()
{
mvprintw(19, 20, "Quit with %hd dollars", Hand[1].amt);
mvprintw(20, 20, "Press any key to exit...");
refresh();
getch();
endwin();
exit(0);
}
---cut here---cut here---cut here---cut here---cut here---cut here---cut here--
--
.--------------------------. ... |On the border of your mind lies a place
|uunet!mcnc!unccvax!cs00chs| (") |where dreams and reality are one...I will
`--------------------------'-w-U-w-|take you there, for I am the subject...
\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\|the subject of your imagination. -Aldo Nova
More information about the Alt.sources
mailing list