games-request@tekred.TEK.COM (11/05/87)
Submitted by: bob@reed (Mythical Bob Ankeney)
Comp.sources.games: Volume 2, Issue 83
Archive-name: hearts/Part02
[The file 'hearts.instr' has several ^H characters in it;
don't be too suprised if they don't make it thru. -br]
#! /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 2 (of 2)."
# Contents: INSTALL Makefile connect.c defs.h hearts.c hearts.instr
# local.proto misc.h select.c sockio.c start_dist.c
# Wrapped by billr@tekred on Thu Nov 5 10:21:04 1987
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f INSTALL -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"INSTALL\"
else
echo shar: Extracting \"INSTALL\" \(497 characters\)
sed "s/^X//" >INSTALL <<'END_OF_INSTALL'
X Installation of hearts is pretty straight-forward. Just edit the
XMakefile to specify the BIN and LIB directories, and select the port
Xnumbers desired. If you wish, you can add an entry into /etc/services for
Xthe hearts distributor. If you do so, set PORT=0. Each dealer invoked
Xrequires a seperate port #, so set DIST_PORT to the starting port to be
Xused. If the distributor finds a port is already in use, it will use the
Xnext-higher one.
X
X Bob Ankeney
X ...!tektronix!reed!bob
X
END_OF_INSTALL
if test 497 -ne `wc -c <INSTALL`; then
echo shar: \"INSTALL\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Makefile -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(1938 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
X#
X# Makefile for hearts
X#
X
X# If you can edit /etc/services, define PORT as 0, else
X# define PORT as an unused internet port address (PORT = xxxx)
X#
XPORT=1030
X#
X# Dealer port numbers are handed out starting at DIST_PORT.
X# Allocate a block of ports starting at DIST_PORT = xxxx.
XDIST_PORT=1031
X
X#
X# where the distributor, dealer and instructions live
X#
X#LIB=/usr/games/lib
XLIB=.
X#
X# where the executable lives
X#
XBIN=/usr/games
X
XCFLAGS = -O
X
XHCFILES =hearts.c select.c connect.c sockio.c start_dist.c
XDCFILES =heartsd.c sockio.c
XHDCFILES =hearts_dist.c opensock.c sockio.c
X
XHOFILES =hearts.o select.o connect.o sockio.o start_dist.o
XDOFILES =heartsd.o sockio.o
XHDOFILES =hearts_dist.o opensock.o sockio.o
X
Xall: hearts heartsd hearts_dist
X
Xinstall: $(LIB)/heartsd $(LIB)/hearts_dist $(LIB)/hearts.instr $(BIN)/hearts
X
X$(LIB)/heartsd: heartsd
X cp heartsd $(LIB)
X
X$(LIB)/hearts_dist: hearts_dist
X cp hearts_dist $(LIB)
X
X$(LIB)/hearts.instr: hearts.instr
X cp hearts.instr $(LIB)
X
X$(BIN)/hearts: hearts
X cp hearts $(BIN)
X
Xhearts: $(HOFILES)
X cc $(CFLAGS) -o $@ $(HOFILES) -lcurses -ltermlib
X
Xheartsd: $(DOFILES)
X cc $(CFLAGS) -o $@ $(DOFILES)
X
Xhearts_dist: $(HDOFILES)
X cc $(CFLAGS) -o $@ $(HDOFILES)
X
Xlocal.h: .local.h
X
X.local.h: Makefile local.proto
X sed -e 's;HEARTSLIB;$(LIB);' \
X -e 's;DIST_PORTNUM;$(DIST_PORT);' \
X -e 's;PORTNUM;$(PORT);' \
X local.proto > .local.h
X -if cmp -s .local.h local.h; then\
X :;\
X else\
X cp .local.h local.h;\
X fi
X
Xalways:
X
Xhearts.o: misc.h defs.h local.h
Xheartsd.o: misc.h defs.h local.h
Xhearts_dist.o: misc.h defs.h local.h
Xselect.o: misc.h defs.h
Xsockio.o: defs.h
Xstart_dist.o: local.h
Xconnect.o: defs.h local.h
Xopensock.o: defs.h local.h
X
Xclean:
X rm -f $(HOFILES) $(DOFILES) $(HDOFILES) hearts hearts_dist local.h .local.h
X
Xlint: linthearts lintheartsd linthearts_dist
X
Xlinthearts:
X lint $(DEFS) $(HCFILES)
X
Xlintheartsd:
X lint $(DEFS) $(DCFILES)
X
Xlinthearts_dist:
X lint $(DEFS) $(HDCFILES)
X
END_OF_Makefile
if test 1938 -ne `wc -c <Makefile`; then
echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f connect.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"connect.c\"
else
echo shar: Extracting \"connect.c\" \(1157 characters\)
sed "s/^X//" >connect.c <<'END_OF_connect.c'
X/*
X * connect.c
X *
X * client connection to hearts server
X */
X
X#include <stdio.h>
X#include "defs.h"
X#include "local.h"
X
Xchar *getenv();
X
X/*
X * Make connection to host running the hearts distributor server,
X * return fd of new socket.
X */
Xconnect_to(servhost, port)
Xchar *servhost; /* name of host running server */
Xint port;
X{
X int sock;
X struct hostent *host;
X struct servent *distributor;
X struct sockaddr_in sockaddr;
X char buf[64];
X
X if ((host = gethostbyname(servhost)) == NULL) {
X perror("gethostbyname");
X exit(1);
X }
X if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
X perror("socket");
X exit(1);
X }
X bzero((char *) &sockaddr, sizeof (sockaddr));
X bcopy(host->h_addr, (char *) &sockaddr.sin_addr, host->h_length);
X sockaddr.sin_family = AF_INET;
X if (port)
X sockaddr.sin_port = htons(port);
X else {
X if ((distributor = getservbyname(SERVICE, PROTO)) == NULL) {
X (void) sprintf(buf, "%s: service not found\n", SERVICE);
X fputs(buf, stderr);
X exit(1);
X }
X sockaddr.sin_port = distributor->s_port;
X }
X if (connect(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr)) < 0) {
X (void) close (sock);
X return(0);
X }
X return(sock);
X}
END_OF_connect.c
if test 1157 -ne `wc -c <connect.c`; then
echo shar: \"connect.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f defs.h -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"defs.h\"
else
echo shar: Extracting \"defs.h\" \(772 characters\)
sed "s/^X//" >defs.h <<'END_OF_defs.h'
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/file.h>
X#include <netinet/in.h>
X#include <netdb.h>
X
X#ifndef NULL
X#define NULL 0
X#endif
X
X#define SLEN 40 /* short string */
X#define PROTO "tcp" /* protocol */
X#define SERVICE "hearts" /* official service name */
X
X#ifdef FD_SETSIZE
X
X#define WIDTH FD_SETSIZE
Xtypedef fd_set fd_type;
X
X#define fd_init(sock, fds) FD_ZERO(fds); FD_SET(sock, fds)
X#define fd_set(sock, fds) FD_SET(sock, fds)
X#define fd_zero(sock, fds) FD_ZERO(sock, fds)
X#define fd_isset(sock, fds) FD_ISSET(sock, &fds)
X
X#else
X
X#define WIDTH 32
Xtypedef int fd_type;
X
X#define fd_init(sock, fds) *fds = 1 << sock
X#define fd_set(sock, fds) *fds |= 1 << sock
X#define fd_zero(sock, fds) *fds = 0
X#define fd_isset(sock, fds) fds & (1 << sock)
X
X#endif
X
END_OF_defs.h
if test 772 -ne `wc -c <defs.h`; then
echo shar: \"defs.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f hearts.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"hearts.c\"
else
echo shar: Extracting \"hearts.c\" \(16883 characters\)
sed "s/^X//" >hearts.c <<'END_OF_hearts.c'
X/*
X * hearts - human interface to hearts program
X *
X * All smarts are in heartsd, which is invoked by initial caller of hearts.
X *
X * By Bob Ankeney or Generic Computer Products
X * Bug reports to:
X * ...!tektronix!reed!bob
X *
X *
X * Commands to hearts client (r = rank, s = suit):
X *
X * Ars Add card to hand.
X * Rrs Remove card from hand.
X * En Erase window n.
X * G Get a card.
X * Pnrs<name> Play card from player n, whose name is <name>.
X * Snpptt<name> Score points (pp) and total points (tt) for player n.
X * Mn<text> Message <text> is placed in window n.
X * X Go away.
X *
X * Messages from client:
X *
X * Prs Pass/Play card from hand.
X * M<text> Send message <text> to all players.
X *
X */
X
X#include <curses.h>
X#include <sys/errno.h>
X#include "misc.h"
X#include "defs.h"
X#include "local.h"
X
Xint dist_socket, dealer_socket;
Xchar host[20];
X
Xtypedef struct node *ptr;
X
Xstruct node {
X ptr llink, rlink;
X int rank;
X};
X
Xstruct suit_list {
X ptr head, tail;
X int length;
X}
Xmy_hand[MAX_SUIT + 1];
X
XWINDOW *card_window[MAX_SUIT + 1],
X *round_window, *lead_window, *inp_window, *text_window,
X *play_window, *tplay_window, *mesg_window, *tmesg_window,
X *header_window, *score_window,
X **window_ptr[MESG_WINDOW + 1];
X
Xint mesg_bottom, /* Bottom line of lower message window */
X tmesg_bottom; /* Bottom line of upper message window */
Xchar show_play, /* TRUE = show play/score window, FALSE = show mesg */
X first_game,
X game_over;
X
Xchar *snames[] = {
X "",
X "clubs",
X "diamonds",
X "hearts",
X "spades"
X },
X rnames[] = " 23456789TJQKA",
X got_char;
X
X
Xinit_suit(list)
Xstruct suit_list *list;
X{
X char *malloc();
X
X list->length = 0;
X list->head = (ptr) malloc(sizeof(struct node));
X list->tail = (ptr) malloc(sizeof(struct node));
X list->head->llink = NULL;
X list->tail->rlink = NULL;
X list->head->rlink = list->tail;
X list->tail->llink = list->head;
X list->head->rank = MAX_RANK + 1;
X list->tail->rank = 0;
X}
X
Xinit()
X{
X int wimp_out();
X int suit;
X char ch;
X char buffer[128];
X char *pager, *getenv();
X
X first_game = TRUE;
X
X (void) signal(SIGINT, wimp_out);
X initscr();
X clearok(stdscr, FALSE);
X crmode();
X init_windows();
X
X mvwaddstr(play_window, 0, 0, "*** The Game of Hearts ***");
X mvwaddstr(play_window, 2, 0, "Do you need instructions? ");
X wrefresh(play_window);
X ch = get_char();
X if ((ch == 'y') || (ch == 'Y')) {
X endwin();
X clear();
X refresh();
X if (!(pager = getenv ("PAGER")))
X pager = "more";
X (void) sprintf (buffer, "%s %s", pager, INSTRUCT);
X (void) system(buffer);
X crmode();
X printf ("Type any key to continue: ");
X (void) fflush (stdout);
X (void) get_char();
X }
X noecho();
X
X for (suit = CLUBS; suit <= SPADES; suit++)
X init_suit(&my_hand[suit]);
X}
X
Xget_going()
X{
X int dealer_port;
X char *name, *getenv();
X /*
X * Connect to distributor. If not available, start it.
X */
X if ((dist_socket = connect_to(host, PORT)) == 0) {
X start_distributor();
X if ((dist_socket = connect_to(host, PORT)) == 0)
X death("Can't invoke distributor!");
X }
X /*
X * Get dealer port and connect to it.
X * If port returned == 0, restart game with old dealer.
X */
X if (dealer_port = select_game()) {
X if (!first_game)
X (void) close(dealer_socket);
X if ((dealer_socket = connect_to(host, dealer_port)) == 0)
X death("Can't connect to dealer!\n");
X if ((name = getenv("HEARTS")) == NULL) /* get user name */
X if ((name = getenv("NAME")) == NULL)
X name = getenv("USER");
X write_socket(dealer_socket, name); /* tell dealer */
X }
X
X werase(play_window);
X mvwaddstr(header_window, 0, 1, "player score total");
X show_play = FALSE;
X toggle_mesg(); /* Show play and score windows */
X}
X
Xget_rank(rch)
Xchar rch;
X{
X int i;
X
X for (i = 1; i <= MAX_RANK; i++)
X if (rch == rnames[i])
X return(i);
X return(0);
X}
X
Xget_suit(sch)
Xchar sch;
X{
X int i;
X
X for (i = 1; i <= MAX_SUIT; i++)
X if (sch == *snames[i])
X return(i);
X return(0);
X}
X
X/*
X * Screen window layout
X *
X * 2 4 6 7
X * 0 0 0 0 9
X * --------------------------------------------------------
X * 0 | | | | |
X * 1 | card_window | card_window | card_window | card_window |
X * 2 | [CLUBS] | [DIAMONDS] | [HEARTS] | [SPADES] |
X * ~ ~ ~ ~ ~
X * ~ ~ ~ ~ ~
X * 16 | | | | |
X * |-------------------------------------------------------|
X * | |
X * if show_play:
X *
X * 2 5 7
X * 0 2 8 9
X * | |
X * ---------------------------------------------------------
X * 17 | round_window | |score_text_window|
X * |--------------| |-----------------|
X * 18 | | | |
X * |--------------| | |
X * 19 | lead_window | | |
X * |--------------| | |
X * 20 | inp_window | play_window | |
X * |--------------| | |
X * 21 | | | |
X * |--------------| | |
X * 22 | text_window | | |
X * |--------------|----------------------------------------|
X * 23 | | |
X * ~ ~ mesg_window ~
X * ~ ~ ~
X *LINES| | |
X * ---------------------------------------------------------
X *
X * if !show_play:
X *
X * 2 5 7
X * 0 2 8 9
X * | |
X * ---------------------------------------------------------
X * 17 | round_window | tplay_window | |
X * |--------------|----------------------------------------|
X * 18 | | |
X * |--------------| |
X * 19 | lead_window | |
X * |--------------| |
X * 20 | inp_window | tmesg_window |
X * |--------------| |
X * 21 | | |
X * |--------------| |
X * 22 | text_window | |
X * |--------------|----------------------------------------|
X * 23 | | |
X * ~ ~ mesg_window ~
X * ~ ~ ~
X *LINES| | |
X * ---------------------------------------------------------
X */
Xinit_windows()
X{
X int i;
X
X for (i = CLUBS; i <= SPADES; i++) {
X card_window[i] = newwin(17, 20, 0, (i - 1) * 20);
X leaveok(card_window[i], TRUE);
X werase(card_window[i]);
X }
X round_window = newwin(1, 22, 17, 0);
X lead_window = newwin(1, 22, 19, 0);
X inp_window = newwin(1, 22, 20, 0);
X text_window = newwin(1, 22, 22, 0);
X play_window = newwin(6, 35, 17, 23);
X tplay_window = newwin(1, 57, 17, 23);
X header_window = newwin(1, 22, 17, 58);
X score_window = newwin(5, 22, 18, 58);
X mesg_window = newwin(0, 57, 23, 23);
X tmesg_window = newwin(5, 57, 18, 23);
X mesg_bottom = LINES - 24;
X tmesg_bottom = 4;
X scrollok(mesg_window, TRUE);
X scrollok(tmesg_window, TRUE);
X window_ptr[ROUND_WINDOW] = &round_window;
X window_ptr[LEAD_WINDOW] = &lead_window;
X window_ptr[INP_WINDOW] = &inp_window;
X window_ptr[TEXT_WINDOW] = &text_window;
X window_ptr[PLAY_WINDOW] = &play_window;
X window_ptr[SCORE_WINDOW] = &score_window;
X window_ptr[MESG_WINDOW] = &mesg_window;
X}
X
X/*
X * toggle_mesg - toggle whether showing message window or score/play windows
X */
Xtoggle_mesg()
X{
X if (show_play) {
X touchwin(tplay_window);
X touchwin(tmesg_window);
X wrefresh(tplay_window);
X wrefresh(tmesg_window);
X }
X else {
X touchwin(play_window);
X touchwin(header_window);
X touchwin(score_window);
X wrefresh(play_window);
X wrefresh(header_window);
X wrefresh(score_window);
X }
X show_play = !show_play;
X}
X
X/*
X * ovl_refresh - refresh window only if visible
X */
Xovl_refresh(window_num)
Xint window_num;
X{
X switch (window_num) {
X case PLAY_WINDOW:
X if (show_play)
X wrefresh(play_window);
X break;
X case SCORE_WINDOW:
X if (show_play)
X wrefresh(score_window);
X break;
X default:
X wrefresh(*window_ptr[window_num]);
X }
X}
X
X/*
X * scroll_mesg - scroll mesg_window onto tmesg_window
X */
Xscroll_mesg()
X{
X int i;
X char ch;
X
X wmove(tmesg_window, tmesg_bottom, 56);
X scroll(tmesg_window);
X wmove(tmesg_window, tmesg_bottom, 0);
X for (i = 0; i < 56; i++) {
X wmove(mesg_window, 0, i);
X ch = winch(mesg_window);
X waddch(tmesg_window, ch);
X }
X scroll(mesg_window);
X if (!show_play)
X wrefresh(tmesg_window);
X}
X
Xput_card(window, y, x, rank, suit)
XWINDOW *window;
Xint y, x,
Xrank, suit;
X{
X mvwaddstr(window, y, x, "+-----+");
X mvwaddstr(window, y + 1, x, "| |");
X mvwaddstr(window, y + 2, x, "| |");
X mvwaddstr(window, y + 3, x, "| |");
X mvwaddstr(window, y + 4, x, "+-----+");
X if ((suit == HEARTS) || (suit == DIAMONDS))
X wstandout(window);
X mvwaddch(window, y + 1, x + 1, rnames[rank]);
X waddch(window, *snames[suit]);
X mvwaddch(window, y + 3, x + 4, rnames[rank]);
X waddch(window, *snames[suit]);
X wstandend(window);
X}
X
Xprint_cards(suit)
Xint suit;
X{
X int y, x;
X ptr p;
X
X werase(card_window[suit]);
X x = y = 0;
X p = my_hand[suit].head->rlink;
X while (p->rank) {
X if (x == 7) {
X ++x;
X y = 0;
X }
X put_card(card_window[suit], y, x++, p->rank, suit);
X y += 2;
X p = p->rlink;
X }
X wrefresh(card_window[suit]);
X}
X
Xget_char()
X{
X char ch;
X
X if (read(0, &ch, 1) == -1) {
X perror("read");
X abort();
X }
X return(ch);
X}
X
Xread_char()
X{
X char ch;
X
X while (!got_char)
X scan();
X ch = got_char;
X got_char = FALSE;
X return(ch);
X}
X
Xread_card()
X{
X int rank, suit;
X char buf[64];
X
X do {
X do {
X werase(inp_window);
X wrefresh(inp_window);
X buf[0] = 'P';
X buf[1] = read_char(); /* Get rank (not smelly) */
X if (buf[1] >= 'a')
X buf[1] += 'A' - 'a';
X if (!(rank = get_rank(buf[1]))) {
X werase(text_window);
X waddstr(text_window, "Bad rank!");
X wrefresh(text_window);
X }
X }
X while (!rank);
X werase(text_window);
X wrefresh(text_window);
X wprintw(inp_window, "%c ", buf[1]);
X wrefresh(inp_window);
X buf[2] = read_char(); /* Get suit (not tuxedo) */
X if ((buf[2] >= 'A') && (buf[2] <= 'Z'))
X buf[2] += 'a' - 'A';
X if (!(suit = get_suit(buf[2])) &&
X (buf[2] != _tty.sg_erase) && (buf[2] != _tty.sg_kill)) {
X werase(text_window);
X waddstr(text_window, "Bad suit!");
X wrefresh(text_window);
X }
X }
X while (!suit);
X wprintw(inp_window, "of %s", snames[suit]);
X wrefresh(inp_window);
X buf[3] = '\0';
X write_socket(dealer_socket, buf);
X}
X
Xenter_card(rank, suit)
Xint rank, suit;
X{
X ptr p, p1;
X
X p = my_hand[suit].head;
X ++my_hand[suit].length;
X while (p->rank > rank)
X p = p->rlink;
X p1 = (ptr) malloc(sizeof(struct node));
X p1->llink = p->llink;
X p1->llink->rlink = p1;
X p->llink = p1;
X p1->rlink = p;
X p1->rank = rank;
X}
X
Xremove_node(p)
Xptr p;
X
X{
X p->llink->rlink = p->rlink;
X p->rlink->llink = p->llink;
X free((char *) p);
X}
X
X
Xptr
Xfind_card(rank_to_play, suit_to_play)
Xint rank_to_play, suit_to_play;
X{
X ptr card_to_play;
X
X card_to_play = my_hand[suit_to_play].head->rlink;
X while (card_to_play->rank != rank_to_play)
X card_to_play = card_to_play->rlink;
X remove_node(card_to_play);
X --my_hand[suit_to_play].length;
X return(card_to_play);
X}
X
Xdo_command(buf)
Xchar *buf;
X{
X char rch, sch;
X int player, suit, pts, total_pts, window_num;
X int temp_y, temp_x;
X
X switch (buf[0]) {
X case 'A' : /* Add card to hand */
X enter_card(get_rank(buf[1]), suit = get_suit(buf[2]));
X print_cards(suit);
X break;
X
X case 'R' : /* Remove card from hand */
X suit = get_suit(buf[2]);
X remove_node(find_card(get_rank(buf[1]), suit));
X print_cards(suit);
X break;
X
X case 'E' : /* Erase window */
X window_num = buf[1] - '0';
X if (window_num == PLAY_WINDOW) {
X werase(tplay_window);
X if (!show_play)
X wrefresh(tplay_window);
X }
X werase(*window_ptr[window_num]);
X ovl_refresh(window_num);
X break;
X
X case 'G' : /* Get card */
X read_card();
X break;
X
X case 'P' : /* Play card from player */
X (void) sscanf(buf+1, "%1d %c %c", &player, &rch, &sch);
X /*
X * Update standard play window
X */
X put_card(play_window, 0, (player - 1) * 9,
X get_rank(rch), get_suit(sch));
X if (buf[4] != '\0')
X mvwaddstr(play_window, 5, (player - 1) * 9, buf + 4);
X /*
X * Update alternate play window
X */
X if ((sch == 'h') || (sch == 'd'))
X wstandout(tplay_window);
X mvwaddch(tplay_window, 0, (player - 1) * 9, rch);
X waddch(tplay_window, sch);
X wstandend(tplay_window);
X if (show_play)
X wrefresh(play_window);
X else
X wrefresh(tplay_window);
X sleep(1);
X break;
X
X case 'S' : /* Score points for player */
X (void) sscanf(buf+1, "%1d %2d %2d", &player, &pts, &total_pts);
X mvwaddstr(score_window, player - 1, 1, " ");
X mvwaddstr(score_window, player - 1, 1, buf + 6);
X mvwprintw(score_window, player - 1, 9, " %2d %2d",
X pts, total_pts);
X ovl_refresh(SCORE_WINDOW);
X break;
X
X case 'M' : /* Print message in window */
X getyx(curscr, temp_y, temp_x);
X window_num = buf[1] - '0';
X if (window_num == MESG_WINDOW) {
X scroll_mesg();
X mvwaddstr(mesg_window, mesg_bottom, 0, buf + 2);
X }
X else {
X werase(*window_ptr[window_num]);
X mvwaddstr(*window_ptr[window_num], 0, 0, buf + 2);
X }
X ovl_refresh(window_num);
X move(temp_y, temp_x);
X refresh();
X break;
X
X case 'X' : /* Game over */
X if (!show_play)
X toggle_mesg();
X werase(round_window);
X wrefresh(round_window);
X werase(lead_window);
X wstandout(lead_window);
X mvwaddstr(lead_window, 0, 0, "--More--");
X wstandend(lead_window);
X wrefresh(lead_window);
X (void) get_char();
X first_game = FALSE;
X game_over = TRUE;
X }
X}
X
X/*
X * Scan input for redraw screen requests or ':' messages.
X * Also scan socket for incoming commands.
X */
Xscan()
X{
X int i, temp_y, temp_x;
X char buf[64];
X fd_type read_fd;
X int nready;
X extern int errno;
X
X fd_init(dealer_socket, &read_fd);
X if (!got_char)
X fd_set(0, &read_fd);
X do {
X nready = select(WIDTH, &read_fd, (fd_type *) 0, (fd_type *) 0,
X (struct timeval *) 0);
X }
X while (nready == -1 && errno == EINTR);
X if (nready == 0)
X return;
X if (fd_isset(0, read_fd)) {
X got_char = get_char();
X getyx(curscr, temp_y, temp_x);
X switch (got_char) {
X case '\f' :
X wrefresh(curscr); /* Redraw screen */
X got_char = FALSE;
X break;
X
X case ' ' :
X case '\t' :
X case '\n' :
X case '\r' :
X got_char = FALSE; /* Ignore white space */
X break;
X
X case 'M' :
X case 'm' :
X toggle_mesg();
X got_char = FALSE;
X break;
X
X case ':' :
X scroll_mesg(); /* Message to all players */
X mvwaddstr(mesg_window, mesg_bottom, 0, "message:");
X wrefresh(mesg_window);
X buf[0] = 'M';
X for (i = 1; (i < 48) && ((buf[i] = get_char()) != '\n');
X i++) {
X if (buf[i] == _tty.sg_erase) {
X i -= 2;
X if (i < 0)
X i = 0;
X else {
X wmove(mesg_window, mesg_bottom, i+8);
X wdelch(mesg_window);
X }
X }
X else {
X if (buf[i] == _tty.sg_kill) {
X wmove(mesg_window, mesg_bottom, 8);
X wclrtoeol(mesg_window);
X i = 0;
X }
X else
X mvwaddch(mesg_window, mesg_bottom, i + 7, buf[i]);
X }
X wrefresh(mesg_window);
X }
X buf[i] = '\0';
X write_socket(dealer_socket, buf);
X got_char = FALSE;
X }
X move(temp_y, temp_x);
X refresh();
X }
X if (fd_isset(dealer_socket, read_fd)) {
X if (!read_socket(dealer_socket, buf))
X death("Dealer died!!");
X do_command(buf);
X }
X}
X
Xclose_windows()
X{
X (void) signal(SIGINT, SIG_IGN);
X clear();
X refresh();
X (void) fflush(stdout);
X endwin();
X}
X
Xdeath(buf)
Xchar *buf;
X{
X close_windows();
X printf("%s\n", buf);
X exit(1);
X}
X
Xwimp_out()
X{
X close_windows();
X exit(0);
X}
X
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X if (argc > 2) {
X fprintf(stderr, "usage: %s [hostname]\n", *argv);
X exit(1);
X }
X if (argc == 2)
X (void) strcpy (host, *++argv);
X else
X (void) gethostname(host, 20); /* host is this machine */
X
X init();
X
X for (;;) {
X game_over = FALSE;
X get_going();
X do {
X scan();
X }
X while (!game_over);
X }
X}
X
END_OF_hearts.c
if test 16883 -ne `wc -c <hearts.c`; then
echo shar: \"hearts.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f hearts.instr -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"hearts.instr\"
else
echo shar: Extracting \"hearts.instr\" \(1833 characters\)
sed "s/^X//" >hearts.instr <<'END_OF_hearts.instr'
X T_h_e_ G_a_m_e_
X
X Hearts is yet another benign, mindless card game. This particular
Xvariation is four-handed, with up to four human players allowed. The
Xremaining hands are played by the computer. Players may join at any time.
XA computer player will replace any player that leaves the game.
X The object of the game is to score as few points as possible. Points
Xare scored by taking tricks with either hearts in them (each heart
Xscores one point), or the Queen of Spades (scores 13). A player that
Xtakes all 26 points is said to "shoot the moon" and scores zero, while
Xall opponents score 26.
X
X P_a_s_s_i_n_g_
X
X Four hands are played, in which each player is dealt 13 cards.
XEach player passes three cards to another player, except on the final
Xround, when no cards are passed.
X
X T_h_e_ P_l_a_y_
X
X The lead card is the 2 of Clubs. Each player must follow suit, if
Xpossible. Otherwise, any card may be played. Points may not be dumped
Xthe first round. Hearts may not be led until a heart has been dumped.
X Play continues till all 13 rounds have been played.
X
X N_o_t_e_s_
X
X To specify a card, the player must enter the card rank (2-9, T, J,
XQ, K, or A) and, if needed, the first letter of the suit (C, D, H, or S).
XFor example, entering "jd" will appear as "Jack of Diamonds".
X
X Messages may be passed to other players by typing ':' followed by the
Xmessage. A scrolling message window exists consisting of lines 23 to the
Xbottom of the screen (just 1 line on 24-line terminals). A hidden window
Xbehind the play and score windows contains an additional 5 message lines,
Xabove which are the cards being played. To toggle this window, type 'm'.
X
X
END_OF_hearts.instr
echo shar: 26 control characters may be missing from \"hearts.instr\"
if test 1833 -ne `wc -c <hearts.instr`; then
echo shar: \"hearts.instr\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f local.proto -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"local.proto\"
else
echo shar: Extracting \"local.proto\" \(286 characters\)
sed "s/^X//" >local.proto <<'END_OF_local.proto'
X/*
X * local.proto
X *
X * prototype for local.h -- creates pathnames for various files
X * from the makefile.
X */
X
X#define INSTRUCT "HEARTSLIB/hearts.instr"
X#define HEARTSD "HEARTSLIB/heartsd"
X#define HEARTS_DIST "HEARTSLIB/hearts_dist"
X#define DIST_PORT DIST_PORTNUM
X#define PORT PORTNUM
END_OF_local.proto
if test 286 -ne `wc -c <local.proto`; then
echo shar: \"local.proto\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f misc.h -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"misc.h\"
else
echo shar: Extracting \"misc.h\" \(480 characters\)
sed "s/^X//" >misc.h <<'END_OF_misc.h'
X
X#include <stdio.h>
X#include <signal.h>
X#include <strings.h>
X#include <sys/time.h>
X
X#ifndef TRUE
X#define TRUE 1
X#endif
X
X#ifndef FALSE
X#define FALSE 0
X#endif
X
X
X#define CLUBS 1
X#define DIAMONDS 2
X#define HEARTS 3
X#define SPADES 4
X
X#define MIN_RANK 1 /* 2 */
X#define MAX_RANK 13 /* Ace */
X#define MAX_SUIT 4 /* 1..4 */
X
X#define ROUND_WINDOW 1
X#define LEAD_WINDOW 2
X#define INP_WINDOW 3
X#define TEXT_WINDOW 4
X#define PLAY_WINDOW 5
X#define SCORE_WINDOW 6
X#define MESG_WINDOW 7
X
END_OF_misc.h
if test 480 -ne `wc -c <misc.h`; then
echo shar: \"misc.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f select.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"select.c\"
else
echo shar: Extracting \"select.c\" \(7179 characters\)
sed "s/^X//" >select.c <<'END_OF_select.c'
X#include <curses.h>
X#include "misc.h"
X#include "defs.h"
X
Xextern WINDOW *card_window[],
X *round_window, *lead_window, *text_window, *play_window;
X
Xextern int dist_socket;
Xextern char first_game;
X
Xtypedef struct table *table_ptr;
X
Xstruct table {
X table_ptr next_table; /* Points to next table entry */
X int table_id; /* Unique ID from distributor */
X char player_name[4][9]; /* Player names */
X int hand; /* Current table hand */
X int round; /* Current table round */
X char closed; /* If game over */
X};
X
Xtable_ptr first_table,
X cur_table;
X
Xint table_count, /* # tables existing */
X cur_screen_table, /* nth table shown as table 1 */
X screen_table_id[8]; /* table_id of tables on screen */
X
Xchar buf[64];
X
X
X/*
X * Find table given unique table_id in buf[1].
X */
Xtable_ptr
Xfind_table(buf)
Xchar *buf;
X{
X table_ptr cur_table;
X int table_num;
X
X (void) sscanf(buf + 1, "%d", &table_num);
X for (cur_table = first_table;
X cur_table && cur_table->table_id != table_num;
X cur_table = cur_table->next_table)
X ;
X return(cur_table);
X}
X
X/*
X * Create new table given table_id in buf[1]. Return pointer to new table.
X */
Xtable_ptr
Xnew_table(buf)
Xchar *buf;
X{
X table_ptr cur_ptr, new_table_ptr;
X int i, table_num;
X char *malloc();
X
X (void) sscanf(buf + 1, "%d", &table_num);
X new_table_ptr = (table_ptr) malloc(sizeof(struct table));
X new_table_ptr->next_table = NULL;
X new_table_ptr->table_id = table_num;
X new_table_ptr->closed = FALSE;
X for (i = 0; i < 4; i++)
X (void) strcpy(new_table_ptr->player_name[i], "<empty>");
X if (first_table) {
X for (cur_ptr = first_table; cur_ptr->next_table;
X cur_ptr = cur_ptr->next_table)
X ;
X cur_ptr->next_table = new_table_ptr;
X }
X else
X first_table = new_table_ptr;
X ++table_count;
X return(new_table_ptr);
X}
X
X/*
X * Update current table entry based on buf. Return table # modified.
X */
Xupdate_table(buf)
Xchar *buf;
X{
X int i;
X table_ptr tmp_table;
X
X switch (buf[0]) {
X case 't' :
X if ((cur_table = find_table(buf)) == NULL)
X cur_table = new_table(buf);
X break;
X case 'h' :
X (void) sscanf(buf + 1, "%d", &cur_table->hand);
X break;
X case 'r' :
X (void) sscanf(buf + 1, "%d", &cur_table->round);
X break;
X case 'p' :
X (void) strcpy(cur_table->player_name[buf[1] - '0'], buf + 2);
X break;
X case 'x' :
X if (tmp_table = find_table(buf)) {
X for (i = 0; i < 8; i++)
X if (screen_table_id[i] = tmp_table->table_id)
X screen_table_id[i] = 0;
X tmp_table->table_id = 0;
X tmp_table->closed = TRUE;
X }
X }
X}
X
X/*
X * show_table - display table which is position table_pos on screen.
X */
Xshow_table(cur_ptr, table_pos)
Xtable_ptr cur_ptr;
Xint table_pos;
X{
X int window_num, window_pos;
X int i;
X
X window_num = table_pos % 4 + 1;
X window_pos = (table_pos + 4) & 8;
X for (i = 0; i < 6; i++) {
X wmove(card_window[window_num], window_pos + i, 0);
X wclrtoeol(card_window[window_num]);
X }
X mvwprintw(card_window[window_num], window_pos++, 0,
X " Table %d", table_pos + 1);
X if (cur_ptr->closed)
X mvwaddstr(card_window[window_num], window_pos++, 0,
X " <game over>");
X else {
X if (cur_ptr->hand == 0)
X mvwaddstr(card_window[window_num], window_pos++, 0,
X " <starting>");
X else
X mvwprintw(card_window[window_num], window_pos++, 0,
X "Hand: %d Round: %d",
X cur_ptr->hand, cur_ptr->round);
X for (i = 0; i <4; i++)
X mvwaddstr(card_window[window_num], window_pos++, 5,
X cur_ptr->player_name[i]);
X }
X wrefresh(card_window[window_num]);
X}
X
X/*
X * show_tables - display up to 8 tables starting with table # start_id.
X */
Xshow_tables(start_id)
Xint start_id;
X{
X table_ptr cur_ptr;
X int cur_id, i;
X
X for (i = 0; i < 8; i++)
X screen_table_id[i] = 0;
X werase(round_window);
X if (table_count)
X mvwprintw(round_window, 0, 0, "Page %d of %d",
X (start_id + 7) / 8, (table_count + 7) / 8);
X wrefresh(round_window);
X cur_ptr = first_table;
X for (cur_id = 1; cur_id < start_id; cur_id++)
X cur_ptr = cur_ptr->next_table;
X for (cur_id = 0; (cur_id < 8) && cur_ptr;
X cur_ptr = cur_ptr->next_table) {
X screen_table_id[cur_id] = cur_ptr->table_id;
X show_table(cur_ptr, cur_id++);
X }
X}
X
Xask_option()
X{
X werase(lead_window);
X mvwaddstr(lead_window, 0, 0, "Option: ");
X wrefresh(lead_window);
X}
X
Xshow_options()
X{
X werase(play_window);
X mvwaddstr(play_window, 0, 0, "Options are:");
X if (!first_game)
X mvwaddstr(play_window, 1, 0, "<A>nother game");
X mvwaddstr(play_window, 2, 0, "<N>ew game");
X if (table_count)
X mvwaddstr(play_window, 3, 0, "<J>oin game");
X if (table_count > 8)
X mvwaddstr(play_window, 4, 0, "<M>ore games");
X mvwaddstr(play_window, 5, 0, "<Q>uit");
X wrefresh(play_window);
X ask_option();
X}
X
Xdist_died()
X{
X death("Distributor died!!");
X}
X
Xselect_game()
X{
X int dealer_port;
X fd_type read_fd;
X int i;
X char ch;
X char joined, joining;
X table_ptr temp_table;
X
X clear();
X refresh();
X /*
X * Get current games info
X */
X do {
X if (read_socket(dist_socket, buf) == 0)
X dist_died();
X if (buf[0] != 'g')
X update_table(buf);
X }
X while (buf[0] != 'g');
X
X show_tables(cur_screen_table = 1);
X show_options();
X
X /*
X * Wait for user input or table update info
X */
X joined = joining = FALSE;
X
X do {
X fd_init(0, &read_fd); /* stdin */
X fd_set(dist_socket, &read_fd);
X if (select(WIDTH, &read_fd, (fd_type *) 0, (fd_type *) 0,
X (struct timeval *) 0) == -1)
X dist_died();
X if (fd_isset(dist_socket, read_fd)) {
X if (read_socket(dist_socket, buf) == 0)
X dist_died();
X i = update_table(buf);
X show_tables(cur_screen_table);
X }
X if (fd_isset(0, read_fd)) {
X ch = get_char();
X werase(text_window);
X wrefresh(text_window);
X switch (ch) {
X case 'Q' :
X case 'q' :
X wimp_out();
X case 'A' :
X case 'a' :
X if (!first_game)
X joined = TRUE;
X break;
X case 'N' :
X case 'n' :
X write_socket(dist_socket, "n");
X joined = TRUE;
X break;
X case 'J' :
X case 'j' :
X mvwaddstr(lead_window, 0, 0, "Join table #:");
X wrefresh(lead_window);
X joining = TRUE;
X break;
X case 'M' :
X case 'm' :
X if (table_count > 8) {
X if ((cur_screen_table += 8) > table_count)
X cur_screen_table = 1;
X for (i = CLUBS; i <= SPADES; i++) {
X werase(card_window[i]);
X wrefresh(card_window[i]);
X }
X show_tables(cur_screen_table);
X }
X break;
X default:
X if (joining && (ch >= '1') && (ch <= '8')) {
X if (i = screen_table_id[ch - '1']) {
X (void) sprintf(buf, "j%d", i);
X write_socket(dist_socket, buf);
X joined = TRUE;
X }
X else {
X mvwaddstr(text_window, 0, 0, "Table not open.");
X wrefresh(text_window);
X ask_option();
X }
X }
X else {
X mvwaddstr(text_window, 0, 0, "Huh?");
X wrefresh(text_window);
X ask_option();
X }
X joining = FALSE;
X break;
X }
X }
X }
X while (!joined);
X
X /*
X * Now free up malloced table space
X */
X while (first_table) {
X temp_table = first_table;
X first_table = first_table->next_table;
X free ((char *) temp_table);
X }
X clear();
X refresh();
X
X if (!first_game && ((ch == 'a') || (ch == 'A')))
X /*
X * Play another game with current dealer.
X */
X dealer_port = 0;
X else {
X if (read_socket(dist_socket, buf) == 0)
X dist_died();
X (void) sscanf(buf + 1, "%d", &dealer_port);
X }
X (void) close(dist_socket);
X return(dealer_port);
X}
END_OF_select.c
if test 7179 -ne `wc -c <select.c`; then
echo shar: \"select.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f sockio.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"sockio.c\"
else
echo shar: Extracting \"sockio.c\" \(676 characters\)
sed "s/^X//" >sockio.c <<'END_OF_sockio.c'
X#include <stdio.h>
X/*
X * Routines to send and receive on sockets. Four bytes of length are
X * sent, followed by the null terminated string.
X *
X */
Xread_socket(s, buf)
Xint s; /* socket to talk on */
Xchar *buf; /* string to send */
X{
X int nbytes;
X
X if (read(s, (char *) &nbytes, sizeof(int)) != sizeof (int))
X return 0;
X nbytes = ntohl(nbytes);
X if (read(s, buf, nbytes) != nbytes)
X return 0;
X return nbytes;
X}
X
X
Xwrite_socket(s, buf)
Xint s; /* socket to talk on */
Xchar *buf; /* string to read on */
X{
X int nbytes, netnbytes;
X
X nbytes = strlen(buf) + 1;
X netnbytes = htonl(nbytes);
X (void) write(s, (char *) &netnbytes, sizeof(int));
X (void) write(s, buf, nbytes);
X}
END_OF_sockio.c
if test 676 -ne `wc -c <sockio.c`; then
echo shar: \"sockio.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f start_dist.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"start_dist.c\"
else
echo shar: Extracting \"start_dist.c\" \(328 characters\)
sed "s/^X//" >start_dist.c <<'END_OF_start_dist.c'
X/*
X * autostart - start up the distributor if it's not around.
X */
X
X#include "local.h"
X
Xstart_distributor ()
X{
X int pid;
X
X switch (pid = fork()) {
X case 0:
X (void) setpgrp (0, getpid());
X execl (HEARTS_DIST, "hearts_dist", 0);
X exit (1);
X case -1:
X perror ("fork");
X exit (1);
X default:
X while (wait (0) != pid)
X ;
X }
X}
END_OF_start_dist.c
if test 328 -ne `wc -c <start_dist.c`; then
echo shar: \"start_dist.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
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