[comp.windows.news] BlackJack in NeWS

keith@sfu_css.cs.sfu (08/07/87)

I wrote this blackjack game as more an exercise in NeWS programming
more than a useful game (that's why it is posted here and not in
comp.sources.games). Hopefully you will find the ideas used within
the program useful although the code is relatively horrible.

You are free to do whatever you want to do to this.

Keith Vincent
Laboratory for Computer and Communication Research (LCCR)
Simon Fraser University
Burnaby, B.C. Canada V5A 1S6

E-Mail -          { ubc-vision }
	     ...! { uw-beaver  } !lccr!keith
	          {     sun    }


############## CUT HERE #################
#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./black.c`
then
echo "writing ./black.c"
cat > ./black.c << 'George_George_George_of_the_Jungle'
#include <black.h>

#define	PLAYER	0
#define	SPLIT	1
#define	DEALER	2

#define	UP	1
#define	DOWN	0

#define	SUIT(c)		(((c) & 0xF0) >> 4)
#define	VALUE(c)	((((c) & 0x0F) > 10) ? 10 : ((c) & 0x0F))

int	deck[52];
int	hand[3][52];
int	count[3];
int	points[3];

int	play_chips = 500;
int	deck_card_count = 0;
int	deal_down = -1;
int	split = 0;
int	wager;

main(argc, argv)
int	argc;
char	**argv;
{
	char	cwager[99];
	char	buff[99];
	long	t;
	int	playing = 1;
	int	tag;
	int	dummy;

	ps_open_PostScript();
	time(&t);
	srandom(getpid() + (int)((t >>16) +t));
	ps_init();
	ps_flush_PostScript();
	init_deck();
	shuffle();	/* shuffle the cards */
	wager = 1;
	ps_set_wager(wager);

	while(playing)
	{
		count[PLAYER] = 0;
		count[SPLIT] = 0;
		count[DEALER] = 0;
		deal_down = -1;
		split = 0;
		ps_message("");
		ps_hit_ok();
		ps_stand_ok();
		ps_wager_ok();
		ps_split_no();
		ps_newgame_no();

		card(PLAYER, UP);
		card(DEALER, DOWN);
		deal_down = hand[DEALER][0];
		card(PLAYER, UP);
		card(DEALER, UP);
		while(1)
		{
			if ((hand[PLAYER][0] & 0x0F) == (hand[PLAYER][1] & 0x0F))
				ps_split_ok();
			ps_flush_PostScript();
			if (ps_hit())
			{
				ps_wager_no();
				ps_split_no();
				switch (split)
				{
					case 0 :	/* no split */
						card(PLAYER, UP);
						if (points[PLAYER] > 21)
						{
							calc_winner();
						}
						break;
					case 1 :	/* first of split hands */
						card(PLAYER, UP);
						if (points[PLAYER] > 21)
						{
							ps_message("Play second hand");
							ps_split_second();
							split++;
						}
						break;
					case 2 :	/* second of split hands */
						card(SPLIT, UP);
						if (points[SPLIT] > 21 && points[PLAYER] > 21)
						{
							calc_winner();
						}
						else if (points[SPLIT] > 21)
						{
							ps_hit_no();
							ps_wager_no();
							ps_flip_card(deal_down & 0x0F, SUIT(deal_down));
							deal_down = -1;
							while (points[DEALER] <= 16)
								card(DEALER, UP);
							calc_winner();
						}
						break;
				}
			}
			if (ps_split())
			{
				split = 1;
				count[PLAYER] = 1;
				count[SPLIT] = 1;
				hand[SPLIT][0] = hand[PLAYER][1];
				ps_clear_cards();
				redraw_cards();
				ps_split_first();
				ps_split_no();
			}
			if (ps_stand())
			{
				ps_split_no();
				if (split == 1)
				{
					ps_split_second();
					split++;
				}
				else
				{
					ps_hit_no();
					ps_wager_no();
					ps_flip_card(deal_down & 0x0F, SUIT(deal_down));
					deal_down = -1;
					while (points[DEALER] <= 16)
						card(DEALER, UP);
					calc_winner();
				}
			}
			if (ps_wager(cwager))
			{
				wager = atoi(cwager);
			}
			if (ps_paint())
			{
				redraw_cards();
			}
			if (ps_newgame())
			{
				ps_hit_ok();
				ps_stand_ok();
				ps_newgame_no();
				ps_split_no();
				ps_clear_cards();
				break;
			}
			else if (ps_quit())
			{
				sprintf(buff, "You leave with %d dollars", play_chips);
				ps_message(buff);
				ps_flush_PostScript();
				playing = 0;
				break;
			}
		}
	}
	ps_close_PostScript();
	exit(0);
}

card(who, up)
int	who, up;
{
	int	c, i;
	int	ace = 0;

	if (deck_card_count > 51)
		shuffle();
	c = deck[deck_card_count++];
	hand[who][count[who]] = c;

	points[who] = 0;
	for (i = 0; i <= count[who]; i++)
	{
		if (VALUE(hand[who][i]) == 1)
			ace++;
		points[who] += VALUE(hand[who][i]);
	}
	for (i = 0; i < ace; i++)
		if (points[who] < 12)
			points[who] += 10;
	
	ps_show_card(who, up, count[who], SUIT(c), (c & 0x0F), split);
	count[who]++;
}

redraw_cards()
{
	int	i;

	if (split == 0)
	{
		for(i = 0; i < count[PLAYER]; i++)
			ps_show_card(PLAYER, UP, i, SUIT(hand[PLAYER][i]), (hand[PLAYER][i]) & 0x0F, 0);
	}
	else
	{
		for(i = 0; i < count[PLAYER]; i++)
			ps_show_card(PLAYER, UP, i, SUIT(hand[PLAYER][i]), (hand[PLAYER][i]) & 0x0F, 1);
		for(i = 0; i < count[SPLIT]; i++)
			ps_show_card(SPLIT, UP, i, SUIT(hand[SPLIT][i]), (hand[SPLIT][i]) & 0x0F, 2);
	}
	if (deal_down != -1)
		ps_show_card(DEALER, DOWN, 0, SUIT(hand[DEALER][0]), (hand[DEALER][0]) & 0x0F, 0);
	else
		ps_show_card(DEALER, UP, 0, SUIT(hand[DEALER][0]), (hand[DEALER][0]) & 0x0F, 0);
	for(i = 1; i < count[DEALER]; i++)
		ps_show_card(DEALER, UP, i, SUIT(hand[DEALER][i]), (hand[DEALER][i]) & 0x0F, 0);
}

init_deck()
{
	int	i, j;
	int	n = 0;

	for (i=1; i < 5; i++)
		for (j = 1; j < 14; j++)
		{
			deck[n++] = ((i & 0x0F) << 4) | (j & 0x0F);
		}
}

shuffle()
{
	int	i, j, c;
	long	random();

	for(i=52-1;i>=0;i--)
	{
		j = random() % 52;
		if (i != j)
		{
			c = deck[i];
			deck[i] = deck[j];
			deck[j] = c;
		}
	}
	deck_card_count = 0;
}

calc_winner()
{
	int	res = 0, res2 = 0;

	if (points[PLAYER] > 21)
		res = -1;
	else if (points[DEALER] > 21)
		res = 1;
	else if (points[PLAYER] > points[DEALER])
		res = 1;
	else if (points[PLAYER] == points[DEALER])
		res = 0;
	else
		res = -1;
	if(split != 0)
	{
		if (points[SPLIT] > 21)
			res2 = -1;
		else if (points[DEALER] > 21)
			res2 = 1;
		else if (points[SPLIT] > points[DEALER])
			res2 = 1;
		else if (points[SPLIT] == points[DEALER])
			res2 = 0;
		else
			res2 = -1;
		if (res == 0)
		{
			if (res2 == 0)
				ps_message("Both hands push");
			else if (res2 == -1)
				ps_message("One push, one loss");
			else if (res2 == 1)
				ps_message("One push, one win");
		}
		else if (res == 1)
		{
			if (res2 == 0)
				ps_message("One win, one push");
			else if (res2 == -1)
				ps_message("One win, one loss");
			else
				ps_message("Two wins");
		}
		else
		{
			if (res2 == 0)
				ps_message("One loss, one push");
			else if (res2 == -1)
				ps_message("Two losses");
			else
				ps_message("One loss, one win");
		}
	}
	else
	{
		if (res == 0)
			ps_message("Push");
		else if (res == 1)
			ps_message("You win");
		else
			ps_message("Dealer wins");
	}
	play_chips = play_chips + wager * (res + res2);
	ps_set_chips(play_chips);
	ps_newgame_ok();
	ps_hit_no();
	ps_stand_no();
}
George_George_George_of_the_Jungle
else
  echo "will not over write ./black.c"
fi
if `test ! -s ./black.cps`
then
echo "writing ./black.cps"
cat > ./black.cps << 'George_George_George_of_the_Jungle'
#define	TAG_HIT		901
#define	TAG_STAND	902
#define	TAG_NEWGAME	903
#define	TAG_QUIT	904
#define	TAG_WAGER	905
#define	TAG_PAINT	906
#define	TAG_SPLIT	907

cdef ps_hit()	=> TAG_HIT ()
cdef ps_stand() => TAG_STAND ()
cdef ps_newgame() => TAG_NEWGAME ()
cdef ps_quit()	=> TAG_QUIT ()
cdef ps_wager(string v) => TAG_WAGER (v)
cdef ps_paint() => TAG_PAINT ()
cdef ps_split() => TAG_SPLIT ()

cdef ps_message(string s)
	(%) [s] /printf messages send

cdef ps_set_wager(v)
	wager begin
		/ItemValue v 20 string cvs def
	end
	[wager] paintitems

cdef ps_set_chips(v)
	(Chips:%) [v] /printf chips send

cdef ps_split_ok()
	/notify-split { TAG_SPLIT tagprint } def

cdef ps_split_no()
	/notify-split {} def

cdef ps_wager_ok()
	/notify-wager { TAG_WAGER tagprint ItemValue typedprint } def

cdef ps_wager_no()
	/notify-wager {} def

cdef ps_hit_ok()
	/notify-hit { TAG_HIT tagprint } def

cdef ps_hit_no()
	/notify-hit {} def

cdef ps_stand_ok()
	/notify-stand { TAG_STAND tagprint } def

cdef ps_stand_no()
	/notify-stand {} def

cdef ps_newgame_ok()
	/notify-newgame { TAG_NEWGAME tagprint } def

cdef ps_newgame_no()
	/notify-newgame {} def

cdef ps_split_first()
	gsave
		20 40 moveto
		0 10 rlineto 10 0 rlineto 0 5 rlineto 10 -10 rlineto
		-10 -10 rlineto 0 5 rlineto -10 0 rlineto
		0 0 0 rgbcolor setcolor fill
	grestore
	
cdef ps_split_second()
	gsave
		20 40 moveto
		0 10 rlineto 10 0 rlineto 0 5 rlineto 10 -10 rlineto
		-10 -10 rlineto 0 5 rlineto -10 0 rlineto
		FillColor setcolor fill
		20 100 moveto
		0 10 rlineto 10 0 rlineto 0 5 rlineto 10 -10 rlineto
		-10 -10 rlineto 0 5 rlineto -10 0 rlineto
		0 0 0 rgbcolor setcolor fill
	grestore
	
cdef ps_clear_cards()
	gsave
		FillColor setcolor
		0 0 moveto 400 150 rect fill
		0 300 moveto 400 150 rect fill
	grestore

cdef ps_flip_card(val, suit)
		gsave
			1 1 1 rgbcolor setcolor 
			50 320 moveto 50 110 rect fill
			55 410 moveto
			0 0 0 rgbcolor setcolor
			TF card-val val 1 sub get show
			SF card-suit suit 1 sub get show
			50 320 moveto 50 110 rect stroke
		grestore
	
cdef ps_show_card(who, up, cnt, suit, val, split)
	can setcanvas
	/this-startx cnt 1 add 50 mul def
	who 2 lt 
		 { split 0 eq 
			{/this-starty  20 def /hgt 110 def} 
			{ split 1 eq
				{ /this-starty 20 def /hgt 50 def }
				{ /this-starty 80 def /hgt 50 def } ifelse
			} ifelse
		 }
		 { /this-starty 320 def /hgt 110 def} 
		 ifelse
	gsave
		0 0 0 rgbcolor setcolor
		up 0 eq 
		{
			gsave
				can /Color get 
					{ 1 0 0 rgbcolor }
					{ .9 .9 .9 rgbcolor } ifelse
				setcolor
				5 this-startx this-starty 60 hgt rrectpath fill
				0 0 0 rgbcolor setcolor
				this-startx 30 add this-starty hgt 2 div add 5 add moveto
				TF
				(Keith's) cshow
				this-startx 30 add this-starty hgt 2 div add 5 sub moveto
				(Casino) cshow
			grestore
		}
		{
			gsave
				1 1 1 rgbcolor setcolor 
				5 this-startx this-starty 60 hgt rrectpath fill
				this-startx 5 add this-starty hgt 20 sub add moveto
				0 0 0 rgbcolor setcolor
				TF card-val val 1 sub get show
				SF card-suit suit 1 sub get show
			grestore
		} ifelse
		5 this-startx this-starty 60 hgt rrectpath stroke
	grestore

cdef ps_init()
	systemdict /Item known not { (NeWS/liteitem.ps) run } if
	1 setlinequality
	3 setlinewidth
	/this-startx 0 def
	/this-starty 0 def
	/hgt 110 def
	/TF { /Times-Bold findfont 12 scalefont setfont } def
	/SF { /Symbol findfont 12 scalefont setfont } def
	/card-val [(A) (2) (3) (4) (5) (6) (7) (8) (9) (10) (J) (Q) (K)] def
	/card-suit [<A7> <A8> <A9> <AA>] def
	/notify-hit { } def
	/notify-stand { } def
	/notify-newgame { } def
	/notify-wager { } def
	/notify-split { } def
	/createitems
	{
		/items 10 dict dup begin
			/split (SPLIT) /notify-split can 40 40 /new ButtonItem send
				450 200 /move 3 index send def
			/hit (HIT) /notify-hit can 40 40 /new ButtonItem send
				450 150 /move 3 index send def
			/stand (STAND) /notify-stand can 40 40 /new ButtonItem send
				450 100 /move 3 index send def
			/newgame (NEW GAME) /notify-newgame can 40 40 /new ButtonItem send
				450 50 /move 3 index send def
			/quit (QUIT) {TAG_QUIT tagprint} can 40 40 /new ButtonItem send
				450 0 /move 3 index send def
			/wager (Wager:) (1         ) /Right /notify-wager can 50 0 
				/new TextItem send 450 250 /move 3 index send def
			/chips /panel_text (Chips:5000   ) /Right {} can 80 0
				/new MessageItem send dup begin
					/ItemFrame 1 def
					/ItemBorder 4 def
				end 450 300 /move 3 index send def
			/messages /panel_text () /Right {} can 500 0
				/new MessageItem send dup begin
					/ItemFrame 1 def
					/ItemBorder 4 def
				end 10 500 /move 3 index send def
		end def
		/wager items /wager get def
		/chips items /chips get def
		/messages items /messages get def
	} def
	/slideitem
	{
		gsave
			dup 4 1 roll
			/moveinteractive exch send
			/bbox exch send
		grestore
	} def
	/main
	{
		/win framebuffer /new DefaultWindow send def
		{
			/PaintClient {FillColor fillcanvas items paintitems TAG_PAINT tagprint} def
			/FrameLabel (Black Jack) def
		} win send
		200 200 600 600 /reshape win send
		/can win /ClientCanvas get def
		/FillColor can /Color get 
			{0 1 0 rgbcolor}
			{.5 .5 .5 rgbcolor} ifelse
			def

		createitems

		/slidemgr [
			items {
				exch pop dup /ItemCanvas get
				MiddleMouseButton [items FillColor 6 -1 roll /slideitem cvx] cvx
				DownTransition 4 -1 roll eventmgrinterest
			      } forall
		] forkeventmgr def

		/map win send

		/itemmgr items forkitems def
	} def
	main
George_George_George_of_the_Jungle
else
  echo "will not over write ./black.cps"
fi
echo "Finished archive 1 of 1"
exit