[comp.sources.misc] v10i098: source to program to run NCAA basketball tourney

jack@blind-lemon.cs.unlv.edu (03/07/90)

Posting-number: Volume 10, Issue 98
Submitted-by: jack@blind-lemon.cs.unlv.edu
Archive-name: tourney/part01

'tourney' is a program to do all the operations necessary to run the traditional
NCAA basketball tournament pool.  It uses curses extensively, and has been
tested on ATT System V R5.3 & 5.2, BSD (unknown version), and whatever
type of BSD derivative that runs on the NEXT machine.

I have run several small test tournaments, but due to the design of the
code, the size of the tournament should have little bearing on whether or not
it will work.  However, this is version 1.0 (the first release), and you may
want to run a small test tournament yourself to guarantee to yourself that
it does, in fact, work.

----------- cut here --------------------- cut here ------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Install
#	MANIFEST
#	Makefile
#	get.c
#	get.h
#	tourney.1
#	tourney.c
# This archive created: Tue Feb 20 18:17:09 1990
export PATH; PATH=/bin:$PATH
if test -f 'Install'
then
	echo shar: will not over-write existing file "'Install'"
else
cat << \SHAR_EOF > 'Install'
To install tourney:

1) unpack the archive into a directory

2) type 'make'

3) move the executable (tourney) into where it's going to reside

4) tourney needs to be run from the same directory every time, as
   this is the working directory.  Go to the directory from which
   tourney will be run.

5) type 'mkdir players'  -- players in the directory in which all
   the entries are kept, as well as a couple of other files.

Now, tourney is ready to run.

NOTE:

tourney will create a file in the current directory called "standings"
every time a score list is created.  Be sure that you don't have any files
of that name that you don't want overwritten.


CUSTOMIZATION:

The scoring style can be modified so that points-per-round can be
awarding differently (read the man pages for more detail on what
tourney does as is).  To change points per round, the "points[]"
array on line 51 of tourney.c will need to be changed.

Also, I've used "West", "East", "Midwest" and "Southeast" as
region names.  These can be changed if you like as well.  Just
keep in mind the order.  the finalist from region #0 is assumed
to play the finalist from region #1, etc., so don't try to change
the order, just the names.  the region names are on line 54 of tourney.c


RE-RUNNING A TOURNAMENT:

Unfortunately, starting over from scratch for a new tournament is not
yet a menu option.  To do this, just remove everything in the
'players' directory, as well as the file 'teams' in the working directory.

Now, you're ready to go!
SHAR_EOF
fi # end of overwriting check
if test -f 'MANIFEST'
then
	echo shar: will not over-write existing file "'MANIFEST'"
else
cat << \SHAR_EOF > 'MANIFEST'
Install
MANIFEST
Makefile
get.c
get.h
tourney.1
tourney.c
SHAR_EOF
fi # end of overwriting check
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#
# Makefile for tourney program
#
CFLAGS = -g -c
OBJECTS = tourney.o get.o
LDFLAGS = -g

tourney: $(OBJECTS)
	cc $(LDFLAGS) $(OBJECTS) -o tourney -lcurses -ltermcap

tourney.o:   tourney.c
	cc $(CFLAGS) tourney.c

get.o:	get.c
	cc $(CFLAGS) get.c
SHAR_EOF
fi # end of overwriting check
if test -f 'get.c'
then
	echo shar: will not over-write existing file "'get.c'"
else
cat << \SHAR_EOF > 'get.c'
/* %W% general getstring routine		   		  */
/* author: Jack Alexander - this routine may be freely distibuted */
#include	<curses.h>
#include	"get.h"

get_num(x,y,digits,low,high,number)
int	x,y,digits,low,high,*number;
{
	char	buf[80];
	int	retval;

	buf[0]='\0';
	noecho();
	raw();
	while(1)
		switch(getst(digits,x,y,buf,digits+1,NULL,NUM_ONLY,NULL)) {
			case GET_ESCAPE:
				return(GET_ESCAPE);
			case GET_DOWN:
			case GET_RETURN:
				retval=atoi(buf);
				if(retval < low || retval>high)
					break;
				*number = retval;
				echo();
				noraw();
				return(0);
			default:
				break;
		}
}

/* a few hints...	*/
/* idx = current index into string */
/* cx = current screen x position */
/* cy = current screen y position */
/* ix = initial screen x (upon call, where cursor is requested to be placed) */
/* iy = initial screen y " " " ... */
/* fw = field width */
/* mx = max length of string */
/* sl = string length */
/* valid = string of acceptable characters within the type passed in gettype */
/*         if NULL, then all type of characters passed in gettype are allowed */

int	idx, cx, cy, ix, iy, fw, mx, sl, rcode;

getst(len,sx,sy,str,fl,retlen,gettype,valid)
int	len, sx, sy, fl, *retlen, gettype;
char	*str, *valid;
{
	int	c;


	rcode = INITIAL;
	idx=0;
	cx=ix=sx;
	cy=iy=sy;
	mx = len;
	fw = fl;
	str[mx]='\0';
	sl=strlen(str);
#ifdef undef
	init();
#endif
	while(1) {
		if(gettype==SHOW) {	/* want only to display the string */
			drawstr(str,0);	/* draw the string */
#ifdef undef
			de_init();
#endif
			return;
		}
		drawstr(str,1);	/* draw the string */
		c=getch();
		switch(c) {
			case GET_CLEAR:
				clearall(str);
				break;
			case GET_ESCAPE:
				rcode=GET_ESCAPE;
				break;
			case GET_UP:
				rcode=dec_y_pos();
				break;
			case GET_DOWN:
				rcode=inc_y_pos();
				break;
			case GET_LEFT:
				rcode=dec_x_pos();
				break;
			case GET_RIGHT:
				rcode=inc_x_pos(1);
				break;
			case GET_DELETE:
			case GET_DELETE2:
				remove_char(str);
				break;
			case GET_TAB:
			case GET_RETURN:
				rcode = GET_RETURN;
				break;
			default:
				switch(gettype) {
					case NUM_ONLY: /* numbers only (0-9) */
						if(c>='0' && c<='9')
							if(in(c,valid))
								add_char(str,c);
						break;
					case LETTER_ONLY:
					/* letters a-z and A-Z, and ' ' only */
						if(c==' ' || (c>='a' && c<='z') || (c>='A' && c<='Z'))
							if(in(c,valid))
								add_char(str,c);
						break;
					case ALL_ALPHA:/* any printable chars */
						if(c>=' ' && c<=0x7f)
							if(in(c,valid))
								add_char(str,c);
						break;
					default:
						if(c>=' ' && c<=0x7f)
							add_char(str,c);
						break;
				}
				break;
		}
		if(rcode != INITIAL) {
#ifdef undef
			de_init();
#endif
			if(retlen != NULL)
				*retlen = sl;
			return(rcode);
		}
	}
}

dec_y_pos()
{
	if(!idx)
		return(GET_UP);
	if(iy >= cy) {
		idx = 0;
		cx = ix;
		return(INITIAL);
	}
	idx -= fw;
	cy--;
	return(INITIAL);
}

inc_y_pos()
{
	if(idx>=mx-1 || idx==sl)
		return(GET_DOWN);
	if(idx+fw >=  mx) {
		cx += mx-idx - (mx-sl);
		idx += mx-idx - (mx-sl);
#ifdef undef
		cx += (mx - idx -fw);
		idx += (mx - idx - fw);
#endif
		return(INITIAL);
	}
	if(idx+fw > sl) {
		cx += sl - idx;
		idx += sl - idx;
		return(INITIAL);
	}
	idx += fw;
	cy++;
	return(INITIAL);
}

inc_x_pos(flag)
int	flag;
{
	if(flag && idx==sl)
		return(GET_RIGHT);
	if(idx == mx)
		return(GET_RIGHT);
	cx++;
	idx++;
	if(cx >= (ix+fw)) {
		cx = ix;
		cy++;
	}
	return(INITIAL);
}

dec_x_pos()
{
	if(idx==0)
		return(GET_LEFT);
	idx--;
	cx--;
	if(cx < ix) {
		cx = fw+ix-1;
		cy--;
	}
	return(INITIAL);
}

add_char(str, c)
char	*str;
char	c;
{
	register	int	i;

	if(inc_x_pos(0)!=INITIAL)
		return;
	for(i=mx-1;i>=idx;i--)
		str[i]=str[i-1];
	str[idx - 1] = c;
	if(sl!=mx)
		sl++;
}

remove_char(str)
char	*str;
{
	register int i;

	if(idx >= sl) {		/* remove char behind cursor */
		if(dec_x_pos()!=INITIAL)
			return;
		str[sl-1]='\0';
	}
	else 
		for(i=idx;i<mx;i++)
			str[i]=str[i+1];
	sl--;
}

drawstr(str,refr)
char	str[];
int	refr;
{
	int	i, j, s, yo;

	s=sl;
	move(iy,ix);
	for(i=0,yo=1;i<mx;) {
		if(i>=s) {
			addch('.');
			i++;
		}
		else if((s-i) < fw) {
			printw("%s",&str[i]);
			i += s-i;
		}
		else {
			for(j=0;j<fw;j++)
				addch(str[i++]);
		}
		if((i % fw)==0) {
			move(iy + yo,ix);
			yo++;
		}
	}
	move(cy,cx);
	if(refr)
		refresh();
}

init()
{
	noecho();
	raw();
}

de_init()
{
	noraw();
	echo();
}

in(ch,allow)
char	ch, allow[];
{
	register int	i;

	if(allow == NULL)
		return(1);
	for(i=0;i<strlen(allow);i++)
		if(ch==allow[i])
			return(1);
	return(0);
}

clearall(str)
char	str[];
{
	sl=idx=0;
	cx=ix;
	cy=iy;
	str[0]='\0';
}
SHAR_EOF
fi # end of overwriting check
if test -f 'get.h'
then
	echo shar: will not over-write existing file "'get.h'"
else
cat << \SHAR_EOF > 'get.h'
/* defines for my getstring routine */
/* %W% */

#define INITIAL	0
#define GET_CLEAR	0x03	/* control c */
#define	GET_UP		0x0b	/* control k */
#define GET_DOWN	0x0a	/* control j */
#define GET_LEFT	0x08	/* control h */
#define GET_RIGHT	0x0c	/* control l */
#define GET_TAB		0x09	/* control i */
#define GET_RETURN	0x0d	/* control m */
#define GET_DELETE  	24	/* control x */
#define GET_DELETE2	0x7f	/* delete key on most terminals */
#define GET_ESCAPE	0x1b	/* escape */

/* types of characters that can be specified for getstring input */
#define SHOW		0 /* only show the string, don't ask for input */
#define NUM_ONLY	1 /* only numeric characters 0-9 */
#define LETTER_ONLY	2 /* only letters a-z, A-Z and space (' ') */
#define ALL_ALPHA	3 /* all printable ascii characters are permitted */
SHAR_EOF
fi # end of overwriting check
if test -f 'tourney.1'
then
	echo shar: will not over-write existing file "'tourney.1'"
else
cat << \SHAR_EOF > 'tourney.1'
.PU
.TH TOURNEY 1 local
.SH NAME
tourney \-  run an NCAA basketball tournament pool (64-team field)
.SH SYNOPSIS
.ll +8
.B tourney
.ll -8
.br
.SH DESCRIPTION
.B tourney
allows easy tracking of entries in the traditional 64-team
NCAA basketball pool, from the initial 64-team field all the way down
to the final.

As released, 
.B tourney
uses the following scoring method:
1 point for each correct entry for round one, 2 points for correct
entries in round two, 4 points in round three, 8 points in round four,
16 points in round five, and 32 points for round six (the final).
This is the scoring method I've used for years and works
quite well.  If you do not want to score it this way, then it is easily
changed by following instructions in the Install file, which
came with this release.

Entries can be input, and displayed (actually, a ascii file is created,
which can then be sent to a printer), score lists can be printed at
any time, on a game-by-game basis if desired.


.B GETTING STARTED
.RS 5

Although
.B tourney
is menu-driven and intended to be self explanatory,
there are a few things that may be helpful to know going in:

Once
.B tourney
is installed, the next step (before any people's entries
can be entered) is to type in the field of 64 teams.  This is
done through the "1. Setup tournament database" option off of the
main menu, then selecting the "1. Edit list of teams" option off of
the sub-menu.

Once the 64-team field has been entered, individual entries can be
input.  This done from the "1. Setup tournament database" option from
the main menu, then selecting the "Enter a person into the pool, or edit
their entry" option.  This is used to both enter a person initially, as
well as to correct mistakes.  If you must, you can partially enter the
person's picks, then ESCAPE out and finish it later.  This is all
done from this function.

You must completely enter every person's entry before attempting to
create a score list (a pool standing).


.RE
.B RUNNING THE TOURNAMENT
.RS 5

Once all entries have been completed, you can begin the actual running
of the tournament.  This is about the easiest part of
.B tourney.
As game results become available, you can enter them into the database
by selecting the "2. Edit game results" option from the main menu.

This function allows the entering, round-by-round, of game results.
You will be prompted for which round you want to edit (1-6).  Type in the
round number, and press RETURN.  Note that you cannot edit a round without
having completely enter the results for all games from all previous rounds.

You will now be asked for the results of each game in the round.
Again, you can do this partially, then save it out and come back
later when you have more results to enter.  This enables you to
liven up your contest a little bit by providing up-to-the-minute
stats for your rabid basketball fans.

Unfortunately, to run another tournament as of this release, you will
have to manually remove the old player files in the 'players' directory
before you can begin a new tournament.  Hopefully, this type of thing
will come off of the menu a little later on down the line.


.RE
.B EDITING
.RS 5

.B tourney
uses a standard string editing routine I wrote a while back.
Usually, ESCAPE will abort.  Left and right arrows (control-h and
control-l) can be used to move within the string being edited.  Up
and down arrows (control-k and control-j) can be used to move to the next
or previous line.  Control-x is the delete character key.  RETURN or
ENTER is used to enter the current string, and go on to the next string.
TAB can also be used to go to the next entry.  It works a little
differently, as thus a little faster, than RETURN or the arrow keys.


.RE
.B POINT OF INFORMATION
.RS 5

You don't even really need this program for the 1989/90 season, because
anybody who picks UNLV to go all the way will automatically win the
tournament.  You might just want to save it for next year,
or the year after that.
.PP
.SH "AUTHOR"
Jack Alexander, (jack@jimi.cs.unlv.edu)
.SH "BUGS"
This is release 1.0, so who knows?
SHAR_EOF
fi # end of overwriting check
if test -f 'tourney.c'
then
	echo shar: will not over-write existing file "'tourney.c'"
else
cat << \SHAR_EOF > 'tourney.c'
/***********************************************************************
 * tourney - a curses-based program to keep track of the NCAA Basketball
 *	tournament.
 *
 * Author: Jack Alexander
 *         jack@jimi.cs.unlv.edu
 *
 * (c) 1989, by the author.  Feel free to hack this code up as long as
 *	you don't remove the author's name or the copyright notice.
 *	I will attempt to maintain a current version based on valid
 *	changes sent to me at the above email address.
 *
 *	Please send me any WORTHWHILE changes.
 *      
 * 
 * WARNING:  There is absolutely NO WARRANTY OF ANY KIND associated with
 * this program, even for fitness of purpose.  If you choose to run this
 * software, it is at your own risk.
 *
 */
#include <stdio.h>
#include <curses.h>
#include <fcntl.h>
#include <errno.h>

#include "get.h"

#define STANDINGS_FILE	"standings"	/* file used to output standings */
#define MASTER_FILE	"#MASTER"	/* file of results */
#define ENTRY_FILE	"players/#ENTRIES"  /* list of people in contest */
#define TEAM_FILE	"teams" 	/* Name of the file for list of teams */
#define PLAYER_DIR	"players"	/* Directory for people's picks */
#define PLAYER_FILE	"players/%s" 	/* Where to put people's picks */
#define TEAMS		64	 	/* Number of teams in tournament */
#define ROUNDS		7		/* results levels */
#define NAMESZ		20		/* Length of team names */
#define PATHSZ		14		/* max filename */

/* Main menu option values: */
#define MAIN_MENU_NAME	" NCAA Basketball Tournament Tracker "
#define SETUP		1
#define UPDATE		2
#define SHOW_STANDINGS	3
#define EXIT		4

/* Setup menu option values: */
#define SETUP_MENU_NAME	" Tournament Setup menu "
#define ENTER_TEAMS	1
#define ENTER_PERSON	2
#define PRINT_PERSON	3
#define REMOVE_PERSON	4
#define RETURN		5

int	games[ROUNDS] = { 64, 32, 16, 8, 4, 2, 1 };	/* teams per round */
int	points[ROUNDS] = { 0, 1, 2, 4, 8, 16, 32 };	/* points per round */

static	char	*region_name[] = {
	"West", "East", "Midwest", "Southeast"
	};

typedef struct menu_list {
	char 	entry[50];
	int	value;
};

typedef struct	entry {
	char	name[NAMESZ+1];
	unsigned char	round[ROUNDS][TEAMS];
};

struct	menu_list mainmenu[EXIT] = {
	"Setup tournament database", SETUP,
	"Edit game results", UPDATE,
	"Show pool standings", SHOW_STANDINGS,
	"QUIT", EXIT,
};

struct	menu_list setupmenu[RETURN] = {
	"Edit list of teams in the tournament", ENTER_TEAMS,
	"Enter a person into the pool, or edit their entry", ENTER_PERSON,
	"Create a printable file of a person's entry", PRINT_PERSON,
	"Remove an entry from the tournament", REMOVE_PERSON,
	"RETURN to main menu", RETURN,
};

main()
{
	int	done=FALSE;

	tourney_init();
	while(!done)
		switch(main_menu()) {
			case SETUP:
				setup_menu();
				break;
			case UPDATE:
				enter_updates();
				break;
			case SHOW_STANDINGS:
				show_standings();
				break;
			case EXIT:
				cleanup();
				done=TRUE;
				break;
		}
}

tourney_init()
{
	initscr();
}

cleanup()
{
	endwin();
}

enter_updates()
{
	struct	entry	tr;
	int	rnd;
	char	title[80];

	if(read_entry(MASTER_FILE,&tr,0))
		return;
	init();
	while(1) {
		clear();
		printw("Enter the round that you want to edit.  ESC to abort.");
		printw("\n\nRound: ");
		if(get_num(8,2,1,1,6,&rnd)==GET_ESCAPE) {
			de_init();
			return;
		}
		sprintf(title," Enter the results for round %d ",rnd);
		if(edit_round(title,"The winner was ",rnd,games[rnd],&tr,1)) {
			printw("\n Do you want to save this update (y/n)? ");
			refresh();
			if(getch()=='y')
				save_entry(&tr);
		}
		else
			save_entry(&tr);
	}
}

show_standings()
{
	FILE	*fpin, *fpout, *fopen();
	struct	entry	master, this_guy;
	char	name[NAMESZ+1], errmsg[80], sort[80];
	int	score, i, count=0;

	if((fpin=fopen(ENTRY_FILE,"r"))==NULL) {
		terror("ERROR opening entry master file");
		return;
	}
	if((fpout=fopen(STANDINGS_FILE,"w"))==NULL) {
		terror("ERROR opening standings output file");
		return;
	}
	if(read_entry(MASTER_FILE,&master,0)) {
		terror("ERROR opening results file");
		return;
	}

	clear();
	printw("Processing entries...");
	move(5,0);
	refresh();
	while(fgets(name,NAMESZ,fpin)!=NULL) {
		for(i=0;i<strlen(name);i++)
			if(name[i]=='\n')
				name[i]='\0';
		if(read_entry(name,&this_guy,1)) {
			move(5,0);
			continue;
		}
		if((score = calculate_score(&master,&this_guy))<0)
			fprintf(fpout,"*** %-20.20s ***** incomplete entry *****\n",name);
		else
			fprintf(fpout,"%3d %-20.20s\n",score,name);
		count++;
	}
	fclose(fpin);
	fclose(fpout);

	if(count>1) {
		sprintf(sort,"/bin/sort %s -o %s",STANDINGS_FILE,STANDINGS_FILE);
		system(sort);
	}
	sprintf(errmsg,"Output is in '%s'",STANDINGS_FILE);
	terror(errmsg);
}

calculate_score(master,cur)
struct	entry *master, *cur;
{
	int	i, j, score=0;

	for(i=1;i<ROUNDS;i++)
		for(j=0;j<games[i];j++)
			if(cur->round[i][j]==TEAMS+1)
				return(-1); /* incomplete entry */
			else if(master->round[i][j] == cur->round[i][j])
				score += points[i];
	return(score);
}

setup_menu()
{
	int	rcode;

	while(rcode!=RETURN)
		switch(rcode=menu(setupmenu,RETURN,SETUP_MENU_NAME)) {
			case ENTER_TEAMS:
				enter_teams();
				break;
			case ENTER_PERSON:
				enter_picks();
				break;
			case PRINT_PERSON:
				print_picks("");
				break;
			case REMOVE_PERSON:
				remove_pick();
				break;
			case RETURN:
				break;
		}
}

main_menu()
{
	return(menu(mainmenu,EXIT,MAIN_MENU_NAME));
}

menu(sels,q,name)
struct	menu_list	sels[];
int	q;
char	name[];
{
	int	i;

	clear();
	standout();
	printw(name);
	standend();
	printw("\n\n");
	for(i=0;i<q;i++)
		printw("%2d. %s\n",i+1,sels[i].entry);
	for(i=0;i<1 || i>q;) {
		move(q+4,0);
		printw("Which ?");
		refresh();
		i=getch()-'0';
	}
	return(sels[i-1].value);
}

remove_pick()
{
	char	entrant[PATHSZ+1], filename[80], tmp[80];
	FILE	*fpin, *fpout, *fopen();
	int	i;

	init();
	clear();
	printw("Enter the name of the entrant you want to REMOVE\n\n");
	printw("Name: ");
	entrant[0]='\0';
	if(getst(PATHSZ,7,2,entrant,PATHSZ+1,NULL,LETTER_ONLY,NULL)==GET_ESCAPE) {
		de_init();
		return;
	}
	de_init();	/* input is over for this routine */
	for(i=0;i<NAMESZ;i++)
		tmp[i]= (entrant[i]==' ')? '_':entrant[i];
	sprintf(filename,PLAYER_FILE,tmp);
	if(unlink(filename)<0) {
		terror("ERROR unlinking entry file");
		return;
	}
	sprintf(filename,"%stourney.XXXXXX",PLAYER_FILE);
	mktemp(filename);
	if((fpout=fopen(filename,"w"))==NULL) {
		terror("ERROR opening temporary file");
		return;
	}
	if((fpin=fopen(ENTRY_FILE,"r"))==NULL) {
		terror("ERROR opening entry file (list of people)");
		return;
	}
	while(fgets(tmp,NAMESZ,fpin)!=NULL) {
		for(i=strlen(tmp);i>=0;i--)
			if(tmp[i]=='\n') {
				tmp[i]='\0';
				break;
			}
		if(strcmp(tmp,entrant))
			fprintf(fpout,"%s\n",tmp);
	}
	fclose(fpout);
	fclose(fpin);
	if(unlink(ENTRY_FILE)<0) {	/* remove old entry file */
		terror("ERROR unlinking old entry file");
		return;
	}
	link(filename,ENTRY_FILE);	/* link to new version */
	unlink(filename);	/* remove temporary file */
}

print_picks(name)
char	name[];
{
	char	entrant[NAMESZ+1], errmsg[80], teams[TEAMS][NAMESZ+1],
		filename[PATHSZ+1];
	struct	entry	tr;
	int	i, j;
	FILE	*fp, *fopen();

	clear();
	if(read_teams(teams)) {
		terror("ERROR opening teams file");
		return;
	}
	init();
	if(name[0]=='\0') {
		printw("Enter the name of the entrant\n\n");
		printw("Name: ");
		entrant[0]='\0';
		if(getst(PATHSZ,7,2,entrant,PATHSZ+1,NULL,LETTER_ONLY,NULL)==GET_ESCAPE) {
			de_init();
			return;
		}
	}
	else
		strcpy(entrant,name);

	if(read_entry(entrant,&tr,1)) {
		sprintf(errmsg,"There is no '%s' on file.",entrant);
		de_init();
		return;
		}

	for(i=0;i<ROUNDS;i++)
		for(j=0;j<games[i];j++)
			if(tr.round[i][j] >= TEAMS) {
				terror("ERROR this entry has not been completly entered");
				de_init();
				return;
			}
	clear();
	filename[0]='\0';
	printw("Enter the name of the output file.\n\n");
	printw("File Name: ");
	if(getst(PATHSZ,11,2,filename,PATHSZ+1,NULL,LETTER_ONLY,NULL)==GET_ESCAPE) {
		de_init();
		return;
	}
	de_init();

	for(i=0;i<strlen(filename);i++)
		if(filename[i]==' ')
			filename[i]='_';
	if((fp=fopen(filename,"w"))==NULL) {
		sprintf(errmsg,"ERROR opening file '%s', errno=%d",filename,errno);
		terror(errmsg);
		return;
	}
	for(i=0;i<4;i++) {
		fprintf(fp,"==============================================================================\n");
		fprintf(fp,"SELECTIONS FOR ENTRANT: %-12.12s     %12.12s Region            page %d\n",entrant,region_name[i],i+1);
		fprintf(fp,"==============================================================================\n");
		/* This code is a little ugly, but a fancy little
			loop would have been more time consuming that
				I felt it was worth... */
		fprintf(fp,"%s\n",teams[tr.round[0][16*i]]);
		fprintf(fp,"             %s\n",teams[tr.round[1][8*i]]);
		fprintf(fp,"%s\n",teams[tr.round[0][16*i + 1]]);
		fprintf(fp,"                          %s\n",teams[tr.round[2][4*i]]);
		fprintf(fp,"%s\n",teams[tr.round[0][16*i + 2]]);
		fprintf(fp,"             %s\n",teams[tr.round[1][8*i + 1]]);
		fprintf(fp,"%s\n",teams[tr.round[0][16*i + 3]]);
		fprintf(fp,"                                       %s\n",
			teams[tr.round[3][2*i]]);
		fprintf(fp,"%s\n",teams[tr.round[0][16*i + 4]]);
		fprintf(fp,"             %s\n",teams[tr.round[1][8*i + 2]]);
		fprintf(fp,"%s\n",teams[tr.round[0][16*i + 5]]);
		fprintf(fp,"                          %s\n",teams[tr.round[2][4*i+1]]);
		fprintf(fp,"%s\n",teams[tr.round[0][16*i + 6]]);
		fprintf(fp,"             %s\n",teams[tr.round[1][8*i + 3]]);
		fprintf(fp,"%s\n",teams[tr.round[0][16*i + 7]]);

		fprintf(fp,"                                       Final Four:  %-s\n",
			teams[tr.round[4][i]]);

		fprintf(fp,"%s\n",teams[tr.round[0][16*i + 8]]);
		fprintf(fp,"             %s\n",teams[tr.round[1][8*i + 4]]);
		fprintf(fp,"%s\n",teams[tr.round[0][16*i + 9]]);
		fprintf(fp,"                          %s\n",teams[tr.round[2][4*i+2]]);
		fprintf(fp,"%s\n",teams[tr.round[0][16*i + 10]]);
		fprintf(fp,"             %s\n",teams[tr.round[1][8*i + 5]]);
		fprintf(fp,"%s\n",teams[tr.round[0][16*i + 11]]);
		fprintf(fp,"                                       %s\n",
			teams[tr.round[3][2*i+1]]);
		fprintf(fp,"%s\n",teams[tr.round[0][16*i + 12]]);
		fprintf(fp,"             %s\n",teams[tr.round[1][8*i + 6]]);
		fprintf(fp,"%s\n",teams[tr.round[0][16*i + 13]]);
		fprintf(fp,"                          %s\n",teams[tr.round[2][4*i+3]]);
		fprintf(fp,"%s\n",teams[tr.round[0][16*i + 14]]);
		fprintf(fp,"             %s\n",teams[tr.round[1][8*i + 7]]);
		fprintf(fp,"%s\n",teams[tr.round[0][16*i + 15]]);
		if(i!=3)
			fprintf(fp,"%c",12);	/* form feed at all but last */
	}
	fprintf(fp,"\n\n\n\nFinal four on down to champion:");
	fprintf(fp,"-------------------------------\n\n\n");
	fprintf(fp,"%-s\n",teams[tr.round[4][0]]);
	fprintf(fp,"             %s\n",teams[tr.round[5][0]]);
	fprintf(fp,"%-s\n",teams[tr.round[4][1]]);
	fprintf(fp,"                          %s **** NATIONAL CHAMPION ****\n",
		teams[tr.round[6][0]]);
	fprintf(fp,"%-s\n",teams[tr.round[4][2]]);
	fprintf(fp,"             %s\n",teams[tr.round[5][1]]);
	fprintf(fp,"%-s\n",teams[tr.round[4][3]]);
	
	fclose(fp);

}

enter_picks()
{
	char	teams[TEAMS][NAMESZ+1], entrant[NAMESZ+1], title[80],
		blurb[80];
	int	round, game, p, i, save_flag=0, print_flag=1;
	struct	entry	tr;

	clear();
	init();
	printw("Enter the name of the entrant (must be a unique name)\n\n");
	printw("Name: ");
	if(getst(PATHSZ,7,2,entrant,PATHSZ+1,NULL,LETTER_ONLY,NULL)==GET_ESCAPE)
		return;
	if(!read_entry(entrant,&tr,1)) {
		printw("\n\n\nThis person is already on file.  Do you wish to edit their entry (y/n)?");
		refresh();
		if(getch()!='y') {
			de_init();
			return;
		}
	}
	else {
		save_flag = 1;
		clear_entry(&tr);
		sprintf(tr.name,entrant);
	}
	sprintf(blurb,"%s picks ",entrant);
	for(i=1;i<ROUNDS;i++) {
		sprintf(title," Enter round %d picks for entrant '%s' ",
			i,entrant);
		if(edit_round(title,blurb,i,games[i],&tr,0)) {
			printw("\n\n Do you want to save this entry (y/n)? ");
			refresh();
			if(getch()=='y')
				save_entry(&tr);
			else
				print_flag=save_flag=0;
			i=ROUNDS+1;
		}
	}
	if(i==ROUNDS)
		save_entry(&tr);
	if(save_flag)
		update_entry_list(entrant);
	if(print_flag) {
		printw("\nThe entry for '%s' has been saved.\n",entrant);
		printw("\nDo you want to create a printable file of this entry (y/n)?");
		refresh();
		if(getch()=='y')
			print_picks(entrant);
	}
	de_init();
}

save_teams(teams)
char	teams[TEAMS][NAMESZ+1];
{
	int	i;
	FILE	*fp, *fopen();
	

	if((fp=fopen(TEAM_FILE,"w"))==NULL) {
		clear();
		terror("ERROR opening teams file");
		return;
	}
	for(i=0;i<TEAMS;i++)
		fprintf(fp,"%s\n",(teams[i][0]=='\0')? "#":teams[i]);
	fclose(fp);
}

read_teams(teams)
char	teams[TEAMS][NAMESZ+1];
{
	FILE	*fp, *fopen();
	int	i, j;

	if((fp=fopen(TEAM_FILE,"r"))<0) {
		return(1);
	}
	for(i=0;i<TEAMS;i++) {
		if(fgets(teams[i],NAMESZ,fp)==NULL)
			break;
		else if(teams[i][0]=='#')
			teams[i][0]='\0';
		else
			for(j=0;j<NAMESZ;j++) 
				if(teams[i][j]=='\n') {
					teams[i][j] = '\0';
					break;
				}
	}
	for(;i<TEAMS;i++)
		teams[i][0]='\0';

	fclose(fp);
	return(0);
}

terror(s)
char	s[];
{
	char	dummy[11];

	standout();
	printw("\n\n%s\n\n",s);
	standend();
	printw("Press RETURN to continue...");
	refresh();
	scanw("%10.10s",dummy);
}

enter_teams()
{
	char	teams[TEAMS][NAMESZ+1], the_header[80];
	static char	*headers[] = {
		" ENTER TEAMS IN %s ",
		" ENTER TEAMS IN %s ",
		" ENTER TEAMS IN %s ",
		" ENTER TEAMS IN %s ",
	};
	int	i=0, done=0, r;

	read_teams(teams);	/* get currently saved team info */
	i=0;
	while(!done) {
		sprintf(the_header, headers[i], region_name[i]);
		switch(r=editlist(the_header,i*16,(i+1)*16,teams)) {
			case GET_DOWN:
			case GET_RIGHT:
				if(i!=3)
					i++;
				else {
					done=1;
					save_teams(teams);
					init_standings();
				}
				break;
			case GET_UP:
			case GET_LEFT:
				if(i)
					i--;
				break;
			case -1:		/* ABORT! */
				move(21,0);
				printw("Are you sure you want to abort (y/n)?");
				refresh();
				if(getch()=='y')
					done = 1;
				break;
			default:
				move(21,0);
				printw("editlist returns %d\n",r);
				break;
		}
	}
	return;
}

editlist(title,i1,i2,names)
char	title[], names[TEAMS][NAMESZ+1];
int	i1, i2;
{
	int	state = 0, i, j, game, rval, done=0, rcode=0, y;
	
	clear();
	standout();
	printw(title);
	standend();
	edit_msg();

	init();
	for(i=i1,j=2;i!=i2;i++,j++) {
		move(j,0);
		if((i%2) == 0) {
			game = i/2 + 1;
			printw("Game #%02d,  team #1:  ", game);
		}
		else
			printw("           team #2:  ");
		getst(NAMESZ,21,j,names[i],NAMESZ+1,NULL,SHOW,NULL);
	}
	refresh();
	i=0;
	while(!done) {
		y = 2+i;
		switch(getst(NAMESZ,21,y,names[i+i1],NAMESZ+1,NULL,ALL_ALPHA,NULL))
		{
			case GET_ESCAPE:
				done=1;
				rcode= -1;
				break;
			case GET_RETURN:
			case GET_RIGHT:
			case GET_DOWN:
				i++;
				if(i+i1 == i2) {
					done=1;
					rcode = GET_DOWN;
				}
				break;
			case GET_UP:
			case GET_LEFT:
				i--;
				if(i<0) {
					i=0;
					done=1;	
					rcode=GET_LEFT;
				}
				break;
			default:
				break;
		}
	}
	de_init();
	return(rcode);
}

edit_msg()
{
	standout();

	move(22,0);
	printw(" To change regions, scroll off the top and bottom ends of current region.  ");
	move(23,0);
	printw(" Use arrow keys for cursor movement, ESC to abort, and control-x to delete ");
	standend();
}

init_standings()
{
	struct	entry	tr;

	clear_entry(&tr);
	sprintf(tr.name,MASTER_FILE);
	save_entry(&tr);
}

clear_entry(e)
struct	entry *e;
{
	int	i, j;

	for(i=0;i<ROUNDS;i++)
		for(j=0;j<TEAMS;j++)
			e->round[i][j]= (i==0)? j: TEAMS+1;
}

read_entry(name,e,flag)
char	name[];
struct	entry	*e;
int	flag;		/* if set, no error messages */
{
	char	filename[80],tmp[NAMESZ+1], errmsg[80];
	int	fd, i;

	for(i=0;i<NAMESZ;i++)
		tmp[i]= (name[i]==' ')? '_':name[i];
	sprintf(filename,PLAYER_FILE,tmp);
	if((fd=open(filename,O_RDONLY))<0) {
		if(!flag) {
			sprintf(errmsg,"ERROR reading entry '%s', errno=%d",
				filename,errno);
			terror(errmsg);
		}
		return(1);
	}
	read(fd,e,sizeof(struct entry));
	close(fd);
	return(0);
}

save_entry(e)
struct	entry	*e;
{
	char	filename[80],tmp[NAMESZ+1], errmsg[80];
	int	fd, i;

	for(i=0;i<NAMESZ;i++)
		tmp[i]= (e->name[i]==' ')? '_':e->name[i];
	sprintf(filename,PLAYER_FILE,tmp);
	if((fd=open(filename,O_CREAT|O_WRONLY,0600))<0) {
		sprintf(errmsg,"ERROR saving entry, errno=%d",errno);
		terror(errmsg);
		return(1);
	}
	if(write(fd,e,sizeof(struct entry))!=sizeof(struct entry)) {
		sprintf(errmsg,"ERROR in write of entry, errno=%d",errno);
		terror(errmsg);
	}
	close(fd);
}

/* title is the line on top of the screen.
 * prompt is the message to display prior to showing current selection
 * rnd in the round number (1-6)
 * entires is the number of games this round
 * e is this person's entry structure (pointer to)
 * non is flag, if set then person can select neither team (results not in)
 */
edit_round(title,prompt,rnd,entries,e,non)
char	title[], prompt[];
int	entries, rnd,non;
struct	entry	*e;
{
	int	i, winner1, winner2, c, done, toggle, x, x2;
	char	teams[TEAMS][NAMESZ+1], *p;
	static	char	neither[] = "neither -- Game not played yet";

	if(read_teams(teams)) {
		terror("ERROR: have to enter tournament teams before results");
		return(1);
	}
	clear();
	standout();
	printw(title);
	standend();

	if(rnd!=1) 	/* check to see if previous round is complete */
		for(i=0;i<games[rnd-1];i++)
			if(e->round[rnd-1][i]== TEAMS+1) {
				clear();
				terror("ERROR: previous round incomplete");
				return(1);
			}

	move(22,0);
	standout();
	printw(" Use the space bar to select advancing team, RETURN once the correct team is  \n");
	printw(" displayed.   Use left arrow to go to a previously entered game. ESC to abort ");
	standend();
	for(i=0;i<games[rnd];i++) {
		move(3,0);
		printw("Game %d:\n------------\n\n",i+1);
		printw("%s\n vs                %s\n%s\n",
			teams[e->round[rnd-1][i*2]], prompt,
			teams[e->round[rnd-1][i*2+1]]);
		winner1 = e->round[rnd-1][i*2];
		winner2 = e->round[rnd-1][i*2+1];
		done = toggle = 0;
		if(e->round[rnd][i] == winner1)
			toggle = 0;
		else if(non) {
			if(e->round[rnd][i] == winner2)
				toggle = 1;
			else
				toggle = 2;
		}
		else
			toggle = 1;
		x = strlen(prompt) + 19;
		while(!done) {
			move(7,x);
			standout();
			switch(toggle) {
				case 0:
					p = teams[winner1];
					break;
				case 1:
					p = teams[winner2];
					break;
				case 2:
					p = neither;
					break;
			}
			printw("%s\n",p);
			standend();
			x2 = x + strlen(p) +1;
			move(7,x2);
			clrtoeol();	/* get rid of "standend" char on some terminals */
			refresh();
			switch(c = getch()) {
				case ' ':
					if(non)
						toggle = ++toggle % 3;
					else
						toggle = ++toggle % 2;
					break;
				case GET_RETURN:
				case GET_DOWN:
					done=1;
					break;
				case GET_LEFT:
					if(i==0)
						break;
					done = 2;
					break;
				case GET_ESCAPE:
					return(1);
			}
			if(done==2)
				i-=2;
			else
				switch(toggle) {
					case 0:
						e->round[rnd][i] = winner1;
						break;
					case 1:
						e->round[rnd][i] = winner2;
						break;
					case 2:
						e->round[rnd][i] = TEAMS+1;
						break;
				}
		}
	}
	return(0);
}

update_entry_list(name)
char	name[];
{
	FILE	*fp, *fopen();

	if((fp=fopen(ENTRY_FILE,"a"))==NULL) {
		terror("ERROR opening entry file (list of people)");
		return;
	}
	fprintf(fp,"%s\n",name);
	fclose(fp);
}
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0