[comp.sources.games] v05i030: yahtzee - curses based game of yahtzee, Part01/02

games@tekred.TEK.COM (07/27/88)

Submitted by: lsuc!hcr!hcrvax!stacey (Stacey Campbell)
Comp.sources.games: Volume 5, Issue 30
Archive-name: yahtzee/Part01

	[I compiled and ran this on a Sun 3/60 (Sun OS 3.5) with no
	 probelms whatsoever (just edited the makefile).  -br]

	[[Here is a game I have been working on for a while.
	It works on both System 5 and BSD.  The README
	file contains details on how to install it
	and the game itself contains rules on how
	to play it. The program makes heavy use of
	curses and I have limited it to features common
	to both System 5 and BSD curses.]]

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 2)."
# Contents:  README MANIFEST best.c costs.c costs.h help.h high.c
#   play_info.c shwin.c yz.c
# Wrapped by billr@saab on Tue Jul 26 11:42:41 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(1441 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XThis is the first (and possibly only) release of Yahtzee.
XYahtzee is also known as dice poker.  Full rules are available
Xin the game by pressing 'b' at any time, and help is
Xavailable at all times by pressing '?'.
X
XThis version compiles and runs under HCR's Unix System V.3 port
Xfor the VAX, the CDC Unix System V.2 emulation for NOS/VE
Xcalled VX/VE running on various Cyber machines, and
XInteractive's 386/ix Unix running on a 386 box.
X
XFor BSD people the game has been ported to an IBM RT running
XBSD 4.3.
X
XYahtzee is likely to compile and run under anything that claims
Xto be Unix.
X
XThe Makefile will have to be altered, just follow the instructions
Xin the file.
X
XThe high score file is configured in the Makefile and is
Xcreated by the first person to run the program. If you want
Xother people to use the score file chmod(1) the file accordingly.
XThe program will still function if it can't access the high score
Xfile.
X
XIf something doesn't work then send me the problem, or even better
Xyour fix, and something will be done for a later version.  The program
Xhas many bells and whistles so if you don't like Yahtzee you can
Xstill have fun discovering them.  Note: the shell window code
Xhasn't been ported to BSD.
X
XPlease read the copyright notice and disclaimer in the first
XC file, best.c.
X
Xhave fun,
X
XStacey Campbell.
X
X{lsuc,utzoo,utcsri}!hcr!hcrvax!stacey, HCR Corporation,
X130 Bloor St W, Toronto, Ontario, Canada. +1 416 922 1937 X48
END_OF_FILE
if test 1441 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(1044 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X MANIFEST                   1	This shipping list
X README                     1	
X best.c                     1	
X boxup.c                    2	
X comp_select.c              2	
X costs.c                    1	
X costs.h                    1	
X defs.h                     2	
X dice.h                     2	
X dis_dice.c                 2	
X eval.c                     2	
X find.c                     2	
X finish.c                   2	
X get_m.c                    2	
X help.c                     2	
X help.h                     1	
X high.c                     1	
X makefile                   2	
X misc.c                     2	
X opthelp.c                  2	
X play_info.c                1	
X rools.c                    2	
X rools.h                    2	
X shell.c                    2	
X shwin.c                    1	
X side.h                     2	
X update_score.c             2	
X values.c                   2	
X yahtzee.6                  2	
X yz.c                       1	
END_OF_FILE
if test 1044 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'best.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'best.c'\"
else
echo shar: Extracting \"'best.c'\" \(7699 characters\)
sed "s/^X//" >'best.c' <<'END_OF_FILE'
X/****************************************************************************/
X/**                  Copyright 1988 by HCR Corporation,                    **/
X/**                       Toronto, Ontario, Canada                         **/
X/**                                                                        **/
X/**                          All Rights Reserved                           **/
X/**                                                                        **/
X/**   Permission to use, copy, modify, and distribute this software and    **/
X/**   its documentation  for  any  purpose  and  without  fee is hereby    **/
X/**   granted, provided that the above copyright notice appear  in  all    **/
X/**   copies and that both  that  copyright  notice  and  this  permis-    **/
X/**   sion  notice appear in supporting  documentation,  and  that  the    **/
X/**   name of  HCR Corporation  not  be  used  in advertising or publi-    **/
X/**   city pertaining to distribution  of the software without  specif-    **/
X/**   ic, written prior permission.                                        **/
X/**                                                                        **/
X/**   HCR   CORPORATION   DISCLAIMS  ALL   WARRANTIES  WITH  REGARD  TO    **/
X/**   THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILI-    **/
X/**   TY AND  FITNESS,  IN  NO EVENT  SHALL HCR  CORPORATION BE  LIABLE    **/
X/**   FOR  ANY  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY  DAM-    **/
X/**   AGES  WHATSOEVER RESULTING FROM  LOSS OF USE,  DATA  OR  PROFITS,    **/
X/**   WHETHER   IN  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS    **/
X/**   ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE  OR PER-    **/
X/**   FORMANCE OF THIS SOFTWARE.                                           **/
X/****************************************************************************/
X
X/* best.c
X *	This file contains routines to determine which dice
X *	to hold for all possible categories given any 
X *	combination of dice.
X *	These routines are called frequently by the heuristic
X *	evaluation function hence the inlining of code.
X */
X
X#include "defs.h"
X#ifndef TRUE
X#define TRUE 1
X#endif
X#ifndef FALSE
X#define FALSE 0
X#endif
X
X/* count the number of times dice values appear in a set of dice */
X#define rep_count(dice, reps) \
X	{ \
X	register int i; \
X	for (i = 1; i <= dicecount; ++i) \
X		reps[i] = 0; \
X	for (i = 0; i < Five_Dice; ++i) \
X		++reps[dice[i]]; \
X	}
X
X/* discard (set hold[i] to false) the first die corresponding to die_val */
Xstatic void discard_value(dice, hold, die_val)
X
Xint dice[Five_Dice], hold[Five_Dice], die_val;
X
X	{
X	register int i;
X
X	for (i = 0; i < Five_Dice; ++i)
X		if (dice[i] == die_val)
X			if (hold[i])
X				{
X				hold[i] = FALSE;
X				return;
X				}
X	}
X
X/* discard any dice that have less than 2 representatives in a set of dice */
Xvoid discard_full_house(dice, dummy, hold)
X
Xint *dice, dummy, *hold;
X
X	{
X	register int reps[7], i;
X
X	rep_count(dice, reps)
X	for (i = 0; i < Five_Dice; ++i)
X		*hold++ = reps[*dice++] > 1;
X	}
X
X/* if any dice value has multiple representation in a set of dice
X * then discard all but one of those dice (e.g. dice == 1 2 3 3 1
X * will produce hold == 0 1 0 1 1) */
Xstatic void discard_extras(dice, hold, reps)
X
Xint dice[Five_Dice], hold[Five_Dice], reps[7];
X
X	{
X	register int i, j;
X
X	for (i = 1; i <= dicecount; ++i)
X		{
X		j = 0;
X		while (reps[i] > 1)
X			{
X			if (dice[j] == i)
X				{
X				hold[j] = FALSE;
X				--reps[i];
X				}
X			++j;
X			}
X		}
X	}
X
X/* discard dice for a small or large straight */
Xstatic void discard_run(dice, mark, hold)
X
Xint dice[Five_Dice], hold[Five_Dice], mark;
X
X	{
X	int i, reps[7], cur_run = 0, largest_run = 0, start_run, end_run;
X	void zap_die();
X
X/* assume all dice are held */
X	for (i = 0; i < Five_Dice; ++i)
X		hold[i] = TRUE;
X
X/* determine representation for each dice value */
X	rep_count(dice, reps)
X	start_run = 1;
X
X/* determine if there is a run in the dice values (and how long it is) */
X	for (i = 1; i < dicecount; ++i)
X
X/* this test is true if there are consecutive dice */
X		if (reps[i] && reps[i + 1])
X			++cur_run;
X		else
X
X/* ...else a break in the dice */
X			{
X
X/* if the current run of consecutive values is better than the previous best */
X			if (largest_run < cur_run)
X				{
X
X/* store size of run and where it started */
X				largest_run = cur_run;
X				start_run = i - cur_run;
X				}
X			cur_run = 0;
X			}
X	if (largest_run < cur_run)
X		{
X		largest_run = cur_run;
X		start_run = dicecount - cur_run;
X		}
X
X	end_run = largest_run + cur_run;
X
X/* discard multiple occurances of dice */
X	discard_extras(dice, hold, reps);
X
X/* remove dice that make it difficult or impossible to make a run */
X	zap_die(dice, hold, 1, 6, start_run, end_run);
X	if (mark == 4)
X		{
X		zap_die(dice, hold, 1, 5, start_run, end_run);
X		zap_die(dice, hold, 2, 6, start_run, end_run);
X		}
X	}
X
Xstatic void zap_die(dice, hold, pair1, pair2, start_run, end_run)
X
Xint dice[Five_Dice], hold[Five_Dice], pair1, pair2, start_run, end_run;
X
X	{
X	if (held(dice, hold, pair1) && held(dice, hold, pair2))
X		if (start_run <= pair1 && pair1 <= end_run)
X			discard_value(dice, hold, pair2);
X		else
X			discard_value(dice, hold, pair1);
X	}
X
X/* held() returns true of die_val is one of the dice and it is held */
Xstatic int held(dice, hold, die_val)
X
Xint dice[Five_Dice], hold[Five_Dice], die_val;
X
X	{
X	register int i;
X
X	for (i = 0; i < Five_Dice; ++i)
X		if (dice[i] == die_val)
X			if (hold[i])
X				return(TRUE);
X	return(FALSE);
X	}
X
X/* discard any dice with a value less than 4 in attempt to produce best
X * possible chance score */
Xstatic void discard_chance(dice, dummy, hold)
X
Xint *dice, dummy, *hold;
X
X	{
X	register int i;
X
X	for (i = 0; i < Five_Dice; ++i)
X		*hold++ = *dice++ > 3;
X	}
X
X/* discard all dice that do not correspond to mark */
Xstatic void discard_num(dice, mark, hold)
X
Xint *dice, mark, *hold;
X
X	{
X	register int i;
X
X	for (i = 0; i < Five_Dice; ++i)
X		*hold++ = (*dice++) == mark;
X	}
X
Xstatic float sqrtmap[7] = {0.0, 1.0, 1.414, 1.732, 2.0, 2.236, 2.449};
X
X/* determine best dice to hold for 3 of a kind and 4 of a kind */
Xstatic void discard_of_a_kind(dice, dummy, hold)
X
Xint dice[Five_Dice], dummy, hold[Five_Dice];
X
X	{
X	register int i, best_index = Five_Dice;
X	register float rep_vals[7], best_rep = 0.0;
X
X	for (i = 1; i <= dicecount; ++i)
X		rep_vals[i] = 0.0;
X	for (i = 0; i < Five_Dice; ++i)
X		rep_vals[dice[i]] += sqrtmap[dice[i]];
X
X/* determine which dice value will produce the best 'of a kind' score */
X	for (i = 1; i <= dicecount; ++i)
X		if (rep_vals[i] > best_rep)
X			{
X			best_rep = rep_vals[i];
X			best_index = i;
X			}
X
X/* discard dice which do not correspond to that value */
X	discard_num(dice, best_index, hold);
X	}
X
X/* determine which dice has the best representation and hold
X * all dice of that value */
Xstatic void discard_yahtzee(dice, dummy, hold)
X
Xint dice[Five_Dice], dummy, hold[Five_Dice];
X
X	{
X	register int reps[7], best_count, best_rep, i;
X
X	rep_count(dice, reps)
X	best_count = 0;
X	for (i = 1; i <= dicecount; ++i)
X		if (reps[i] >= best_count)
X			{
X			best_rep = i;
X			best_count = reps[i];
X			}
X	discard_num(dice, best_rep, hold);
X	}
X
X/* the above routines are accessed by the heuristics via a table
X * of function calls, find_kind[14] is a fixed array of parameters
X * for the functions, find_table is the mapping of functions,
X * this rigamarole is used to avoid an expensive switch statement */
X
Xint find_kind[14] = {0, 1, 2, 3, 4, 5, 6, 3, 4, 0, 4, 5, 5, 0};
Xvoid (*find_table[])() = {discard_num, discard_num, discard_num,
X	discard_num, discard_num, discard_num, discard_num,
X	discard_of_a_kind, discard_of_a_kind, discard_full_house,
X	discard_run, discard_run, discard_yahtzee, discard_chance};
END_OF_FILE
if test 7699 -ne `wc -c <'best.c'`; then
    echo shar: \"'best.c'\" unpacked with wrong size!
fi
# end of 'best.c'
fi
if test -f 'costs.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'costs.c'\"
else
echo shar: Extracting \"'costs.c'\" \(19 characters\)
sed "s/^X//" >'costs.c' <<'END_OF_FILE'
X#include "costs.h"
END_OF_FILE
if test 19 -ne `wc -c <'costs.c'`; then
    echo shar: \"'costs.c'\" unpacked with wrong size!
fi
# end of 'costs.c'
fi
if test -f 'costs.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'costs.h'\"
else
echo shar: Extracting \"'costs.h'\" \(7541 characters\)
sed "s/^X//" >'costs.h' <<'END_OF_FILE'
X/*	This sparse array is accessed very frequently by the
X *	heuristics, any other implementation of this data
X *	structure would slow the program considerably.
X */
X
Xfloat cost_list[13][51] = {
X /* one */ {1.000000, 0.300000, 1.000000, 1.000000, 1.700000,
X	1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
X	1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
X	1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
X	1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
X	1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
X	1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
X	1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
X	1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
X	1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
X	1.000000},
X /* two */ {-1.000000, -1.000000, -2.000000, -0.714286, -1.000000,
X	-0.428571, 1.000000, -0.142857, 0.142857, 0.142857,
X	0.428571, 0.428571, 0.714286, 0.714286, 1.000000,
X	1.000000, 1.285714, 1.285714, 1.571429, 1.571429,
X	1.857143, 1.857143, 2.142857, 2.142857, 2.428571,
X	2.428571, 2.714286, 2.714286, 3.000000, 3.000000,
X	3.285714, 3.285714, 3.571429, 3.571429, 3.857143,
X	3.857143, 4.142857, 4.142857, 4.428571, 4.428571,
X	-5.000000, 4.714286, 5.000000, 5.000000, 5.285714,
X	5.285714, 5.571429, 5.571429, 5.857143, 5.857143,
X	6.142857},
X /* three */ {-7.000000, -7.000000, -7.000000, -7.000000, -4.000000,
X	-4.000000, -5.000000, -3.500000, -3.000000, 2.000000,
X	2.000000, 2.000000, -1.000000, 5.000000, 5.000000,
X	11.000000, 8.000000, 8.000000, 11.000000, 11.000000,
X	11.000000, 14.000000, 14.000000, 14.000000, 17.000000,
X	17.000000, 17.000000, 20.000000, 20.000000, 20.000000,
X	23.000000, 23.000000, 23.000000, 26.000000, 26.000000,
X	26.000000, 29.000000, 29.000000, 29.000000, 32.000000,
X	32.000000, 32.000000, 35.000000, 35.000000, 35.000000,
X	38.000000, 38.000000, 38.000000, 41.000000, 41.000000,
X	41.000000},
X /* four */ {-27.000000, -27.000000, -27.000000, -27.000000, -19.000000,
X	-19.000000, -19.000000, -19.000000, -11.000000, -5.100000,
X	-5.500000, -11.000000, 9.000000, 9.000000, 9.000000,
X	9.000000, 14.000000, 14.000000, 14.000000, 14.000000,
X	19.000000, 19.000000, 19.000000, 19.000000, 24.000000,
X	24.000000, 24.000000, 24.000000, 29.000000, 29.000000,
X	29.000000, 29.000000, 34.000000, 34.000000, 34.000000,
X	34.000000, 39.000000, 39.000000, 39.000000, 39.000000,
X	44.000000, 44.000000, 44.000000, 44.000000, 49.000000,
X	49.000000, 49.000000, 49.000000, 54.000000, 54.000000,
X	54.000000},
X /* five */ {-31.000000, -31.000000, -31.000000, -31.000000, -31.000000,
X	-22.000000, -22.000000, -22.000000, -22.000000, -22.000000,
X	-13.000000, -13.000000, -9.000000, -10.000000, -13.000000,
X	9.000000, 10.000000, 10.000000, 10.000000, 10.000000,
X	16.000000, 16.000000, 16.000000, 16.000000, 16.000000,
X	22.000000, 22.000000, 22.000000, 22.000000, 22.000000,
X	28.000000, 28.000000, 28.000000, 28.000000, 28.000000,
X	34.000000, 34.000000, 34.000000, 34.000000, 34.000000,
X	40.000000, 40.000000, 40.000000, 40.000000, 40.000000,
X	46.000000, 46.000000, 46.000000, 46.000000, 46.000000,
X	52.000000},
X /* six */ {-35.000000, -35.000000, -35.000000, -35.000000, -35.000000,
X	-35.000000, -25.000000, -25.000000, -25.000000, -25.000000,
X	-25.000000, -25.000000, -18.000000, -10.000000, -8.000000,
X	-9.000000, -10.000000, -15.000000, 6.700000, 11.000000,
X	11.000000, 11.000000, 11.000000, 11.000000, 18.000000,
X	18.000000, 18.000000, 18.000000, 18.000000, 18.000000,
X	19.000000, 25.000000, 25.000000, 25.000000, 25.000000,
X	25.000000, 32.000000, 32.000000, 32.000000, 32.000000,
X	32.000000, 32.000000, 39.000000, 39.000000, 39.000000,
X	39.000000, 39.000000, 39.000000, 46.000000, 46.000000,
X	46.000000},
X /* 3 of a kind */ {-2.000000, 0.100000, 0.200000, 0.300000, 0.400000,
X	-1.000000, -1.100000, -4.500000, -5.500000, -8.000000,
X	-10.000000, -10.000000, -12.000000, -9.900000, -12.000000,
X	-12.000000, -9.700000, -11.500000, -12.000000, -9.900000,
X	-12.000000, -11.000000, -1.000000, -2.000000, 0.400000,
X	-0.500000, 2.600000, 2.700000, 2.800000, 2.900000,
X	3.000000, 3.100000, 3.200000, 3.300000, 3.400000,
X	3.500000, 3.600000, 3.700000, 3.800000, 3.900000,
X	4.000000, 4.100000, 4.200000, 4.300000, 4.400000,
X	4.500000, 4.600000, 4.700000, 4.800000, 4.900000,
X	5.000000},
X /* 4 of a kind */ {-1.500000, 0.111111, 0.222222, 0.333333, 0.444444,
X	0.555556, -1.000000, -3.377778, -4.000000, -7.000000,
X	-9.000000, -4.222220, -10.000000, -5.000000, -6.500000,
X	-5.999999, -5.700000, -8.500000, -8.500000, 2.111111,
X	2.222222, 2.333333, 2.444444, 2.555556, 2.666667,
X	2.777778, 2.888889, 3.000000, 3.111111, 3.222222,
X	3.333333, 3.444444, 3.555556, 3.666667, 3.777778,
X	3.888889, 4.000000, 4.111111, 4.222222, 4.333333,
X	4.444444, 4.555556, 4.666667, 4.777778, 4.888889,
X	5.000000, 5.111111, 5.222222, 5.333333, 5.444444,
X	5.555556},
X /* full house */ {-3.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000},
X /* small straight */ {-3.000000, 0.000000, 0.000000, -1.000000, -6.000000,
X	-7.000000, -7.000000, -7.000000, -8.000000, -8.000000,
X	-8.000000, -10.000000, -8.000000, -7.000000, -9.000000,
X	-9.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000},
X /* large straight */ {-5.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000},
X /* yahtzee */ {-1.001000, 4.000000, 5.000000, 13.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000},
X /* chance */ {-8.000000, -9.000000, -10.000000, -11.000000, -12.000000,
X	-13.000000, -14.000000, -15.000000, -16.000000, -17.000000,
X	-17.000000, -17.000000, -17.000000, -17.000000, -14.000000,
X	-16.000000, -16.000000, -16.000000, -16.000000, -16.000000,
X	-17.000000, -17.000000, -17.000000, -17.000000, -20.000000,
X	-21.000000, -22.000000, -23.000000, -24.000000, -25.000000,
X	-26.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
X	0.000000}};
END_OF_FILE
if test 7541 -ne `wc -c <'costs.h'`; then
    echo shar: \"'costs.h'\" unpacked with wrong size!
fi
# end of 'costs.h'
fi
if test -f 'help.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'help.h'\"
else
echo shar: Extracting \"'help.h'\" \(5187 characters\)
sed "s/^X//" >'help.h' <<'END_OF_FILE'
X#define max_lines 20
X#define max_cols 55
X
Xchar help_words[9][max_lines + 1][max_cols + 1] = {
X	{"Player Selection",
X	 " ",
X	 "This is where you select which players will be",
X	 "human and which will be simulated by the computer.",
X	 " ",
X	 " press 'k' - to move the cursor up",
X	 "       'j' - to move the cursor down",
X	 "     space - to toggle between human or computer",
X	 "       'b' - to display rule book",
X	 "       'q' - to quit the game",
X	 "       'v' - version display",
X         "    return - to begin play",
X	 "other features:",
X#if defined(SYS5) || defined(SYS5_3)
X	 " - shell window available by pressing '$' during play",
X#endif
X	 " - on-line help available by pressing '?' during play",
X	 " - redraw current window with '^L'",
X	 " - rule book available by pressing 'b' during play"},
X	{"End of Game",
X	 " ",
X	 "To continue the game press 'c', otherwise press",
X	 "'q' to quit.  Note that the high score file will",
X	 "only ever keep the highest score in the given round.",
X	 "The high score file can be displayed by pressing 's'",
X	 "at most times (including now).",
X	 " ",
X	 "The game can be reconfigured by pressing 'r'.",
X	 "This allows you to alter the number of players",
X	 "and which players are simulated."},
X	{"Select Dice to Hold",
X	 " ",
X	 "Select which dice you want to hold such that they",
X	 "will not be part of the next roll of the dice.",
X	 "Hold the dice that are likely to give the best",
X	 "score for your score-card.",
X	 " press 'l' - to move cursor right",
X	 "       'h' - to move cursor left",
X	 "     space - to hold/free die cursor is on",
X	 "    return - to roll dice",
X	 "       'r' - to get computer's advice on best hold",
X	 "       't' - shows value of dice in all categories",
X	 "       'a' - to hold all dice then roll",
X	 "       'b' - to display rule book",
X#if defined(SYS5) || defined(SYS5_3)
X	 "       '$' - to obtain shell window",
X#endif
X	 "       '!' - to obtain shell",
X	 "       'q' - to quit the game"},
X	{"Select Score Card Position",
X	 " ",
X	 "Select one of the available places to put the",
X	 "score for your final set of dice.  If your dice",
X	 "don't meet the requirements for the selected place",
X	 "you will receive 0 points (e.g. putting 1 2 3 6 6 in",
X	 "the 'three of a kind' position).",
X	 " ",
X	 " press 'k' - to move the cursor up",
X	 "       'j' - to move the cursor down",
X	 "    return - put score in indicated category",
X	 "       'r' - get computer's advice on best category",
X	 "       't' - shows value of dice in all categories",
X	 "       'b' - to display rule book",
X#if defined(SYS5) || defined(SYS5_3)
X	 "       '$' - to obtain shell window",
X#endif
X	 "       '!' - to obtain shell",
X	 "       'q' - to quit the game"},
X	{"Rules of Yahtzee",
X	 " ",
X	 "These are not the definitive rules for this game,",
X	 "many other versions exist, the game is sometimes",
X	 "referred to as 'dice poker'.  Possibly the rule",
X	 "with the greatest variation is the 'two hold' rule",
X	 "where the dice are held twice.  Some versions of",
X	 "Yahtzee only allow for one chance at holding dice.",
X	 "Allowing the player to hold twice, however, decreases",
X	 "the amount of 'luck' required to win, and increases",
X	 "the need for skillfull play."},
X	{"Help",
X	 " ",
X	 "Help is available at all stages of the game.",
X	 "Press 'q' or space to exit help.",
X	 " ",
X	 " press 'b' - to display rule book",
X	 "       's' - to display current scoreboard",
X	 "      '^L' - to redraw current window",
X	 "       '!' - to obtain shell escape",
X#if defined(SYS5) || defined(SYS5_3)
X	 "       '$' - enters shell window when pressed",
X#endif
X	 "       'v' - display yahtzee version"},
X	{"Player Count",
X	 " ",
X	 "Input the number of players, this version can have",
X	 "up to six players in a game. Also you can...",
X	 " ",
X	 "press 'q' - to quit the game",
X	 "     '^L' - redraws screen whenever pressed",
X	 "      'b' - displays the rule book whenever pressed",
X#if defined(SYS5) || defined(SYS5_3)
X	 "      '$' - enters shell window whenever pressed",
X#endif
X	 "      '!' - to obtain shell",
X	 "      'v' - displays yahtzee version",
X	 "      's' - displays the score board when pressed"},
X	{"High Score",
X	 " ",
X	 "This is the most recent high score file, it is",
X	 "updated at the end of each game.  Only the player",
X	 "with the highest score in a game is eligable to",
X	 "have their score recorded.",
X	 " ",
X	 "press 'q' - to resume the game",
X	 "     '^L' - to redraw the current window",
X#if defined(SYS5) || defined(SYS5_3)
X	 "      '$' - to obtain shell window",
X#endif
X	 "      '!' - to obtain shell",
X	 "      'v' - displays yahtzee version",
X	 "      'b' - to display the rule book"},
X	{"Shell Window",
X	 " ",
X	 "This is a limited shell window and should not be",
X	 "used for programs using full screen curses(3X)",
X	 "features (e.g. don't try to play yahtzee from",
X	 "inside this shell window).  Programs that expect",
X	 "input from stderr will also fail.",
X	 "To leave the shell and return to the game type",
X	 "exit at the shell prompt.  Also:",
X	 " ",
X	 "press '~.' - to kill shell",
X	 "      '~T' - to signal SIGTERM to shell",
X	 "      '~c' - toggle ticking clock on or off",
X	 "      '~~' - to send tilde to shell"}};
END_OF_FILE
if test 5187 -ne `wc -c <'help.h'`; then
    echo shar: \"'help.h'\" unpacked with wrong size!
fi
# end of 'help.h'
fi
if test -f 'high.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'high.c'\"
else
echo shar: Extracting \"'high.c'\" \(6388 characters\)
sed "s/^X//" >'high.c' <<'END_OF_FILE'
X/* high.c
X *	contains routines for the maintenance of the high score file.
X */
X#include <stdio.h>
X#include <curses.h>
X#include "defs.h"
X
X#define High_Length (max_hs_count + 5)
X#define High_Width 29
X#define Start_Line 3
X#define Display_High_Time 5
X
Xextern WINDOW *screen;
X
X/* dis_score() displays the current high score file in a
X * window, 'Back_Window' is the window behind the high score
X * display window, 'Back_Window' must be restored once the
X * user has finished with the high score window */
Xdis_score(Back_Window)
X
XWINDOW *Back_Window;
X
X	{
X	FILE *fp;
X	char Name[player_name_len], ch;
X	int score, i, tmp_y, tmp_x;
X	extern int non_stop;
X	WINDOW *High_Window;
X
X/* Back_Window will be NULL in the case where yahtzee is exiting
X * and displaying the high score file as its last action */
X	if (Back_Window != (WINDOW *) 0)
X		{
X		getyx(Back_Window, tmp_y, tmp_x);
X		wmove(Back_Window, 0, 0);
X		wrefresh(Back_Window);
X		}
X
X/* create the high score window */
X	High_Window = newwin(High_Length, High_Width, LINES - High_Length - 1,
X		3);
X	werase(High_Window);
X	BoxUp(High_Window, High_Length, High_Width);
X	wmove(High_Window, 1, 1);
X
X/* open high score file (note HSFILE is defined at compile time, see
X * the makefile) */
X	fp = fopen(HSFILE, "r");
X	if (fp == NULL)
X		waddstr(High_Window, "Cannot access score file.");
X	else
X		{
X		wprintw(High_Window, "Top %d Yahtzee High Scores",
X			max_hs_count);
X		i = Start_Line;
X
X/* output all high scores */
X		while (fscanf(fp, "%d %s\n", &score, Name) != EOF)
X			{
X			wmove(High_Window, i, 1);
X			wprintw(High_Window, "%20s %5d", Name, score);
X			++i;
X			}
X		fclose(fp);
X		}
X	touchwin(High_Window);
X	wrefresh(High_Window);
X	if (Back_Window != (WINDOW *) 0)
X		{
X
X/* if the user specified non-stop play then don't get input */
X		if (non_stop)
X			{
X			wmove(High_Window, 0, 0);
X			wrefresh(High_Window);
X			sleep(Display_High_Time);
X			}
X		else
X			{
X			mvwaddstr(High_Window, High_Length - 2, 1,
X				"--(q)uit--");
X#ifndef SYS5_3
X			wrefresh(High_Window);
X#endif
X			do
X				{
X				ch = wgetch(High_Window);
X				switch (ch)
X					{
X					case Form_Feed : redraw(High_Window);
X				   		break;
X					case '?' : help_out(7, High_Window);
X				   		break;
X					case 'b' : rools(High_Window);
X				   		break;
X					case '!' : shell(High_Window);
X						break;
X					case 'v' : version(High_Window);
X						break;
X#if defined(SYS5) || defined(SYS5_3)
X					case '$' : shwin(High_Window);
X						   break;
X					case 'q' :
X					case ' ' : break;
X					default : flash();
X				  		break;
X#endif
X					}
X				} while (ch != 'q' && ch != ' ');
X			}
X		delwin(High_Window);
X
X/* restore previous window */
X		touchwin(Back_Window);
X		wmove(Back_Window, tmp_y, tmp_x);
X		wrefresh(Back_Window);
X		}
X	}
X
Xextern int machine[max_players];
Xextern char *getenv(), *strcpy(), *strcat();
X
X/* update high score file */
Xupdate_high(player_number, score)
X
Xint player_number, score;
X
X	{
X	FILE *hsf;
X	char player[max_hs_count + 1][player_name_len],
X		tmp_player[player_name_len];
X	int player_score[max_hs_count + 1], own_score,
X		lowest_score = 0;
X	register int hs_count = 0, existing_entries = 0, i, j;
X	char message[150];
X	void file_mess();
X
X/* read contents of high score file (also check to see if it exists) */
X	hsf = fopen(HSFILE, "r");
X	if (hsf == NULL)
X		{
X		sprintf(message, "trying to create: %s", HSFILE);
X		if (strlen(HSFILE) > 79)
X			strcpy(message, "Trying to create high score file.");
X		file_mess(screen, message);
X		}
X	else
X		{
X		while (fscanf(hsf, "%d %s\n", &player_score[hs_count],
X			player[hs_count]) != EOF)
X			++hs_count;
X		fclose(hsf);
X		}
X
X/* there is probably a better way of getting a player name,
X * but we don't want to pester the user for too much info */
X#ifdef BSD
X	strcpy(tmp_player, getenv("USER"));
X#else
X	strcpy(tmp_player, getenv("LOGNAME"));
X#endif
X
X/* make sure that the heuristics get credit for winning a game */
X	if (machine[player_number])
X		strcat(tmp_player, "-machine");
X
X/* determine how many entries the user has in the high score file,
X * and if the user has an entry what the users lowest recorded score is */
X	for (i = 0; i < hs_count; ++i)
X		if (strcmp(player[i], tmp_player) == 0)
X			{
X			own_score = i;
X			++existing_entries;
X			lowest_score = player_score[i];
X			}
X
X	if (existing_entries >= max_entries)
X		{
X		if (lowest_score < score)
X			{
X
X/* if the user already has the max. number of entries in the HS file
X * but the new score is better than a previous score then delete the
X * users worst high score and insert the new score */
X			--hs_count;
X			for (j = own_score; j < hs_count; ++j)
X				{
X				player_score[j] = player_score[j + 1];
X				strcpy(player[j], player[j + 1]);
X				}
X			insert_score(player_score, player, hs_count,
X				tmp_player, score);
X			}
X		}
X	else
X
X/* attempt to insert the score */
X		insert_score(player_score, player, hs_count, tmp_player, score);
X	}
X
Xinsert_score(player_score, player, hs_count, player_name, score)
X
Xint player_score[max_hs_count + 1], hs_count, score;
Xchar *player_name, player[max_hs_count + 1][player_name_len];
X
X	{
X	int j, position = 0;
X	FILE *hsf;
X	void file_mess();
X
X/* determine the users ranking in the HS file */
X	while (position < hs_count && player_score[position] > score)
X		++position;
X
X/* if the user has the a ranking lower than the number of possible
X * entries then don't update file */
X	if (position >= max_hs_count)
X		return(0);
X
X/* make room for the new score */
X	for (j = hs_count; j > position; --j)
X		{
X		strcpy(player[j], player[j - 1]);
X		player_score[j] = player_score[j - 1];
X		}
X
X/* insert the new name and score */
X	player_score[position] = score;
X	strcpy(player[position], player_name);
X	++hs_count;
X
X/* truncate HS file if it exceeds the maximum allowable entries */
X	if (hs_count > max_hs_count)
X		hs_count = max_hs_count;
X
X/* write the new HS file */
X	if ((hsf = fopen(HSFILE, "w")) == NULL)
X		{
X		file_mess(screen, "Cannot write to high score file.");
X		return;
X		}
X	for (j = 0; j < hs_count; ++j)
X		fprintf(hsf, "%d %s\n", player_score[j], player[j]);
X	fclose(hsf);
X	}
X
Xstatic void file_mess(back_window, message)
X
XWINDOW *back_window;
Xchar *message;
X
X	{
X	WINDOW *mess_win;
X	int mess_len = strlen(message) + 3;
X
X	mess_win = newwin(3, mess_len, 11, (COLS - mess_len) / 2);
X	BoxUp(mess_win, 3, mess_len);
X	mvwaddstr(mess_win, 1, 1, message);
X	touchwin(mess_win);
X	wrefresh(mess_win);
X	sleep(3);
X	touchwin(back_window);
X	wrefresh(back_window);
X	delwin(mess_win);
X	}
END_OF_FILE
if test 6388 -ne `wc -c <'high.c'`; then
    echo shar: \"'high.c'\" unpacked with wrong size!
fi
# end of 'high.c'
fi
if test -f 'play_info.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'play_info.c'\"
else
echo shar: Extracting \"'play_info.c'\" \(3888 characters\)
sed "s/^X//" >'play_info.c' <<'END_OF_FILE'
X/* play_info.c
X *	get game configuration information from the user.
X */
X#include "defs.h"
X#include <curses.h>
X#include <stdio.h>
X#include <fcntl.h>
X#include <signal.h>
X
X#define A_Bad_Number -1
X
X/* size of configuration window */
X#define Config_Length 17
X#define Config_Width 29
X
Xextern WINDOW *Config_Win;
Xextern int BadStandout;
X
Xstatic char brand[3][10] = {"Human   ", "Computer"};
X
Xint player_info(machine, Back_Window)
X
Xint machine[max_players];
XWINDOW *Back_Window;
X
X	{
X	int i, cur_player = 0, player_count = 0, tmp_y, tmp_x;
X	char ch;
X	WINDOW *Config_Win;
X
X	getyx(Back_Window, tmp_y, tmp_x);
X	wmove(Back_Window, 0, 0);
X	wrefresh(Back_Window);
X
X/* create configuration window */
X	Config_Win = newwin(Config_Length, Config_Width, 0, 0);
X	werase(Config_Win);
X	BoxUp(Config_Win, Config_Length, Config_Width);
X	touchwin(Config_Win);
X
X/* set all players to machine by default */
X	for (i = 0; i < max_players; ++i)
X		machine[i] = TRUE;
X	if (! BadStandout)
X		wstandout(Config_Win);
X	mvwaddstr(Config_Win, 1, 5, "-- y a h t z e e --");
X	if (! BadStandout)
X		wstandend(Config_Win);
X	mvwaddstr(Config_Win, Config_Length - 2, 1,
X		"For on-line help press '?'");
X	while (player_count < 1 || player_count > max_players)
X		{
X		mvwaddstr(Config_Win, 3, 2, "number of players: ");
X#ifndef SYS5_3
X		wrefresh(Config_Win);
X#endif
X
X/* get the number of players */
X		ch = wgetch(Config_Win);
X		if (ch >= '1' && ch <= Max_Players_Ch)
X			{
X			player_count = ch - '0';
X			waddch(Config_Win, ch);
X			}
X		else
X			{
X			player_count = A_Bad_Number;
X			switch (ch)
X				{
X				case 'b' : rools(Config_Win);
X					   break;
X				case '?' : help_out(6, Config_Win);
X					   break;
X				case 's' : dis_score(Config_Win);
X					   break;
X				case Form_Feed : redraw(Config_Win);
X					   break;
X				case 'q' : yahtzee_exit(0);
X					   break;
X				case '!' : shell(Config_Win);
X					   break;
X				case 'v' : version(Config_Win);
X					   break;
X#if defined(SYS5) || defined(SYS5_3)
X				case '$' : shwin(Config_Win);
X					   break;
X#endif
X
X/* default case is bad input so tell the user the limits */
X				default : mvwprintw(Config_Win, Config_Length -
X						3, 3, "1 < player count < %d",
X						max_players);
X					   wrefresh(Config_Win);
X					   sleep(2);
X					   wmove(Config_Win, Config_Length - 3,
X						3);
X					   waddstr(Config_Win, 
X						"                     ");
X					   wrefresh(Config_Win);
X				}
X			}
X		}
X
X/* determine which players will be human and which will be simulated */
X	for (i = 0; i < player_count; ++i)
X		mvwprintw(Config_Win, i + 5, 3, "%d %s", i, brand[machine[i]]);
X	do
X		{
X		wmove(Config_Win, cur_player + 5, 2);
X#ifndef SYS5_3
X		wrefresh(Config_Win);
X#endif
X		ch = wgetch(Config_Win);
X		switch(ch)
X			{
X
X/* toggle between machine and human */
X			case ' ' : machine[cur_player] = ! machine[cur_player];
X				   mvwprintw(Config_Win, cur_player + 5, 3,
X					"%d %s", cur_player,
X					brand[machine[cur_player]]);
X				   break;
X
X/* move cursor up */
X			case 'k' : --cur_player;
X				   cur_player = wrap(cur_player, 0,
X					player_count - 1);
X				   break;
X
X/* move cursor down */
X			case 'j' : ++cur_player;
X				   cur_player = wrap(cur_player, 0,
X					player_count - 1);
X				   break;
X			case '?' : help_out(0, Config_Win);
X				   break;
X			case 'q' : dis_score((WINDOW *) 0);
X				   yahtzee_exit(0);
X				   break;
X			case 's' : dis_score(Config_Win);
X				   break;
X			case Form_Feed : redraw(Config_Win);
X				   break;
X			case 'b' : rools(Config_Win);
X				   break;
X			case '!' : shell(Config_Win);
X				   break;
X			case 'v' : version(Config_Win);
X				   break;
X#if defined(SYS5) || defined(SYS5_3)
X			case '$' : shwin(Config_Win);
X				   break;
X			case '\n' : break;
X			default : flash();
X				  break;
X#endif
X			}
X		} while (ch != '\n');
X	delwin(Config_Win);
X
X/* restore previous window */
X	touchwin(Back_Window);
X	wmove(Back_Window, tmp_y, tmp_x);
X	wrefresh(Back_Window);
X	return(player_count);
X	}
END_OF_FILE
if test 3888 -ne `wc -c <'play_info.c'`; then
    echo shar: \"'play_info.c'\" unpacked with wrong size!
fi
# end of 'play_info.c'
fi
if test -f 'shwin.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'shwin.c'\"
else
echo shar: Extracting \"'shwin.c'\" \(10074 characters\)
sed "s/^X//" >'shwin.c' <<'END_OF_FILE'
X/* shwin.c
X *	contains a routine to implement a shell window under
X *	System 5 using fairly crude multiplexing.  For performance
X *	reasons there is very heavy use of code in-lining.
X */
X
X#if (defined(SYS5) || defined(SYS5_3)) && ! defined(cyber)
X
X/* How it works:
X *	A child is created and it execs a csh, all terminal IO from the
X *	child uses 3 pipes (stdin, stdout, stderr). The parent process
X *	keeps a check on data coming from these pipes (the childs stdout
X *	and stderr) and data coming from the terminal.  Data read from
X *	the terminal is sent down the childs stdin pipe.
X *	Curses is used to control the window environment (see the code).
X *	The above description implies the parent is 'busy waiting' on
X *	data from the pipes, to avoid this undesirable feature if
X *	the parent receives no terminal input or output from the pipes
X *	it goes to sleep.  If this keeps happening the parent goes
X *	to sleep for longer and longer times (until it hits a maximum
X *	sleep time). As the comments say, the multiplexing is fairly
X *	crude.
X */
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <curses.h>
X#include <signal.h>
X#include <time.h>
X
X#define ERROR_EXIT {perror("yahtzee"); exit(-1);}
X#define WERROR_EXIT {perror("yahtzee"); return(-1);}
X
X/* the maximum sleep time */
X#define MAX_SLEEP 10
X
X/* the rate at which the sleep clock is incremented */
X#define SLEEP_INC 0.01
X
X/* read buffer size */
X#define BUFFER_SIZE 1024
X
X/* column in which the time appears in the top row */
X#define TIME_COL 52
X
X/* macro to read from a file descriptor and write the contents to the
X * given window, if nothing is read the sleep counter is incremented */
X#define READ_WWRITE(infd, outwin) \
X	status = read(infd, buffer, BUFFER_SIZE); \
X	if (status > 0) \
X		{ \
X		buffer[status] = '\0'; \
X		waddstr(outwin, buffer); \
X		wrefresh(outwin); \
X		bdcount = 0.0; \
X		}
X
X/* draw a line across screen at row a */
X#define line_across(a) {for (i = 0; i < COLS; ++i) \
X	mvwaddch(screen, a, i, '-'); }
X
X/* update the ticking clock in the top row of the screen */
X#define UPDATE_TIME { \
X	time(&cur_time); \
X	strncpy(time_buf, ctime(&cur_time), 19); \
X	time_buf[19] = '\0'; \
X	mvwaddstr(screen, 0, TIME_COL, time_buf); \
X	wrefresh(screen); \
X	}
X
Xextern int execl(), fork(), pipe(), close(), fcntl();
Xextern int BadStandout;
Xstatic int child_dead;
Xint shell_window_active = 0;
X
Xshwin(backwin)
X
XWINDOW *backwin;
X
X	{
X	int Pread_Cwrite[2], Pwrite_Cread[2], pid, status, stat_flg, i,
X		Stderr_Pr_Cw[2], buffer_index = 0, tmp_y, tmp_x, tilde = FALSE,
X		clock_toggle = TRUE, old_y, old_x;
X	char buffer[BUFFER_SIZE], ch, in_buf[BUFFER_SIZE], time_buf[30];
X	extern void signal_catch();
X	register unsigned int sleep_now;
X	register float bdcount = 0.0;
X	WINDOW *wstdout, *wstderr, *screen;
X	void (*oldcld)(), (*oldterm)(), (*oldint)(), (*oldquit)(), (*oldpipe)();
X	long cur_time;
X
X
X	getyx(backwin, tmp_y, tmp_x);
X	wmove(backwin, 0, 0);
X	wrefresh(backwin);
X
X/* create the child's output pipe */
X	if (pipe(Pread_Cwrite) < 0)
X		ERROR_EXIT
X
X/* create the child's input pipe */
X	if (pipe(Pwrite_Cread) < 0)
X		ERROR_EXIT
X
X/* create the one-way stderr pipe of the child, WARNING: this pipe is
X * never written to by the parent, programs such as less will not work */
X	if (pipe(Stderr_Pr_Cw) < 0)
X		ERROR_EXIT
X
X/* create child process */
X	if ((pid = fork()) == 0)
X		{
X
X/* direct child stdout to the relevant pipe */
X		close(fileno(stdout)); /* stdout */
X		fcntl(Pread_Cwrite[1], F_DUPFD, fileno(stdout));
X		close(Pread_Cwrite[1]);
X
X/* direct child stdin to the relevant pipe */
X		close(fileno(stdin)); /* stdin */
X		fcntl(Pwrite_Cread[0], F_DUPFD, fileno(stdin));
X		close(Pwrite_Cread[0]);
X
X/* direct child stderr to the relevant pipe */
X		close(fileno(stderr));
X		fcntl(Stderr_Pr_Cw[1], F_DUPFD, fileno(stderr));
X		close(Stderr_Pr_Cw[1]);
X
X/* exec csh */
X		execl("/bin/csh", "csh", "-i", 0);
X		ERROR_EXIT
X		}
X	if (pid == -1)
X		ERROR_EXIT
X	child_dead = FALSE;
X	++shell_window_active;
X
X/* catch signals associated with child death, ignore interrupts */
X	oldcld = signal(SIGCLD, signal_catch);
X	oldterm = signal(SIGTERM, signal_catch);
X	oldint = signal(SIGINT, SIG_IGN);
X	oldquit = signal(SIGQUIT, SIG_IGN);
X	oldpipe = signal(SIGPIPE, signal_catch);
X
X/* close pipe descriptors that will not be used */
X	close(Pread_Cwrite[1]);
X	close(Pwrite_Cread[0]);
X	close(Stderr_Pr_Cw[1]);
X
X/* get status flags for the childs stdout pipe */
X	if ((stat_flg = fcntl(Pread_Cwrite[0], F_GETFL)) == -1)
X		ERROR_EXIT
X
X/* set the flags to that pipe to no-delay on read */
X	if (fcntl(Pread_Cwrite[0], F_SETFL, stat_flg | O_NDELAY) == -1)
X		ERROR_EXIT
X
X/* likewise for stderr */
X	if ((stat_flg = fcntl(Stderr_Pr_Cw[0], F_GETFL)) == -1)
X		ERROR_EXIT
X	if (fcntl(Stderr_Pr_Cw[0], F_SETFL, stat_flg | O_NDELAY) == -1)
X		ERROR_EXIT
X
X/* enable mapping of newlines */
X	nl();
X
X/* create the 'background screen' */
X	screen = newwin(6, COLS, 0, 0);
X	werase(screen);
X
X/* create the stderr window */
X	wstderr = newwin(3, COLS, 2, 0);
X
X/* create the stdout and stdin window */
X	wstdout = newwin(18, COLS, 6, 0);
X
X/* format the background screen */
X	if (! BadStandout)
X		wstandout(screen);
X	line_across(1);
X	line_across(5);
X	wmove(screen, 0, 0);
X	waddstr(screen, "-- y a h t z e e -- ~? for help");
X	if (! BadStandout)
X		wstandend(screen);
X
X/* tick the clock */
X	UPDATE_TIME
X	werase(wstdout);
X
X/* allow insert and delete line escape sequences to be used when
X * scrolling the stdin/stdout window (note: stderr uses a redraw
X * mechanism to scroll) */
X	idlok(wstdout, TRUE);
X
X/* set terminal stdin to no-delay */
X	nodelay(wstdout, TRUE);
X	werase(wstderr);
X	wrefresh(wstdout);
X
X/* tell curses to scroll stdout/stdin and stderr windows in cases
X * where the cursor is at the bottom of a window and a CR is put
X * in the window */
X	scrollok(wstdout, TRUE);
X	scrollok(wstderr, TRUE);
X
X/* iterate until the child dies (note: child_dead is not altered by
X * any code inside its loop, your optimiser might try to be clever
X * and get rid of it, use volatile(!)) */
X	while (! child_dead)
X		{
X
X/* do a no-delay read of the stderr pipe, put any output to the
X * stderr window */
X		READ_WWRITE(Stderr_Pr_Cw[0], wstderr)
X
X/* do a no-delay read of the stdout pipe, put any output to the
X * stdout window */
X		READ_WWRITE(Pread_Cwrite[0], wstdout)
X
X/* do no-delay reads of the terminal until no more input is forthcoming */
X		while ((ch = wgetch(wstdout)) > 0)
X			{
X
X/* the tilde (~) is the escape char to do other things */
X			if (tilde)
X				{
X				tilde = FALSE;
X				switch (ch)
X					{
X
X/* two tildes means send a tilde to the shell */
X					case '~' : in_buf[buffer_index] = ch;
X						   ++buffer_index;
X						   waddch(wstdout, ch);
X						   wrefresh(wstdout);
X						   break;
X
X/* get help */
X					case '?' :
X
X/* get rid of no-delay input */
X						   fcntl(fileno(stdin),
X							F_SETFL, 0);
X						   help_out(8, screen);
X
X/* redraw the relvant screens */
X						   touchwin(wstderr);
X						   wrefresh(wstderr);
X						   touchwin(wstdout);
X						   wrefresh(wstdout);
X
X/* set input to nodelay and continue */
X						   nodelay(wstdout, TRUE);
X						   break;
X
X/* kill the child */
X					case '.' : kill(pid, SIGKILL);
X						   break;
X
X/* send a sigterm to the child */
X					case 'T' : kill(pid, SIGTERM);
X						   break;
X
X/* toggle the clock on or off (preferrably off) */
X					case 'c' : clock_toggle = (clock_toggle
X							? FALSE : TRUE);
X						   break;
X
X/* default: bad escape sequence */
X					default : flash();
X					}
X				}
X			else
X/* must be char for shell */
X				{
X				switch (ch)
X					{
X
X/* BS and DEL will non-destructively remove chars from the input
X * line for the shell */
X					case (char) 8 :
X					case (char) 127 :
X						buffer_index = (buffer_index > 0
X							? (buffer_index - 1) :
X							0);
X						getyx(wstdout, old_y, old_x);
X						if (old_x > 0)
X							wmove(wstdout, old_y,
X								old_x - 1);
X						break;
X
X/* get ready for an escape sequence */
X					case '~' : tilde = TRUE;
X						break;
X
X/* all other chars are for the shell */
X					default : in_buf[buffer_index] = ch;
X						waddch(wstdout, ch);
X						wrefresh(wstdout);
X					  	++buffer_index;
X						break;
X					}
X
X/* only send line to shell when it is complete and terminated with
X * a NL, this implies that programs that set the terminal to raw
X * mode that are run inside the shell will not work correcly */
X				if (ch == '\n')
X					{
X					write(Pwrite_Cread[1], in_buf,
X						buffer_index);
X					buffer_index = 0;
X					}
X
X/* terminal input means reset the sleep counter */
X				bdcount = 0.0;
X				}
X			}
X		sleep_now = bdcount;
X		bdcount += SLEEP_INC;
X
X/* if sufficient time has elapsed since the last read, then slowly
X * put the parent process to sleep */
X		if (sleep_now > 2)
X			{
X			if (sleep_now > MAX_SLEEP)
X				sleep_now = MAX_SLEEP;
X			sleep(sleep_now);
X			if (clock_toggle)
X				{
X
X/* display the clock if so required */
X				UPDATE_TIME
X				wrefresh(wstdout);
X				}
X			}
X		}
X
X/* set terminal read to normal mode (not no-delay), I'm not sure
X * how to achieve this, the nodelay() call doesn't work as I would
X * expect on System 5.3 and I don't have any docs for curses to see
X * how it should be used */
X/*	nodelay(wstdout, FALSE);     this doesn't work */
X	fcntl(fileno(stdin), F_SETFL, 0); /* this does */
X
X/* close the pipe file descriptors */
X	close(Pread_Cwrite[0]);
X	close(Pwrite_Cread[1]);
X	close(Stderr_Pr_Cw[0]);
X
X/* cleanup the shell windows */
X	delwin(screen);
X	delwin(wstderr);
X	delwin(wstdout);
X	touchwin(backwin);
X
X/* restore the previous window */
X	wmove(backwin, tmp_y, tmp_x);
X	wrefresh(backwin);
X
X/* child_dead must be left false so that any recursive calls to
X * this function will not make earlier calls fail */
X	child_dead = FALSE;
X	--shell_window_active;
X
X/* reset the signal handlers */
X	signal(SIGCLD, oldcld);
X	signal(SIGTERM, oldterm);
X	signal(SIGPIPE, oldpipe);
X	signal(SIGINT, oldint);
X	signal(SIGQUIT, oldquit);
X	return(0);
X	}
X
X/* this is called when the shell dies, it sets the child_dead flag */
Xvoid signal_catch()
X
X	{
X	signal(SIGCLD, SIG_IGN);
X	signal(SIGPIPE, SIG_IGN);
X	signal(SIGTERM, SIG_IGN);
X	child_dead = TRUE;
X	}
X
X#else
Xshwin() {}
X#endif
END_OF_FILE
if test 10074 -ne `wc -c <'shwin.c'`; then
    echo shar: \"'shwin.c'\" unpacked with wrong size!
fi
# end of 'shwin.c'
fi
if test -f 'yz.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'yz.c'\"
else
echo shar: Extracting \"'yz.c'\" \(6191 characters\)
sed "s/^X//" >'yz.c' <<'END_OF_FILE'
X/* yz.c
X *	main function and declaration of the important global
X *	data structures.
X */
X#include <stdio.h>
X#include <curses.h>
X#include <signal.h>
X#include "defs.h"
X
X/* sleep period at end of game if no delay flag is given to yahtzee */
X#define Non_Stop_Wait 10
X#define TicToc fprintf(stderr, "."); fflush(stderr);
X
X/* y and x coordinates for the display of the 5 dice */
Xint diey[Five_Dice] = {0, 0, 0, 0, 0}, diex[Five_Dice] = {0, 12, 24, 36, 48};
X
X/* scoreboard stores scores for all players for each category, machine
X * is a boolean to determine if the given player is a human or
X * computer simulation */
Xint scoreboard[max_players][max_marks], machine[max_players];
Xint subtotals[max_players];
X
X/* used to form category availability list for all players */
Xint available[13], avail_count;
XWINDOW *screen;
X
X/* users that don't like the default curses standout mode and don't
X * want to change it themselves can avoid it my setting this boolean
X * at startup */
Xint BadStandout = FALSE;
X
X/* boolean for non-stop play, set at startup */
Xint non_stop = FALSE;
X
X/* me */
X#ifndef BSD
Xstatic char id[] = "@(#)yz.c 1.2	Yahtzee -  Stacey Campbell";
X#endif
X
X#ifdef BSD
Xextern long random();
Xextern void srandom();
X#else
Xextern long lrand48();
Xextern void srand48();
X#endif
Xextern byebye();
X
Xmain(argc, argv)
X
Xint argc;
Xchar *argv[];
X
X	{
X	int mark, player, player_count, round, i, dice[Five_Dice],
X		hold[Five_Dice], totals[max_players], best_player;
X	extern long time();
X	extern int old_dice[Five_Dice];
X	char ch = ' ', arg[50];
X
X/* boot the seed for the random number generator */
X#ifdef BSD
X	srandom((int) time(0));
X#else
X	srand48(time((long *) 0));
X#endif
X	TicToc
X
X/* initialise curses */
X	initscr();
X	TicToc
X
X/* create the game window */
X	screen = newwin(0, 0, 0, 0);
X	TicToc
X
X/* process arguments */
X	for (i = 1; i < argc; ++i)
X		{
X		strcpy(arg, argv[i]);
X
X/* flag for non-stop play */
X		if (strcmp("-N", arg) == 0)
X			non_stop = TRUE;
X
X/* flag to avoid using standout mode of terminal */
X		else if (strcmp("-d", arg) == 0)
X			BadStandout = TRUE;
X
X/* display score and exit */
X		else if (strcmp("-s", arg) == 0)
X			yahtzee_exit(dis_score((WINDOW *) 0));
X
X/* put options on stdout then exit */
X		else if (strcmp("-h", arg) == 0)
X			{
X			option_message(argv[0]);
X			yahtzee_exit(0);
X			}
X		else
X			{
X			fprintf(stderr, "Unknown argument: %s\n", arg);
X			fprintf(stderr, "Try: %s -h\n", argv[0]);
X			sleep(4);
X			}
X		}
X
X/* trap signals for clean exit */
X	signal(SIGINT, byebye);
X	signal(SIGQUIT, byebye);
X	signal(SIGTERM, byebye);
X	TicToc
X
X/* set crmode and noecho for the terminal */
X	crmode();
X	noecho();
X
X/* determine player count and which players will be simulated */
X	player_count = player_info(machine, screen);
X
X/* loop until user quits */
X	do
X		{
X
X/* setup the play screen */
X		werase(screen);
X		dis_side();
X		for (i = 0; i < Five_Dice; ++i)
X			{
X			old_dice[i] = 0;
X			hold[i] = FALSE;
X			}
X
X/* initialise dice to anything */
X		roll_dice(dice, hold);
X		dis_dice(dice, hold);
X		if (! BadStandout)
X			wstandout(screen);
X
X/* initialise the scoreboard */
X		for (player = 0; player < player_count; ++player)
X			{
X			subtotals[player] = 0;
X			for (mark = 0; mark < max_marks; ++mark)
X				scoreboard[player][mark] = category_available;
X			mvwprintw(screen, 6, player * 10 + 27, "%d", player);
X			}
X		if (! BadStandout)
X			wstandend(screen);
X		mvwaddstr(screen, 2, 59, "-- y a h t z e e --");
X		wmove(screen, 3, 68);
X		wrefresh(screen);
X
X/* start the game */
X		for (round = 0; round < 13; ++round)
X			for (player = 0; player < player_count; ++player)
X				{
X
X/* player is human then form availability list */
X				if (! machine[player])
X					human_availability(player);
X
X/* stage 1: roll dice then get move */
X				roll_dice(dice, hold);
X				get_move(player, dice, hold);
X				if (machine[player])
X					sleep(4);
X
X/* stage 2: if all dice have not been held then do it again */
X				if (! all_held(hold))
X					{
X					roll_dice(dice, hold);
X					get_move(player, dice, hold);
X					if (machine[player])
X						sleep(4);
X					roll_dice(dice, hold);
X					}
X
X/* display the dice */
X				if (BadStandout)
X					dis_dice(dice, hold);
X				for (i = 0; i < Five_Dice; ++i)
X					hold[i] = FALSE;
X				if (! BadStandout)
X					dis_dice(dice, hold);
X
X/* get selection of best category */
X				if (machine[player])
X					mark = computer_select(player, dice,
X						available, avail_count);
X				else
X					mark = human_select(player, dice);
X
X/* update the score board (not the HS board!) */
X				update_score(player, mark, dice);
X
X/* have a little nap if a computer simulation */
X				if (machine[player])
X					sleep(4);
X				}
X
X/* determine who won */
X		best_player = finish(totals, player_count);
X		wrefresh(screen);
X
X/* attempt to put the best players score in the HS file */
X		update_high(best_player, totals[best_player]);
X		if (! non_stop)
X			{
X
X/* determine if user wishes to continue */
X			mvwaddstr(screen, 5, 0,
X				"--(q)uit, (c)ontinue, (r)econfigure--");
X#ifndef SYS5_3
X			wrefresh(screen);
X#endif
X			do
X				{
X				ch = wgetch(screen);
X				switch (ch)
X					{
X
X/* get help */
X					case '?' : help_out(1, screen);
X						   break;
X
X/* display the current HS file */
X					case 's' : dis_score(screen);
X						   break;
X
X/* redraw the current window */
X					case Form_Feed : redraw(screen);
X						   break;
X
X/* display the rule book */
X					case 'b' : rools(screen);
X						   break;
X
X/* reconfigure the players */
X					case 'r' : player_count =
X							player_info(machine,
X							screen);
X						  break;
X
X/* get a shell */
X					case '!' : shell(screen);
X						   break;
X					case 'v' : version(screen);
X						   break;
X#if defined(SYS5) || defined(SYS5_3)
X
X/* get a shell window */
X					case '$' : shwin(screen);
X						   break;
X					case ' ' :
X					case 'q' :
X					case 'c' : break;
X					default : flash();
X						  break;
X#endif
X					}
X				} while (ch != ' ' && ch != 'q' && ch != 'c');
X			}
X		else
X			{
X			dis_score(screen);
X			sleep(Non_Stop_Wait);
X			}
X		} while (ch != 'q');
X	dis_score((WINDOW *) 0);
X	yahtzee_exit(0);
X	}
X
X/* return true if all dice are held */
Xint all_held(hold)
X
Xint hold[Five_Dice];
X
X	{
X	register int i;
X
X	for (i = 0; i < Five_Dice; ++i)
X		if (! hold[i])
X			return(FALSE);
X	return(TRUE);
X	}
END_OF_FILE
if test 6191 -ne `wc -c <'yz.c'`; then
    echo shar: \"'yz.c'\" unpacked with wrong size!
fi
# end of 'yz.c'
fi
echo shar: End of archive 1 \(of 2\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0