PD Terminfo/Curses (part 11 of 11)

sources at genrad.UUCP sources at genrad.UUCP
Sat Dec 22 08:41:21 AEST 1984


This is part of a distribution of a public domain version of terminfo/curses
It is a rather large distribution, so I have broken it up into 11 modules
(each less than 64K long.) Each shar format module should end with the line
"exit".  This code is completely public domain, originally written by Pavel
Curtis of Cornell University.  This version has some small improvements and
bug fixes.

This unit contains:
	The demo program "mille".

----------------- cut here ----------------
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
echo 'Making directory "=test"'
mkdir =test
echo 'Making directory "=test/=mille"'
mkdir =test/=mille
echo 'x - =test/=mille/Makefile'
sed 's/^X//' <<'//go.sysin dd *' >=test/=mille/Makefile
HEADERS=mille.h
CFILES=	comp.c end.c extern.c init.c mille.c misc.c move.c print.c \
	roll.c save.c types.c varpush.c
OBJS=	comp.o end.o extern.o init.o mille.o misc.o move.o print.o \
	roll.o save.o types.o varpush.o
POBJS=	comp.po end.po extern.po init.po mille.po misc.po move.po \
	roll.po print.po save.po types.po varpush.po
LIBS=	../../=src/libpcurses.a
CFLAGS=	-O -DSTANDOUT -I../../=src
X.SUFFIXES: .po .i

X.c.po:
	rm -f x.c ; ln $*.c x.c
	${CC} ${CFLAGS} -pg -c x.c
	mv x.o $*.po

X.c.i:
	${CC} ${CFLAGS} -P $*.c

mille: ${OBJS} 
	${CC} ${CFLAGS} -n -o mille ${OBJS} ${LIBS}

install: mille
	cp mille /usr/games

pmb: ${POBJS}
	${CC} ${CFLAGS} -n -pg -o pmb ${POBJS} $(LIBS)

mille.po: mille.c
	rm -f x.c ; ln mille.c x.c
	${CC} ${CFLAGS} -DPROF -p -c x.c
	mv x.o mille.po

table: table.o extern.o
	${CC} ${CFLAGS} -i -o table table.o extern.o

readdump: readdump.o extern.o varpush.o
	${CC} ${CFLAGS} -i -o readdump readdump.o extern.o varpush.o

ctags:
	ctags ${HEADERS} ${CFILES}
	ed - tags < :ctfix
	sort tags -o tags

lint:
	lint -hxb ${CFILES} > lint.out

mille.ar:
	ar ruv mille.ar Makefile tags ${HEADERS} ${CFILES}

tar:
	tar crvf mille.tar Makefile tags :ctfix ${HEADERS} ${CFILES}

lpr:
	pr Makefile ${HEADERS} ${CFILES} tags | lpr ; lpq
//go.sysin dd *
echo 'x - =test/=mille/comp.c'
sed 's/^X//' <<'//go.sysin dd *' >=test/=mille/comp.c
# include	"mille.h"

# define	V_VALUABLE	40

calcmove() {

	reg CARD	card;
	reg int		*value;
	reg PLAY	*pp, *op;
	reg bool	foundend, cango, canstop, foundlow;
	reg unsgn int	i, count200, badcount, nummin, nummax, diff;
	reg int		curmin, curmax;
	reg CARD	safe, oppos;
	int		valbuf[HAND_SZ], count[NUM_CARDS];
	bool		playit[HAND_SZ];

	wmove(Score, ERR_Y, ERR_X);	/* get rid of error messages	*/
	wclrtoeol(Score);
	pp = &Player[COMP];
	op = &Player[PLAYER];
	safe = 0;
	cango = 0;
	canstop = FALSE;
	foundend = FALSE;
	for (i = 0; i < NUM_CARDS; i++)
		count[i] = 0;
	for (i = 0; i < HAND_SZ; i++) {
		card = pp->hand[i];
		switch (card) {
		  case C_STOP:	case C_CRASH:
		  case C_FLAT:	case C_EMPTY:
			if (playit[i] = canplay(pp, op, card))
				canstop = TRUE;
			goto norm;
		  case C_LIMIT:
			if ((playit[i] = canplay(pp, op, card))
			    && Numseen[C_25] == Numcards[C_25]
			    && Numseen[C_50] == Numcards[C_50])
				canstop = TRUE;
			goto norm;
		  case C_25:	case C_50:	case C_75:
		  case C_100:	case C_200:
			if ((playit[i] = canplay(pp, op, card))
			    && pp->mileage + Value[card] == End)
				foundend = TRUE;
			goto norm;
		  default:
			playit[i] = canplay(pp, op, card);
norm:
			if (playit[i])
				++cango;
			break;
		  case C_GAS_SAFE:	case C_DRIVE_SAFE:
		  case C_SPARE_SAFE:	case C_RIGHT_WAY:
			if (pp->battle == opposite(card)
			   || (pp->speed == C_LIMIT && card == C_RIGHT_WAY)) {
				Movetype = M_PLAY;
				Card_no = i;
				return;
			}
			++safe;
			playit[i] = TRUE;
			break;
		}
		++count[card];
	}
	if (pp->hand[0] == C_INIT && Topcard > Deck) {
		Movetype = M_DRAW;
		return;
	}
	if (Debug)
		fprintf(outf, "CALCMOVE: cango = %d, canstop = %d, safe = %d\n", cango, canstop, safe);
	if (foundend)
		foundend = !check_ext(TRUE);
	for (i = 0; safe && i < HAND_SZ; i++) {
		if (issafety(pp->hand[i])) {
			if (onecard(op) || (foundend && cango && !canstop)) {
				if (Debug)
					fprintf(outf, "CALCMOVE: onecard(op) = %d, foundend = %d\n", onecard(op), foundend);
playsafe:
				Movetype = M_PLAY;
				Card_no = i;
				return;
			}
			oppos = opposite(pp->hand[i]);
			if (Numseen[oppos] == Numcards[oppos])
				goto playsafe;
			else if (!cango
			    && (op->can_go || !pp->can_go || Topcard < Deck)) {
				card = (Topcard - Deck) - roll(1, 10);
				if ((!pp->mileage) != (!op->mileage))
					card -= 7;
				if (Debug)
					fprintf(outf, "CALCMOVE: card = %d, DECK_SZ / 4 = %d\n", card, DECK_SZ / 4);
				if (card < DECK_SZ / 4)
					goto playsafe;
			}
			safe--;
			playit[i] = cango;
		}
	}
	if (!pp->can_go && !isrepair(pp->battle))
		Numneed[opposite(pp->battle)]++;
redoit:
	foundlow = (cango || count[C_END_LIMIT] != 0
			  || Numseen[C_LIMIT] == Numcards[C_LIMIT]
			  || pp->safety[S_RIGHT_WAY] != S_UNKNOWN);
	foundend = FALSE;
	count200 = pp->nummiles[C_200];
	badcount = 0;
	curmax = -1;
	curmin = 101;
	nummin = -1;
	nummax = -1;
	value = valbuf;
	for (i = 0; i < HAND_SZ; i++) {
		card = pp->hand[i];
		if (issafety(card) || playit[i] == (cango != 0)) {
			if (Debug)
				fprintf(outf, "CALCMOVE: switch(\"%s\")\n", C_name[card]);
			switch (card) {
			  case C_25:	case C_50:
				diff = End - pp->mileage;
				/* avoid getting too close */
				if (Topcard > Deck && cango && diff <= 100
				    && diff / Value[card] > count[card]
				    && (card == C_25 || diff % 50 == 0)) {
					if (card == C_50 && diff - 50 == 25
					    && count[C_25] > 0)
						goto okay;
					*value = 0;
					if (--cango <= 0)
						goto redoit;
					break;
				}
okay:
				*value = (Value[card] >> 3);
				if (pp->speed == C_LIMIT)
					++*value;
				else
					--*value;
				if (!foundlow
				   && (card == C_50 || count[C_50] == 0)) {
					*value = (pp->mileage ? 10 : 20);
					foundlow = TRUE;
				}
				goto miles;
			  case C_200:
				if (++count200 > 2) {
					*value = 0;
					break;
				}
			  case C_75:	case C_100:
				*value = (Value[card] >> 3);
				if (pp->speed == C_LIMIT)
					--*value;
				else
					++*value;
miles:
				if (pp->mileage + Value[card] > End)
					*value = (End == 700 ? card : 0);
				else if (pp->mileage + Value[card] == End) {
					*value = (foundend ? card : V_VALUABLE);
					foundend = TRUE;
				}
				break;
			  case C_END_LIMIT:
				if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN)
					*value = (pp->safety[S_RIGHT_WAY] == S_PLAYED ? -1 : 1);
				else if (pp->speed == C_LIMIT && End - pp->mileage <= 50)
					*value = 1;
				else if (pp->speed == C_LIMIT
				    || Numseen[C_LIMIT] != Numcards[C_LIMIT]) {
					safe = S_RIGHT_WAY;
					oppos = C_LIMIT;
					goto repair;
				}
				else {
					*value = 0;
					--count[C_END_LIMIT];
				}
				break;
			  case C_REPAIRS:	case C_SPARE:	case C_GAS:
				safe = safety(card) - S_CONV;
				oppos = opposite(card);
				if (pp->safety[safe] != S_UNKNOWN)
					*value = (pp->safety[safe] == S_PLAYED ? -1 : 1);
				else if (pp->battle != oppos
				    && (Numseen[oppos] == Numcards[oppos] || Numseen[oppos] + count[card] > Numcards[oppos])) {
					*value = 0;
					--count[card];
				}
				else {
repair:
					*value = Numcards[oppos] * 6;
					*value += (Numseen[card] - Numseen[oppos]);
					if (!cango)
					    *value /= (count[card]*count[card]);
					count[card]--;
				}
				break;
			  case C_GO:
				if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN)
					*value = (pp->safety[S_RIGHT_WAY] == S_PLAYED ? -1 : 2);
				else if (pp->can_go
				 && Numgos + count[C_GO] == Numneed[C_GO]) {
					*value = 0;
					--count[C_GO];
				}
				else {
					*value = Numneed[C_GO] * 3;
					*value += (Numseen[C_GO] - Numgos);
					*value /= (count[C_GO] * count[C_GO]);
					count[C_GO]--;
				}
				break;
			  case C_LIMIT:
				if (op->mileage + 50 >= End) {
					*value = (End == 700 && !cango);
					break;
				}
				if (canstop || (cango && !op->can_go))
					*value = 1;
				else {
					*value = (pp->safety[S_RIGHT_WAY] != S_UNKNOWN ? 2 : 3);
					safe = S_RIGHT_WAY;
					oppos = C_END_LIMIT;
					goto normbad;
				}
				break;
			  case C_CRASH:	case C_EMPTY:	case C_FLAT:
				safe = safety(card) - S_CONV;
				oppos = opposite(card);
				*value = (pp->safety[safe]!=S_UNKNOWN ? 3 : 4);
normbad:
				if (op->safety[safe] == S_PLAYED)
					*value = -1;
				else {
				    *value *= (Numneed[oppos] + Numseen[oppos] + 2);
				    if (!pp->mileage || foundend || onecard(op))
					*value += 5;
				    if (op->mileage == 0 || onecard(op))
					*value += 5;
				    if (op->speed == C_LIMIT)
					*value -= 3;
				    if (cango && pp->safety[safe] != S_UNKNOWN)
					*value += 3;
				    if (!cango)
					*value /= ++badcount;
				}
				break;
			  case C_STOP:
				if (op->safety[S_RIGHT_WAY] == S_PLAYED)
					*value = -1;
				else {
				    *value = (pp->safety[S_RIGHT_WAY] != S_UNKNOWN ? 3 : 4);
				    *value *= (Numcards[C_STOP] + Numseen[C_GO]);
				    if (!pp->mileage || foundend || onecard(op))
					*value += 5;
				    if (!cango)
					*value /= ++badcount;
				    if (op->mileage == 0)
					*value += 5;
				    if ((card == C_LIMIT
				      && op->speed == C_LIMIT) || (!op->can_go))
					*value -= 5;
				    if (cango && pp->safety[S_RIGHT_WAY] != S_UNKNOWN)
					*value += 5;
				}
				break;
			  case C_GAS_SAFE:	case C_DRIVE_SAFE:
			  case C_SPARE_SAFE:	case C_RIGHT_WAY:
				*value = cango ? 0 : 101;
				break;
			  case C_INIT:
				*value = 0;
			}
		}
		else
			*value = cango ? 0 : 101;
		if (card != C_INIT) {
			if (*value >= curmax) {
				nummax = i;
				curmax = *value;
			}
			if (*value <= curmin) {
				nummin = i;
				curmin = *value;
			}
		}
		if (Debug)
			mvprintw(i+6,2,"%3d %-14s",*value,C_name[pp->hand[i]]);
		value++;
	}
	if (!pp->can_go && !isrepair(pp->battle))
		Numneed[opposite(pp->battle)]++;
	if (cango) {
		mvaddstr(MOVE_Y + 1, MOVE_X, "PLAY\n");
		if (Debug)
			getmove();
		if (!Debug || Movetype == M_DRAW) {
			Movetype = M_PLAY;
			Card_no = nummax;
		}
	}
	else {
		mvaddstr(MOVE_Y + 1, MOVE_X, "DISCARD\n");
		if (Debug)
			getmove();
		if (!Debug || Movetype == M_DRAW) {
			Movetype = M_DISCARD;
			Card_no = nummin;
		}
	}
	mvprintw(MOVE_Y + 2, MOVE_X, "%16s", C_name[pp->hand[Card_no]]);
}

onecard(pp)
reg PLAY	*pp; {

	reg CARD	bat, spd, card;

	bat = pp->battle;
	spd = pp->speed;
	card = -1;
	if (pp->can_go || ((isrepair(bat) || bat == C_STOP
	    || spd == C_LIMIT) && Numseen[S_RIGHT_WAY] != 0)
	    || Numseen[safety(bat)] != 0)
		switch (End - pp->mileage) {
		  case 200:
			if (pp->nummiles[C_200] == 2)
				return FALSE;
			card = C_200;
		  case 100:
		  case 75:
			if (card == -1)
				card = (End - pp->mileage == 75 ? C_75 : C_100);
			if (spd == C_LIMIT)
				return Numseen[S_RIGHT_WAY] == 0;
		  case 50:
		  case 25:
			if (card == -1)
				card = (End - pp->mileage == 25 ? C_25 : C_50);
			return Numseen[card] != Numcards[card];
		}
	return FALSE;
}

canplay(pp, op, card)
reg PLAY	*pp, *op;
reg CARD	card; {

	switch (card) {
	  case C_200:
		if (pp->nummiles[C_200] == 2)
			break;
	  case C_75:	case C_100:
		if (pp->speed == C_LIMIT)
			break;
	  case C_50:
		if (pp->mileage + Value[card] > End)
			break;
	  case C_25:
		if (pp->can_go)
			return TRUE;
		break;
	  case C_EMPTY:	case C_FLAT:	case C_CRASH:
	  case C_STOP:
		if (op->can_go && op->safety[safety(card) - S_CONV] != S_PLAYED)
			return TRUE;
		break;
	  case C_LIMIT:
		if (op->speed != C_LIMIT && op->safety[S_RIGHT_WAY] != S_PLAYED
		    && op->mileage + 50 < End)
			return TRUE;
		break;
	  case C_GAS:	case C_SPARE:	case C_REPAIRS:
		if (pp->battle == opposite(card))
			return TRUE;
		break;
	  case C_GO:
		if (!pp->can_go
		    && (isrepair(pp->battle) || pp->battle == C_STOP))
			return TRUE;
		break;
	  case C_END_LIMIT:
		if (pp->speed == C_LIMIT)
			return TRUE;
	}
	return FALSE;
}
//go.sysin dd *
echo 'x - =test/=mille/end.c'
sed 's/^X//' <<'//go.sysin dd *' >=test/=mille/end.c
# include	"mille.h"

X/*
 *	print out the score as if it was final, and add the totals for
 * the end-of-games points to the user who deserves it (if any).
 */
finalscore(pp)
reg PLAY	*pp; {

	reg int		temp, tot, num;

	num = pp - Player;
	temp = num * 6 + 21 + 3;
	for (tot = 5; tot <= 9; tot++)
		mvaddch(tot, temp, '0');
	if (pp->mileage == End) {
		temp -= 2;
		mvaddstr(5, temp, "40");
		tot = SC_TRIP;
		if (pp->nummiles[C_200] == 0) {
			mvaddstr(6, temp, "30");
			tot = SC_TRIP + SC_SAFE;
		}
		if (Topcard <= Deck) {
			mvaddstr(7, temp, "30");
			tot += SC_DELAY;
		}
		if (End == 1000) {
			mvaddstr(8, temp, "20");
			tot += SC_EXTENSION;
		}
		if (Player[other(num)].mileage == 0) {
			mvaddstr(9, temp, "50");
			tot += SC_SHUT_OUT;
		}
		pp->total += tot;
		pp->hand_tot += tot;
	}
}

# ifdef EXTRAP
static int	Last_tot[2];	/* last tot used for extrapolate	*/

X/*
 *	print out the score as if it was final, and add the totals for
 * the end-of-games points to the user who deserves it (if any).
 */
extrapolate(pp)
reg PLAY	*pp; {

	reg int		x, num, tot, count;

	num = pp - Player;
	tot += SC_TRIP + SC_DELAY + SC_EXT;
	x = num * 6 + 21 + 3;
	for (tot = 5; tot <= 9; tot++)
		mvaddch(tot, x, '0');
	x -= 2;
	pp = &Player[other(num)];
	for (count = 0, tot = 0; tot < NUM_SAFE; tot++)
		if (pp->safety[tot] != S_PLAYED)
			count += SC_SAFE;
	mvprintw(3, x, "%3d", count);
	tot += count;
	if (count == 400) {
		mvaddstr(4, x, "30");
		tot += SC_ALL_SAFE;
	}
	pp = &Player[num];
	for (count = 0, tot = 0; tot < NUM_SAFE; tot++)
		if (pp->safety[tot] != S_PLAYED)
			count += SC_COUP / 10;
	mvprintw(4, x - 1, "%3d", count);
	tot += count;
	tot += 1000 - pp->mileage;
	mvaddstr(5, x, "40");
	mvaddstr(7, x, "30");
	mvaddstr(8, x, "20");
	if (pp->nummiles[C_200] == 0) {
		mvaddstr(6, x, "30");
		tot = SC_TRIP + SC_SAFE;
	}
	if (Player[other(num)].mileage == 0) {
		mvaddstr(9, x, "50");
		tot += SC_SHUT_OUT;
	}
	pp->total += tot;
	pp->hand_tot += tot;
	Last_tot[num] = tot;
}

undoex() {

	reg PLAY	*pp;
	reg int		i;

	i = 0;
	for (pp = Player; pp < &Player[2]; pp++) {
		pp->total -= Last_tot[i];
		pp->hand_tot -= Last_tot[i++];
	}
}
# endif
//go.sysin dd *
echo 'x - =test/=mille/extern.c'
sed 's/^X//' <<'//go.sysin dd *' >=test/=mille/extern.c
# include	"mille.h"

bool	Debug,			/* set if debugging code on		*/
	Finished,		/* set if current hand is finished	*/
	Next,			/* set if changing players		*/
	On_exit,		/* set if game saved on exiting		*/
	Order,			/* set if hand should be sorted		*/
	Saved;			/* set if game just saved		*/

char	*C_fmt = "%-18.18s",	/* format for printing cards		*/
	*Fromfile = NULL,	/* startup file for game		*/
	Initstr[100],		/* initial string for error field	*/
	*_cn[NUM_CARDS] = {	/* Card name buffer			*/
		"",
		"25",
		"50",
		"75",
		"100",
		"200",
		"Out of Gas",
		"Flat Tire",
		"Accident",
		"Stop",
		"Speed Limit", 
		"Gasoline",
		"Spare Tire",
		"Repairs",
		"Go",
		"End of Limit",
		"Extra Tank",
		"Puncture Proof",
		"Driving Ace",
		"Right of Way"
	},
	**C_name = &_cn[1];	/* Card names				*/

int	Card_no,		/* Card number for current move		*/
	End,			/* End value for current hand		*/
	Handstart = COMP,	/* Player who starts hand		*/
	Movetype,		/* Current move type			*/
	Play,			/* Current player			*/
	Numgos,			/* Number of Go cards used by computer	*/
	Window = W_SMALL,	/* Current window wanted		*/
	Numseen[NUM_CARDS],	/* Number of cards seen in current hand	*/
	Value[NUM_MILES] = {	/* Value of mileage cards		*/
		25, 50, 75, 100, 200
	},
	Numcards[NUM_CARDS] = {	/* Number of cards in deck		*/
		10,	/* C_25 */
		10,	/* C_50 */
		10,	/* C_75 */
		12,	/* C_100 */
		4,	/* C_200 */
		2,	/* C_EMPTY */
		2,	/* C_FLAT */
		2,	/* C_CRASH */
		4,	/* C_STOP */
		3,	/* C_LIMIT */
		6,	/* C_GAS */
		6,	/* C_SPARE */
		6,	/* C_REPAIRS */
		14,	/* C_GO */
		6,	/* C_END_LIMIT */
		1,	/* C_GAS_SAFE */
		1,	/* C_SPARE_SAFE */
		1,	/* C_DRIVE_SAFE */
		1,	/* C_RIGHT_WAY */
		0	/* C_INIT */
	};
	Numneed[NUM_CARDS] = {	/* number of cards needed per hand	*/
		0,	/* C_25 */
		0,	/* C_50 */
		0,	/* C_75 */
		0,	/* C_100 */
		0,	/* C_200 */
		2,	/* C_EMPTY */
		2,	/* C_FLAT */
		2,	/* C_CRASH */
		4,	/* C_STOP */
		3,	/* C_LIMIT */
		2,	/* C_GAS */
		2,	/* C_SPARE */
		2,	/* C_REPAIRS */
		10,	/* C_GO */
		3,	/* C_END_LIMIT */
		1,	/* C_GAS_SAFE */
		1,	/* C_SPARE_SAFE */
		1,	/* C_DRIVE_SAFE */
		1,	/* C_RIGHT_WAY */
		0	/* C_INIT */
	};

CARD	Discard,		/* Top of discard pile			*/
	*Topcard,		/* Pointer to next card to be picked	*/
	Opposite[NUM_CARDS] = {	/* Opposites of each card		*/
		C_25, C_50, C_75, C_100, C_200, C_GAS, C_SPARE,
		C_REPAIRS, C_GO, C_END_LIMIT, C_EMPTY, C_FLAT, C_CRASH,
		C_STOP, C_LIMIT, C_EMPTY, C_FLAT, C_CRASH, C_STOP, C_INIT
	},
	Deck[DECK_SZ] = {	/* Current deck				*/
		C_25, C_25, C_25, C_25, C_25, C_25, C_25, C_25, C_25, C_25,
		C_50, C_50, C_50, C_50, C_50, C_50, C_50, C_50, C_50, C_50,
		C_75, C_75, C_75, C_75, C_75, C_75, C_75, C_75, C_75, C_75,
		C_100, C_100, C_100, C_100, C_100, C_100, C_100, C_100, C_100,
		C_100, C_100, C_100,
		C_200, C_200, C_200, C_200,
		C_EMPTY, C_EMPTY,
		C_FLAT, C_FLAT,
		C_CRASH, C_CRASH,
		C_STOP, C_STOP, C_STOP, C_STOP,
		C_LIMIT, C_LIMIT, C_LIMIT,
		C_GAS, C_GAS, C_GAS, C_GAS, C_GAS, C_GAS,
		C_SPARE, C_SPARE, C_SPARE, C_SPARE, C_SPARE, C_SPARE,
		C_REPAIRS, C_REPAIRS, C_REPAIRS, C_REPAIRS, C_REPAIRS,
			C_REPAIRS,
		C_END_LIMIT, C_END_LIMIT, C_END_LIMIT, C_END_LIMIT, C_END_LIMIT,
			C_END_LIMIT,
		C_GO, C_GO, C_GO, C_GO, C_GO, C_GO, C_GO, C_GO, C_GO, C_GO,
			C_GO, C_GO, C_GO, C_GO,
		C_GAS_SAFE, C_SPARE_SAFE, C_DRIVE_SAFE, C_RIGHT_WAY
	};

XFILE	*outf;

PLAY	Player[2];		/* Player descriptions			*/

WINDOW	*Board,			/* Playing field screen			*/
	*Miles,			/* Mileage screen			*/
	*Score;			/* Score screen				*/
//go.sysin dd *
echo 'x - =test/=mille/init.c'
sed 's/^X//' <<'//go.sysin dd *' >=test/=mille/init.c
# include	"mille.h"

init() {

	reg PLAY	*pp;
	reg int		i, j;
	reg CARD	card;

	for (j = 0; j < C_RIGHT_WAY; j++)
		Numseen[j] = 0;
	Numgos = 0;

	for (i = 0; i < 2; i++) {
		pp = &Player[i];
		pp->hand[0] = C_INIT;
		for (j = 0; j < NUM_SAFE; j++) {
			pp->safety[j] = S_UNKNOWN;
			pp->coups[j] = FALSE;
		}
		for (j = 1; j < HAND_SZ; j++) {
			pp->hand[j] = *--Topcard;
			if (i == COMP) {
				account(card = *Topcard);
				if (issafety(card))
					pp->safety[card - S_CONV] = S_IN_HAND;
			}
		}
		pp->mileage = 0;
		pp->hand_tot = 0;
		pp->safescore = 0;
		pp->coupscore = 0;
		pp->can_go = FALSE;
		pp->speed = C_INIT;
		pp->battle = C_INIT;
		pp->new_speed = FALSE;
		pp->new_battle = FALSE;
		for (j = 0; j < NUM_MILES; j++)
			pp->nummiles[j] = 0;
	}
	if (Order)
		sort(Player[PLAYER].hand);
	Discard = C_INIT;
	Finished = FALSE;
	End = 700;
}

shuffle() {

	reg int		i, r;
	reg CARD	temp;

	for (i = 0; i < DECK_SZ; i++) {
		r = roll(1, DECK_SZ) - 1;
		if (r < 0 || r > DECK_SZ - 1) {
			fprintf(stderr, "shuffle: card no. error: %d\n", r);
			die();
		}
		temp = Deck[r];
		Deck[r] = Deck[i];
		Deck[i] = temp;
	}
	Topcard = &Deck[DECK_SZ];
}

newboard() {

	werase(Board);
	werase(Score);
	mvaddstr(5, 0, "--HAND--");
	mvaddch(6, 0, 'P');
	mvaddch(7, 0, '1');
	mvaddch(8, 0, '2');
	mvaddch(9, 0, '3');
	mvaddch(10, 0, '4');
	mvaddch(11, 0, '5');
	mvaddch(12, 0, '6');
	mvaddstr(13, 0, "--BATTLE--");
	mvaddstr(15, 0, "--SPEED--");
	mvaddstr(5, 20, "--DECK--");
	mvaddstr(7, 20, "--DISCARD--");
	mvaddstr(13, 20, "--BATTLE--");
	mvaddstr(15, 20, "--SPEED--");
	wmove(Miles, 0, 0);
	if (winch(Miles) != '-') {
		werase(Miles);
		mvwaddstr(Miles, 0, 0, "--MILEAGE--");
		mvwaddstr(Miles, 0, 41, "--MILEAGE--");
	}
	else {
		wmove(Miles, 1, 0);
		wclrtobot(Miles);
	}
	newscore();
	stdscr = Board;
}

newscore() {

	reg int	i;

	stdscr = Score;
	move(0, 22);
	if (inch() != 'Y') {
		erase();
		mvaddstr(0, 22,  "You   Comp   Value");
		mvaddstr(1, 2, "Milestones Played");
		mvaddstr(2, 8, "Each Safety");
		mvaddstr(3, 5, "All 4 Safeties");
		mvaddstr(4, 3, "Each Coup Fourre");
		mvaddstr(2, 37, "100");
		mvaddstr(3, 37, "300");
		mvaddstr(4, 37, "300");
	}
	else {
		move(5, 1);
		clrtobot();
	}
	for (i = 0; i < SCORE_Y; i++)
		mvaddch(i, 0, '|');
	move(SCORE_Y - 1, 1);
	while (addch('_') != ERR)
		continue;
	if (Window == W_FULL || Finished) {
		mvaddstr(5, 5, "Trip Completed");
		mvaddstr(6, 10, "Safe Trip");
		mvaddstr(7, 5, "Delayed Action");
		mvaddstr(8, 10, "Extension");
		mvaddstr(9, 11, "Shut-Out");
		mvaddstr(10, 21, "----   ----   -----");
		mvaddstr(11, 9, "Hand Total");
		mvaddstr(12, 20, "-----  -----");
		mvaddstr(13, 6, "Overall Total");
		mvaddstr(14, 15, "Games");
		mvaddstr(5, 37, "400");
		mvaddstr(6, 37, "300");
		mvaddstr(7, 37, "300");
		mvaddstr(8, 37, "200");
		mvaddstr(9, 37, "500");
	}
	else {
		mvaddstr(5, 21, "----   ----   -----");
		mvaddstr(6, 9, "Hand Total");
		mvaddstr(7, 20, "-----  -----");
		mvaddstr(8, 6, "Overall Total");
		mvaddstr(9, 15, "Games");
		mvaddstr(11, 2, "p: pick");
		mvaddstr(12, 2, "u: use #");
		mvaddstr(13, 2, "d: discard #");
		mvaddstr(14, 2, "w: toggle window");
		mvaddstr(11, 21, "q: quit");
		mvaddstr(12, 21, "o: order hand");
		mvaddstr(13, 21, "s: save");
		mvaddstr(14, 21, "r: reprint");
	}
	stdscr = Board;
}
//go.sysin dd *
echo 'x - =test/=mille/mille.c'
sed 's/^X//' <<'//go.sysin dd *' >=test/=mille/mille.c
# include	"mille.h"
# include	<signal.h>
# include       <term.h>

int	rub();

char	_sobuf[BUFSIZ];

main(ac, av)
reg int		ac;
reg char	*av[]; {

	reg bool	restore;

# if 0
	if (getuid() == GURP) {
		printf("%s: Permission denied\n", av[0]);
		exit(1);
	}
# endif
	if (strcmp(av[0], "a.out") == 0) {
		outf = fopen("q", "w");
		setbuf(outf, 0);
		Debug = TRUE;
	}
	restore = FALSE;
# ifdef pdp11
	if (geteuid() != ARNOLD)
		maxusers(MAXUSERS, NULL);
# endif
	switch (ac) {
	  case 2:
		rest_f(av[1]);
		restore = TRUE;
	  case 1:
		break;
	  default:
		printf("usage: milles [ restore_file ]\n");
		exit(-1);
		/* NOTREACHED */
	}
	setbuf(stdout, _sobuf);
	Play = PLAYER;
	initscr();
	if (! cursor_address) {
		printf("Sorry.  Need cursor addressing to play mille\n");
		exit(-1);
	}
	delwin(stdscr);
	stdscr = Board = newwin(BOARD_Y, BOARD_X, 0, 0);
	Score = newwin(SCORE_Y, SCORE_X, 0, 40);
	Miles = newwin(MILES_Y, MILES_X, 17, 0);
	leaveok(Score, TRUE);
	leaveok(Miles, TRUE);
	clearok(curscr, TRUE);
# ifndef PROF
	srand(getpid());
# else
	srand(0);
# endif
	crmode();
	noecho();
	nonl();
	signal(SIGINT, rub);
	for (;;) {
		if (!restore || (Player[PLAYER].total >= 5000
		    || Player[COMP].total >= 5000)) {
			if (Player[COMP].total < Player[PLAYER].total)
				Player[PLAYER].games++;
			else if (Player[COMP].total > Player[PLAYER].total)
				Player[COMP].games++;
			Player[COMP].total = 0;
			Player[PLAYER].total = 0;
		}
		do {
			if (!restore)
				Handstart = Play = other(Handstart);
			if (!restore || On_exit) {
				shuffle();
				init();
			}
			newboard();
			if (restore)
				mvwaddstr(Score, ERR_Y, ERR_X, Initstr);
			prboard();
			do {
				domove();
				if (Finished)
					newscore();
				prboard();
			} while (!Finished);
			check_more();
			restore = On_exit = FALSE;
		} while (Player[COMP].total < 5000
		    && Player[PLAYER].total < 5000);
	}
}

X/*
 *	Routine to trap rubouts, and make sure they really want to
 * quit.
 */
rub() {

	signal(SIGINT, 1);
	if (getyn("Really? "))
		die();
	signal(SIGINT, rub);
}

X/*
 *	Time to go beddy-by
 */
die() {

	signal(SIGINT, 1);
	if (outf)
		fflush(outf);
	mvcur(0, COLS - 1, LINES - 1, 0);
	endwin();
	exit(1);
}
//go.sysin dd *
echo 'x - =test/=mille/mille.h'
sed 's/^X//' <<'//go.sysin dd *' >=test/=mille/mille.h
# include	<ctype.h>
# include	<curses.h>

X/*
 * Miscellaneous constants
 */

# define	unsgn		unsigned
# define        reg             register
# define	CARD		short

# ifdef  vax
#	define	ARNOLD		78	/* my uid			*/
# else
#	define	ARNOLD		24601	/* my uid			*/
# endif

# define	GURP		28672	/* bad uid			*/
# define	MAXUSERS	35	/* max # of users for startup	*/
# define	HAND_SZ		7	/* number of cards in a hand	*/
# define	DECK_SZ		101	/* number of cards in decks	*/
# define	NUM_SAFE	4	/* number of saftey cards	*/
# define	NUM_MILES	5	/* number of milestones types	*/
# define	NUM_CARDS	20	/* number of types of cards	*/
# define	BOARD_Y		17	/* size of board screen		*/
# define	BOARD_X		40
# define	MILES_Y		7	/* size of mileage screen	*/
# define	MILES_X		80
# define	SCORE_Y		17	/* size of score screen		*/
# define	SCORE_X		40
# define	MOVE_Y		10	/* Where to print move prompt	*/
# define	MOVE_X		20
# define	ERR_Y		15	/* Where to print errors	*/
# define	ERR_X		5
# define	EXT_Y		4	/* Where to put Extension	*/
# define	EXT_X		9

# define	PLAYER		0
# define	COMP		1

# define	W_SMALL		0	/* Small (initial) window	*/
# define	W_FULL		1	/* Full (final) window		*/

X/*
 * Move types
 */

# define	M_DISCARD	0
# define	M_DRAW		1
# define	M_PLAY		2
# define	M_ORDER		3

X/*
 * Scores
 */

# define	SC_SAFETY	100
# define	SC_ALL_SAFE	300
# define	SC_COUP		300
# define	SC_TRIP		400
# define	SC_SAFE		300
# define	SC_DELAY	300
# define	SC_EXTENSION	200
# define	SC_SHUT_OUT	500

X/*
 * safety descriptions
 */

# define	S_UNKNOWN	0	/* location of safety unknown	*/
# define	S_IN_HAND	1	/* safety in player's hand	*/
# define	S_PLAYED	2	/* safety has been played	*/
# define	S_GAS_SAFE	0	/* Gas safety card index	*/
# define	S_SPARE_SAFE	1	/* Tire safety card index	*/
# define	S_DRIVE_SAFE	2	/* Driveing safety card index	*/
# define	S_RIGHT_WAY	3	/* Right-of-Way card index	*/
# define	S_CONV		15	/* conversion from C_ to S_	*/

X/*
 * card numbers
 */

# define	C_INIT		-1
# define	C_25		0
# define	C_50		1
# define	C_75		2
# define	C_100		3
# define	C_200		4
# define	C_EMPTY		5
# define	C_FLAT		6	
# define	C_CRASH		7
# define	C_STOP		8
# define	C_LIMIT		9
# define	C_GAS		10
# define	C_SPARE		11
# define	C_REPAIRS	12
# define	C_GO		13
# define	C_END_LIMIT	14
# define	C_GAS_SAFE	15
# define	C_SPARE_SAFE	16
# define	C_DRIVE_SAFE	17
# define	C_RIGHT_WAY	18

typedef struct {
	bool	coups[NUM_SAFE];
	bool	can_go;
	bool	new_battle;
	bool	new_speed;
	short	safety[NUM_SAFE];
	short	nummiles[NUM_MILES];
	CARD	hand[HAND_SZ];
	CARD	battle;
	CARD	speed;
	int	mileage;
	int	hand_tot;
	int	safescore;
	int	coupscore;
	int	total;
	int	games;
} PLAY;

X/*
 * macros
 */

# define	other(x)	(1 - x)
# define	nextplay()	(Play = other(Play))
# define	nextwin(x)	(1 - x)
# define	opposite(x)	(Opposite[x])
# define	issafety(x)	(x >= C_GAS_SAFE)

X/*
 * externals
 */

extern bool	Debug, Finished, Next, On_exit, Order, Saved;

extern char	*C_fmt, **C_name, *Fromfile, Initstr[];

extern int	Card_no, End, Handstart, Movetype, Numcards[], Numgos,
		Numneed[], Numseen[NUM_CARDS], Play, Value[], Window;

extern CARD	Deck[DECK_SZ], Discard, Opposite[NUM_CARDS], *Topcard;

extern FILE	*outf;

extern PLAY	Player[2];

extern WINDOW	*Board, *Miles, *Score;

X/*
 * functions
 */

CARD	getcard();
//go.sysin dd *
echo 'x - =test/=mille/misc.c'
sed 's/^X//' <<'//go.sysin dd *' >=test/=mille/misc.c
#include	"mille.h"
#include	"unctrl.h"
#define	NUMSAFE	4

X/* VARARGS1 */
error(str, arg)
char	*str;
{
	stdscr = Score;
	mvprintw(ERR_Y, ERR_X, str, arg);
	clrtoeol();
	putchar('');
	refresh();
	stdscr = Board;
	return FALSE;
}

CARD
getcard()
{
	reg char	c, c1;

	for (;;) {
		while ((c = getch()) == '\n' || c == '\r' || c == ' ')
			continue;
		if (islower(c))
			c = toupper(c);
		if (c == killchar() || c == erasechar())
			return -1;
		addstr(unctrl(c));
		clrtoeol();
		switch (c) {
		  case '1':	case '2':	case '3':
		  case '4':	case '5':	case '6':
			c -= '0';
			break;
		  case '0':	case 'P':	case 'p':
			c = 0;
			break;
		  default:
			putchar('');
			addch('\b');
			if (!isprint(c))
				addch('\b');
			c = -1;
			break;
		}
		refresh();
		if (c >= 0) {
			while ((c1=getch()) != '\r' && c1 != '\n' && c1 != ' ')
				if (c1 == killchar())
					return -1;
				else if (c1 == erasechar()) {
					addch('\b');
					clrtoeol();
					refresh();
					goto cont;
				}
				else
					write(0, "", 1);
			return c;
		}
cont:		;
	}
}

check_ext(forcomp)
reg bool	forcomp; {


	if (End == 700)
		if (Play == PLAYER) {
			if (getyn("Extension? ")) {
extend:
				if (!forcomp)
					End = 1000;
				return TRUE;
			}
			else {
done:
				if (!forcomp)
					Finished = TRUE;
				return FALSE;
			}
		}
		else {
			reg PLAY	*pp, *op;
			reg int		i, safe, miles;

			pp = &Player[COMP];
			op = &Player[PLAYER];
			for (safe = 0, i = 0; i < NUMSAFE; i++)
				if (pp->safety[i] != S_UNKNOWN)
					safe++;
			if (safe < 2)
				goto done;
			if (op->mileage == 0 || onecard(op)
			    || (op->can_go && op->mileage >= 500))
				goto done;
			for (miles = 0, i = 0; i < NUMSAFE; i++)
				if (op->safety[i] != S_PLAYED
				    && pp->safety[i] == S_UNKNOWN)
					miles++;
			if (miles + safe == NUMSAFE)
				goto extend;
			for (miles = 0, i = 0; i < HAND_SZ; i++)
				if ((safe = pp->hand[i]) <= C_200)
					miles += Value[safe]; 
			if (miles + (Topcard - Deck) * 3 > 1000)
				goto extend;
			goto done;
		}
	else
		goto done;
}

X/*
 *	Get a yes or no answer to the given question.  Saves are
 * also allowed.  Return TRUE if the answer was yes, FALSE if no.
 */
getyn(prompt)
reg char	*prompt; {

	reg char	c;

	Saved = FALSE;
	for (;;) {
		leaveok(Board, FALSE);
		mvaddstr(MOVE_Y, MOVE_X, prompt);
		clrtoeol();
		refresh();
		switch (c = getch()) {
		  case 'n':	case 'N':
			addch('N');
			refresh();
			leaveok(Board, TRUE);
			return FALSE;
		  case 'y':	case 'Y':
			addch('Y');
			refresh();
			leaveok(Board, TRUE);
			return TRUE;
		  case 's':	case 'S':
			addch('S');
			refresh();
			Saved = save();
			continue;
		  default:
			addstr(unctrl(c));
			refresh();
			putchar('');
			break;
		}
	}
}

X/*
 *	Check to see if more games are desired.  If not, and game
 * came from a saved file, make sure that they don't want to restore
 * it.  Exit appropriately.
 */
check_more() {

	raw();	/* Flush input */
	noraw();

	On_exit = TRUE;
	if (Player[PLAYER].total >= 5000 || Player[COMP].total >= 5000)
		if (getyn("Another game? "))
			return;
		else {
			/*
			 * must do accounting normally done in main()
			 */
			if (Player[PLAYER].total > Player[COMP].total)
				Player[PLAYER].games++;
			else if (Player[PLAYER].total < Player[COMP].total)
				Player[COMP].games++;
			Player[COMP].total = 0;
			Player[PLAYER].total = 0;
		}
	else
		if (getyn("Another hand? "))
			return;
	if (!Saved && getyn("Save game? "))
		if (!save())
			return;
	die();
}
//go.sysin dd *
echo 'x - =test/=mille/move.c'
sed 's/^X//' <<'//go.sysin dd *' >=test/=mille/move.c
#include	"mille.h"
#include	"unctrl.h"

#define	CTRL(c)		(c - 'A' + 1)

char	*Movenames[] = {
		"M_DISCARD", "M_DRAW", "M_PLAY", "M_ORDER"
	};

domove()
{
	reg PLAY	*pp;
	reg int		i, j;
	reg bool	goodplay;

	pp = &Player[Play];
	if (Play == PLAYER)
		getmove();
	else
		calcmove();
	Next = FALSE;
	goodplay = TRUE;
	switch (Movetype) {
	  case M_DISCARD:
		if (haspicked(pp)) {
			if (pp->hand[Card_no] == C_INIT)
				if (Card_no == 6)
					Finished = TRUE;
				else
					error("no card there");
			else {
				Discard = pp->hand[Card_no];
				pp->hand[Card_no] = C_INIT;
				Next = TRUE;
				if (Play == PLAYER)
					account(Discard);
			}
		}
		else
			error("must pick first");
		break;
	  case M_PLAY:
		goodplay = playcard(pp);
		break;
	  case M_DRAW:
		Card_no = 0;
		if (Topcard <= Deck)
			error("no more cards");
		else if (haspicked(pp))
			error("already picked");
		else {
			pp->hand[0] = *--Topcard;
			if (Debug)
				fprintf(outf, "DOMOVE: Draw %s\n", C_name[*Topcard]);
acc:
			if (Play == COMP) {
				account(*Topcard);
				if (issafety(*Topcard))
					pp->safety[*Topcard-S_CONV] = S_IN_HAND;
			}
			if (pp->hand[1] == C_INIT && Topcard > Deck) {
				Card_no = 1;
				pp->hand[1] = *--Topcard;
				if (Debug)
					fprintf(outf, "DOMOVE: Draw %s\n", C_name[*Topcard]);
				goto acc;
			}
			pp->new_battle = FALSE;
			pp->new_speed = FALSE;
		}
		break;

	  case M_ORDER:
		break;
	}
	/*
	 * move blank card to top by one of two methods.  If the
	 * computer's hand was sorted, the randomness for picking
	 * between equally valued cards would be lost
	 */
	if (Order && Movetype != M_DRAW && goodplay && pp == &Player[PLAYER])
		sort(pp->hand);
	else
		for (i = 1; i < HAND_SZ; i++)
			if (pp->hand[i] == C_INIT) {
				for (j = 0; pp->hand[j] == C_INIT; j++)
					if (j >= HAND_SZ) {
						j = 0;
						break;
					}
				pp->hand[i] = pp->hand[j];
				pp->hand[j] = C_INIT;
			}
	if (Topcard <= Deck)
		check_go();
	if (Next)
		nextplay();
}

X/*
 *	Check and see if either side can go.  If they cannot,
 * the game is over
 */
check_go() {

	reg CARD	card;
	reg PLAY	*pp, *op;
	reg int		i;

	for (pp = Player; pp < &Player[2]; pp++) {
		op = (pp == &Player[COMP] ? &Player[PLAYER] : &Player[COMP]);
		for (i = 0; i < HAND_SZ; i++) {
			card = pp->hand[i];
			if (issafety(card) || canplay(pp, op, card)) {
				if (Debug) {
					fprintf(outf, "CHECK_GO: can play %s (%d), ", C_name[card], card);
					fprintf(outf, "issafety(card) = %d, ", issafety(card));
					fprintf(outf, "canplay(pp, op, card) = %d\n", canplay(pp, op, card));
				}
				return;
			}
			else if (Debug)
				fprintf(outf, "CHECK_GO: cannot play %s\n",
				    C_name[card]);
		}
	}
	Finished = TRUE;
}

playcard(pp)
reg PLAY	*pp;
{
	reg int		v;
	reg CARD	card;

	/*
	 * check and see if player has picked
	 */
	switch (pp->hand[Card_no]) {
	  default:
		if (!haspicked(pp))
mustpick:
			return error("must pick first");
	  case C_GAS_SAFE:	case C_SPARE_SAFE:
	  case C_DRIVE_SAFE:	case C_RIGHT_WAY:
		break;
	}

	card = pp->hand[Card_no];
	if (Debug)
		fprintf(outf, "PLAYCARD: Card = %s\n", C_name[card]);
	Next = FALSE;
	switch (card) {
	  case C_200:
		if (pp->nummiles[C_200] == 2)
			return error("only two 200's per hand");
	  case C_100:	case C_75:
		if (pp->speed == C_LIMIT)
			return error("limit of 50");
	  case C_50:
		if (pp->mileage + Value[card] > End)
			return error("puts you over %d", End);
	  case C_25:
		if (!pp->can_go)
			return error("cannot move now");
		pp->nummiles[card]++;
		v = Value[card];
		pp->total += v;
		pp->hand_tot += v;
		if ((pp->mileage += v) == End)
			check_ext(FALSE);
		break;

	  case C_GAS:	case C_SPARE:	case C_REPAIRS:
		if (pp->battle != opposite(card))
			return error("can't play \"%s\"", C_name[card]);
		pp->battle = card;
		if (pp->safety[S_RIGHT_WAY] == S_PLAYED)
			pp->can_go = TRUE;
		break;

	  case C_GO:
		if (pp->battle != C_INIT && pp->battle != C_STOP
		    && !isrepair(pp->battle))
			return error("cannot play \"Go\" on a \"%s\"",
			    C_name[pp->battle]);
		pp->battle = C_GO;
		pp->can_go = TRUE;
		break;

	  case C_END_LIMIT:
		if (pp->speed != C_LIMIT)
			return error("not limited");
		pp->speed = C_END_LIMIT;
		break;

	  case C_EMPTY:	case C_FLAT:	case C_CRASH:
	  case C_STOP:
		pp = &Player[other(Play)];
		if (!pp->can_go)
			return error("opponent cannot go");
		else if (pp->safety[safety(card) - S_CONV] == S_PLAYED)
protected:
			return error("opponent is protected");
		pp->battle = card;
		pp->new_battle = TRUE;
		pp->can_go = FALSE;
		pp = &Player[Play];
		break;

	  case C_LIMIT:
		pp = &Player[other(Play)];
		if (pp->speed == C_LIMIT)
			return error("opponent has limit");
		if (pp->safety[S_RIGHT_WAY] == S_PLAYED)
			goto protected;
		pp->speed = C_LIMIT;
		pp->new_speed = TRUE;
		pp = &Player[Play];
		break;

	  case C_GAS_SAFE:	case C_SPARE_SAFE:
	  case C_DRIVE_SAFE:	case C_RIGHT_WAY:
		if (pp->battle == opposite(card)
		    || (card == C_RIGHT_WAY && pp->speed == C_LIMIT)) {
			if (!(card == C_RIGHT_WAY && !isrepair(pp->battle))) {
				pp->battle = C_GO;
				pp->can_go = TRUE;
			}
			if (card == C_RIGHT_WAY && pp->speed == C_LIMIT)
				pp->speed = C_INIT;
			if (pp->new_battle
			    || (pp->new_speed && card == C_RIGHT_WAY)) {
				pp->coups[card - S_CONV] = TRUE;
				pp->total += SC_COUP;
				pp->hand_tot += SC_COUP;
				pp->coupscore += SC_COUP;
			}
		}
		/*
		 * if not coup, must pick first
		 */
		else if (pp->hand[0] == C_INIT && Topcard > Deck)
			goto mustpick;
		pp->safety[card - S_CONV] = S_PLAYED;
		pp->total += SC_SAFETY;
		pp->hand_tot += SC_SAFETY;
		if ((pp->safescore += SC_SAFETY) == NUM_SAFE * SC_SAFETY) {
			pp->total += SC_ALL_SAFE;
			pp->hand_tot += SC_ALL_SAFE;
		}
		if (card == C_RIGHT_WAY) {
			if (pp->speed == C_LIMIT)
				pp->speed = C_INIT;
			if (pp->battle == C_STOP || pp->battle == C_INIT) {
				pp->can_go = TRUE;
				pp->battle = C_INIT;
			}
			if (!pp->can_go && isrepair(pp->battle))
				pp->can_go = TRUE;
		}
		Next = -1;
		break;

	  case C_INIT:
		error("no card there");
		Next = -1;
		break;
	}
	if (pp == &Player[PLAYER])
		account(card);
	pp->hand[Card_no] = C_INIT;
	Next = (Next == -1 ? FALSE : TRUE);
	return TRUE;
}

getmove()
{
	reg char	c, *sp;
	static char	moveprompt[] = ">>:Move:";
#ifdef EXTRAP
	static bool	last_ex = FALSE;	/* set if last command was E */

	if (last_ex) {
		undoex();
		prboard();
		last_ex = FALSE;
	}
#endif
	for (;;) {
		stand(MOVE_Y, MOVE_X, moveprompt);
		clrtoeol();
		move(MOVE_Y, MOVE_X + sizeof moveprompt);
		leaveok(Board, FALSE);
		refresh();
		while ((c = getch()) == killchar() || c == erasechar())
			continue;
		if (islower(c))
			c = toupper(c);
		if (isprint(c) && !isspace(c)) {
			addch(c);
			refresh();
		}
		switch (c)
		{
		  case 'P':		/* Pick */
			Movetype = M_DRAW;
			goto ret;
		  case 'U':		/* Use Card */
		  case 'D':		/* Discard Card */
			if ((Card_no = getcard()) < 0)
				break;
			Movetype = (c == 'U' ? M_PLAY : M_DISCARD);
			goto ret;
		  case 'O':		/* Order */
			Order = !Order;
			Movetype = M_ORDER;
			goto ret;
		  case 'Q':		/* Quit */
			rub();		/* Same as a rubout */
			break;
		  case 'W':		/* Window toggle */
			Window = nextwin(Window);
			newscore();
			prscore(TRUE);
			wrefresh(Score);
			break;
		  case 'R':		/* Redraw screen */
		  case CTRL('L'):
			clearok(curscr, TRUE);
			newboard();
			prboard();
			break;
		  case 'S':		/* Save game */
			On_exit = FALSE;
			save();
			break;
		  case 'E':		/* Extrapolate */
#ifdef EXTRAP
			if (last_ex)
				break;
			Finished = TRUE;
			if (Window != W_FULL)
				newscore();
			prscore(FALSE);
			wrefresh(Score);
			last_ex = TRUE;
			Finished = FALSE;
#else
			error("%c: command not implemented", c);
#endif
			break;
		  case '\r':		/* Ignore RETURNs and	*/
		  case '\n':		/* Line Feeds		*/
		  case ' ':		/* and Spaces		*/
			break;
		  case 'Z':		/* Debug code */
			if (geteuid() == ARNOLD) {
				if (!Debug && outf == NULL) {
					char	buf[40];
over:
					mvaddstr(MOVE_Y, MOVE_X, "file: ");
					clrtoeol();
					leaveok(Board, FALSE);
					refresh();
					sp = buf;
					while ((*sp = getch()) != '\n') {
						if (*sp == killchar())
							goto over;
						else if (*sp == erasechar()) {
							if (--sp < buf)
								sp = buf;
							else {
								addch('\b');
								if (*sp < ' ')
								    addch('\b');
								clrtoeol();
							}
						}
						else
							addstr(unctrl(*sp++));
						refresh();
					}
					*sp = '\0';
					leaveok(Board, TRUE);
					if ((outf = fopen(buf, "w")) == NULL)
						perror(buf);
					setbuf(outf, 0);
				}
				Debug = !Debug;
				break;
			}
			/* FALLTHROUGH */
		  default:
			error("unknown command: %s", unctrl(c));
			break;
		}
	}
ret:
	leaveok(Board, TRUE);
}
X/*
 * return whether or not the player has picked
 */
haspicked(pp)
reg PLAY	*pp; {

	reg int	card;

	if (Topcard <= Deck)
		return TRUE;
	switch (pp->hand[Card_no]) {
	  case C_GAS_SAFE:	case C_SPARE_SAFE:
	  case C_DRIVE_SAFE:	case C_RIGHT_WAY:
		card = 1;
		break;
	  default:
		card = 0;
		break;
	}
	return (pp->hand[card] != C_INIT);
}

account(card)
reg CARD	card; {

	reg CARD	oppos;

	if (card == C_INIT)
		return;
	++Numseen[card];
	if (Play == COMP)
		switch (card) {
		  case C_GAS_SAFE:
		  case C_SPARE_SAFE:
		  case C_DRIVE_SAFE:
			oppos = opposite(card);
			Numgos += Numcards[oppos] - Numseen[oppos];
			break;
		  case C_CRASH:
		  case C_FLAT:
		  case C_EMPTY:
		  case C_STOP:
			Numgos++;
			break;
		}
}

sort(hand)
reg CARD	*hand;
{
	reg CARD	*cp, *tp;
	reg int		j;
	reg CARD	temp;

	cp = hand;
	hand += HAND_SZ;
	for ( ; cp < &hand[-1]; cp++)
		for (tp = cp + 1; tp < hand; tp++)
			if (*cp > *tp) {
				temp = *cp;
				*cp = *tp;
				*tp = temp;
			}
}
//go.sysin dd *
echo 'x - =test/=mille/print.c'
sed 's/^X//' <<'//go.sysin dd *' >=test/=mille/print.c
# include	"mille.h"

# define	COMP_STRT	20
# define	CARD_STRT	2

prboard() {

	reg PLAY	*pp;
	reg int		i, j, k, temp;

	for (k = 0; k < 2; k++) {
		pp = &Player[k];
		temp = k * COMP_STRT + CARD_STRT;
		for (i = 0; i < NUM_SAFE; i++)
			if (pp->safety[i] == S_PLAYED) {
				mvaddstr(i, temp, C_name[i + S_CONV]);
				if (pp->coups[i])
					mvaddch(i, temp - CARD_STRT, '*');
			}
		mvprintw(14, temp, C_fmt, C_name[pp->battle]);
		mvprintw(16, temp, C_fmt, C_name[pp->speed]);
		for (i = C_25; i <= C_200; ) {
			reg char	*name;
			reg int		end;

			name = C_name[i];
			temp = k * 40;
			end = pp->nummiles[i++];
			for (j = 0; j < end; j++)
				mvwaddstr(Miles, i, (j << 2) + temp, name);
		}
	}
	prscore(TRUE);
	temp = CARD_STRT;
	pp = &Player[PLAYER];
	for (i = 0; i < HAND_SZ; i++)
		mvprintw(i + 6, temp, C_fmt, C_name[pp->hand[i]]);
	mvprintw(6, COMP_STRT + CARD_STRT, "%2d", Topcard - Deck);
	mvprintw(8, COMP_STRT + CARD_STRT, C_fmt, C_name[Discard]);
	if (End == 1000) {
		static char	ext[] = "Extension";

		stand(EXT_Y, EXT_X, ext);
	}
	wrefresh(Board);
	wrefresh(Miles);
	wrefresh(Score);
}

X/*
 *	Put str at (y,x) in standout mode
 */
stand(y, x, str)
reg int		y, x;
reg char	*str; {

	standout();
	mvaddstr(y, x, str);
	standend();
	return TRUE;
}

prscore(for_real)
reg bool	for_real; {

	reg PLAY	*pp;
	reg int		x;
	reg char	*Score_fmt = "%4d";

	stdscr = Score;
	for (pp = Player; pp < &Player[2]; pp++) {
		x = (pp - Player) * 6 + 21;
		mvprintw(1, x, Score_fmt, pp->mileage);
		mvprintw(2, x, Score_fmt, pp->safescore);
		if (pp->safescore == 400)
			mvaddstr(3, x + 1, "300");
		else
			mvaddch(3, x + 3, '0');
		mvprintw(4, x, Score_fmt, pp->coupscore);
		if (Window == W_FULL || Finished) {
#ifdef EXTRAP
			if (for_real)
				finalscore(pp);
			else
				extrapolate(pp);
#else
			finalscore(pp);
#endif
			mvprintw(11, x, Score_fmt, pp->hand_tot);
			mvprintw(13, x, Score_fmt, pp->total);
			mvprintw(14, x, Score_fmt, pp->games);
		}
		else {
			mvprintw(6, x, Score_fmt, pp->hand_tot);
			mvprintw(8, x, Score_fmt, pp->total);
			mvprintw(9, x, Score_fmt, pp->games);
		}
	}
	stdscr = Board;
}
//go.sysin dd *
echo 'x - =test/=mille/roll.c'
sed 's/^X//' <<'//go.sysin dd *' >=test/=mille/roll.c
X/*
 *	This routine rolls ndie nside-sided dice.
 */

# define	reg	register

# ifndef vax
# define	MAXRAND	32767L

roll(ndie, nsides)
int	ndie, nsides; {

	reg long	tot;
	reg unsigned	n, r;

	tot = 0;
	n = ndie;
	while (n--)
		tot += rand();
	return (int) ((tot * (long) nsides) / ((long) MAXRAND + 1)) + ndie;
}

# else

roll(ndie, nsides)
reg int	ndie, nsides; {

	reg int		tot, r;
	reg double	num_sides;

	num_sides = nsides;
	tot = 0;
	while (ndie--)
		tot += (r = rand()) * (num_sides / 017777777777) + 1;
	return tot;
}
# endif
//go.sysin dd *
echo 'x - =test/=mille/save.c'
sed 's/^X//' <<'//go.sysin dd *' >=test/=mille/save.c
#include	"mille.h"
#include	"unctrl.h"
#include	<sys/types.h>
#include	<sys/stat.h>
#include	<time.h>

typedef	struct stat	STAT;
typedef	struct tm	TIME;

char	*ctime();

int	read(), write();

X/*
 *	This routine saves the current game for use at a later date
 */
extern int	errno;
extern char	*sys_errlist[];

save() {

	reg char	*sp;
	reg int		outf;
	reg TIME	*tp;
	char		buf[80];
	TIME		tme;
	STAT		junk;

	tp = &tme;
	if (Fromfile && getyn("Same file? "))
		strcpy(buf, Fromfile);
	else {
over:
		mvaddstr(MOVE_Y, MOVE_X, "file: ");
		clrtoeol();
		leaveok(Board, FALSE);
		refresh();
#ifdef UNDEFINED
		sp = buf;
		while ((*sp = getch()) != '\n') {
			if (*sp == killchar())
				goto over;
			else if (*sp == erasechar()) {
				if (--sp < buf)
					sp = buf;
				else {
					addch('\b');
					/*
					 * if the previous char was a control
					 * char, cover up two characters.
					 */
					if (*sp < ' ')
						addch('\b');
					clrtoeol();
				}
			}
			else
				addstr(unctrl(*sp++));
			refresh();
		}
		*sp = '\0';
#else
		getstr(buf);
#endif
		leaveok(Board, TRUE);
	}

	/*
	 * check for existing files, and confirm overwrite if needed
	 */

	if (sp == buf || (!Fromfile && stat(buf, &junk) > -1
	    && getyn("Overwrite File? ") == FALSE))
		return FALSE;

	if ((outf = creat(buf, 0644)) < 0) {
		error(sys_errlist[errno]);
		return FALSE;
	}
	mvwaddstr(Score, ERR_Y, ERR_X, buf);
	wrefresh(Score);
	time(tp);			/* get current time		*/
	strcpy(buf, ctime(tp));
	for (sp = buf; *sp != '\n'; sp++)
		continue;
	*sp = '\0';
	varpush(outf, write);
	close(outf);
	wprintw(Score, " [%s]", buf);
	wclrtoeol(Score);
	wrefresh(Score);
	return TRUE;
}

X/*
 *	This does the actual restoring.  It returns TRUE if the
 * backup was made on exiting, in which case certain things must
 * be cleaned up before the game starts.
 */
rest_f(file)
reg char	*file; {

	reg char	*sp;
	reg int		inf;
	char		buf[80];
	STAT		sbuf;

	if ((inf = open(file, 0)) < 0) {
		perror(file);
		exit(1);
	}
	if (fstat(inf, &sbuf) < 0) {		/* get file stats	*/
		perror(file);
		exit(1);
	}
	varpush(inf, read);
	close(inf);
	strcpy(buf, ctime(&sbuf.st_mtime));
	for (sp = buf; *sp != '\n'; sp++)
		continue;
	*sp = '\0';
	/*
	 * initialize some necessary values
	 */
	sprintf(Initstr, "%s [%s]\n", file, buf);
	Fromfile = file;
	return !On_exit;
}
//go.sysin dd *
echo 'x - =test/=mille/table.c'
sed 's/^X//' <<'//go.sysin dd *' >=test/=mille/table.c
# define	DEBUG
# include	"mille.h"

main() {

	reg int	i, j, count;

	printf("   %16s -> %5s %5s %4s %s\n", "Card", "cards", "count", "need", "opposite");
	for (i = 0; i < NUM_CARDS - 1; i++) {
		for (j = 0, count = 0; j < DECK_SZ; j++)
			if (Deck[j] == i)
				count++;
		printf("%2d %16s -> %5d %5d %4d %s\n", i, C_name[i], Numcards[i], count, Numneed[i], C_name[opposite(i)]);
	}
}
//go.sysin dd *
echo 'x - =test/=mille/types.c'
sed 's/^X//' <<'//go.sysin dd *' >=test/=mille/types.c
# include	"mille.h"

isrepair(card)
reg CARD	card; {

	return card == C_GAS || card == C_SPARE || card == C_REPAIRS || card == C_INIT;
}

safety(card)
reg CARD	card; {

	switch (card) {
	  case C_EMPTY:
	  case C_GAS:
	  case C_GAS_SAFE:
		return C_GAS_SAFE;
	  case C_FLAT:
	  case C_SPARE:
	  case C_SPARE_SAFE:
		return C_SPARE_SAFE;
	  case C_CRASH:
	  case C_REPAIRS:
	  case C_DRIVE_SAFE:
		return C_DRIVE_SAFE;
	  case C_GO:
	  case C_STOP:
	  case C_RIGHT_WAY:
	  case C_LIMIT:
	  case C_END_LIMIT:
		return C_RIGHT_WAY;
	}
	/* NOTREACHED */
}
//go.sysin dd *
echo 'x - =test/=mille/unctrl.h'
sed 's/^X//' <<'//go.sysin dd *' >=test/=mille/unctrl.h
# include	<stdio.h>
# define	unctrl(ch)	(_unctrl[ch])

extern char	*_unctrl[];
//go.sysin dd *
echo 'x - =test/=mille/varpush.c'
sed 's/^X//' <<'//go.sysin dd *' >=test/=mille/varpush.c
# include	"mille.h"

int	read(), write();

X/*
 *	push variables around via the routine func() on the file
 * channel file.  func() is either read or write.
 */
varpush(file, func)
reg int	file;
reg int	(*func)(); {

	int	temp;

	(*func)(file, &Debug, sizeof Debug);
	(*func)(file, &Finished, sizeof Finished);
	(*func)(file, &Order, sizeof Order);
	(*func)(file, &End, sizeof End);
	(*func)(file, &On_exit, sizeof On_exit);
	(*func)(file, &Handstart, sizeof Handstart);
	(*func)(file, &Numgos, sizeof Numgos);
	(*func)(file,  Numseen, sizeof Numseen);
	(*func)(file, &Play, sizeof Play);
	(*func)(file, &Window, sizeof Window);
	(*func)(file,  Deck, sizeof Deck);
	(*func)(file, &Discard, sizeof Discard);
	(*func)(file,  Player, sizeof Player);
	if (func == read) {
		read(file, &temp, sizeof temp);
		Topcard = &Deck[temp];
		if (Debug) {
			char	buf[80];
over:
			printf("Debug file:");
			gets(buf);
			if ((outf = fopen(buf, "w")) == NULL) {
				perror(buf);
				goto over;
			}
			if (strcmp(buf, "/dev/null") != 0)
				setbuf(outf, 0);
		}
	}
	else {
		temp = Topcard - Deck;
		write(file, &temp, sizeof temp);
	}
}
//go.sysin dd *
exit



More information about the Mod.sources mailing list