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