games-request@tekred.TEK.COM (09/18/87)
Submitted by: Dan Heller <island!argv%maui@sun.com> Comp.sources.games: Volume 2, Issue 51 Archive-name: dots2 [Here is a revised version of the dots game that Dan submitted earlier. -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 shell archive." # Contents: Makefile board.c comp.c comp2.c dots.doc dots.h findem.c # main.c menu.c misc.c person.c save.c score.c sockt.c # Wrapped by billr@tekred on Thu Sep 17 16:35:24 1987 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f Makefile -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"Makefile\" else echo shar: Extracting \"Makefile\" \(2852 characters\) sed "s/^X//" >Makefile <<'END_OF_Makefile' X# X# Makefile for dots X# X# Dots and Boxes -- the program for UNIX was programmed by Dan Heller and X# Don Hatch Spring, 1984 with further developments continually. X# Sockets Implemented by Dan Heller in May, 1985. X# X# This program was originally written on a PDP-11 under UNIX V7. X# X# If you are on a berkeley unix system, then you should have -DBSD defined X# below and use the appropriate OBJS (see notes below). If you are using X# a system-V unix then you should define -DSYSV and use those OBJS. X# X# Installation is so easy that there's no need for a README or anything, X# Be sure to edit dots.h and change some of the constants to whatever X# pathnames you'd like them to be and note VPRINTF and DESTDIR are defined X# here. X# X# Rules for defining VPRINTF: X# 1) you are a system-v (xenix or otherwise) machine. X# 2) you are on a sun running 3.0 or higher. X# DO NOT define VPRINTF if you are on a vax or running 4.[23] or something. X# If you are unsure, try: X# % ar t /lib/libc.a | grep vprintf X# If you don't get output, you don't have it. If you do have it, you'll X# get several lines of output (vprintf.o vsprintf.o). X# X# This code is intended for public consumption and modifications are X# enoucraged. If you do make mods, I'd love to hear about them and X# include in later releases (interest providing). X# X# Since everything includes dots.h a make depend is senseless. If you X# make changes to defines, grep the files to note which are affected X# and remake them. If you change variables, use grep on .c files or use X# "nm" on the .o files to find which files use them. X# X# The file "dots.doc" has more information on how to play. X# X# comments, etc... to: Dan Heller X# island!argv@sun.com argv@spam.istc.sri.com X# X# Thanx to Jay Libove for his port to XENIX (System-V) X# Thanx to Bruno Wolff for general bug fixes. X X# for xenix systems or (hopefully) any sys-v unix, use these CFLAGS and LDFLAGS X# CFLAGS= -O -DSYSV -Ml -DVPRINTF X# LDFLAGS= -s -Ml X X# BSD systems should use these CFLAGS and LDFLAGS XCFLAGS= -O -DBSD XLDFLAGS= -s X XDESTDIR= /usr/games XLINTFLAGS= -bxah -Dlint XLIBES = -lcurses -ltermlib X XPROG=dots X XSRCS=main.c comp.c comp2.c board.c person.c misc.c menu.c save.c score.c \ X sockt.c findem.c X X# SYSV (xenix) *do not* use sockt.o and findem.o -- BSD systems *do use* them. X# OBJS=main.o comp.o comp2.o board.o person.o misc.o menu.o save.o score.o XOBJS=main.o comp.o comp2.o board.o person.o misc.o menu.o save.o score.o \ X sockt.o findem.o X X${PROG}: ${OBJS} X @echo Loading... X @cc ${LDFLAGS} ${OBJS} ${LIBES} -o ${PROG} X Xinstall: ${PROG} X /bin/mv ${PROG} ${DESTDIR}/${PROG} X chmod 711 ${DESTDIR}/${PROG} X Xtags: X ctags dots.h ${SRCS} X Xclean: X rm -f core ${OBJS} ${PROG} X Xlint: X lint ${LINTFLAGS} ${SRCS} X Xtar: X tar fcv DOTS Makefile dots.h $(SRCS) tags X Xshar: X shar Makefile dots.doc dots.h $(SRCS) > dots.shar END_OF_Makefile if test 2852 -ne `wc -c <Makefile`; then echo shar: \"Makefile\" unpacked with wrong size! fi # end of overwriting check fi if test -f board.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"board.c\" else echo shar: Extracting \"board.c\" \(3320 characters\) sed "s/^X//" >board.c <<'END_OF_board.c' X/* board.c routines that deal with the playing board's display or data */ X X#include "dots.h" X Xsetup() X{ X Length = Width = 0; X comptally = persontally = 0; X xposit = 2, yposit = 1; X X mvprintw(LINES - 6, 0, "Enter LENGTH of board (%d - %d).", X (level == DUMB)? MINL : H_MINL, MAXL); X do { X mvaddstr(LINES - 4, 0, "->> "), clrtoeol(), refresh(); X x_start = COLS / 2 - (Length = get_dimensions()) * 2; X } while (Length > MAXL || (level == DUMB && Length < MINL) || X (level != DUMB && Length < H_MINL)); X X mvprintw(LINES - 6, 0, "Enter WIDTH of board (%d - %d).", X (level==DUMB)? MINW:H_MINW, MAXW), clrtoeol(); X do { X mvaddstr(LINES - 4, 0, "->> "), clrtoeol(), refresh(); X y_start = LINES / 2 - (Width = get_dimensions()); X } while (Width > MAXW || (level == DUMB && Width < MINW) || X (level != DUMB && Width < H_MINW)); X X mvprintw(LINES - 6, 0, "Length is %d, width is %d.", Length, Width); X clrtoeol(), refresh(); X if (mode == INTERACTIVE) X mvprintw(LINES-4, 0, X "Your boxes will be initialed with \"%c\"",Initial[US]), clrtoeol(); X msg("Hit any key to continue. "); X getchar(); X} X Xfree_board() X{ X register int x, y; X X for (x = 0; x <= Length * 2; ++x) X for (y = 0; y <= Width * 2; ++y) X board[x][y] = FREE; X no_good_moves = control_already_established = 0; X} X X/* special signal catcher for get dimensions prompt. If user got here X * by mistake (entering a level unintentionally), he can ^C to get back X * to the main menu. You can't get here without going thru the menu, X * so don't worry about getting a longjump botch. longjmp with value X * of 2 to indicate that it's not necessary to redisplay the menu. X */ Xdont_ask() X{ X (void) signal(SIGINT, onintr); X longjmp(menu_jmp, 2); X} X Xget_dimensions() X{ X char string[10]; X register char c; X register int place_on_line = 0, x = 0; X X (void) signal(SIGINT, dont_ask); X X string[0] = '\0'; X X move(LINES - 4, 4), clrtoeol(); X refresh(); X while ((c = getchar()) != '\n') { X if (c == erase_char || c == '\027') X if (place_on_line != 0) { X string[--x] = '\0'; X --place_on_line; X addstr("\b \b"); X refresh(); X } else X continue; X else if (isdigit(c)) { X if (place_on_line == 4) X continue; X place_on_line++; X addch(string[x++] = c); X refresh(); X } X } X string[x] = '\0'; X (void) signal(SIGINT, onintr); X return atoi(string); X} X Xdrawboard() X{ X register int x, y; X X clear(); X for (y = 1; y < 2 * Width; y++) X for (x = 1; x < 2 * Length; x++) { X move(y_start + (y - 1), x_start + (2 * x - 2)); X if (iseven(x) && isodd(y) && board[x][y] == USED) X addstr("\b---\b\b"); X if (iseven(y) && isodd(x) && board[x][y] == USED) X addch('|'); X else if (iseven(x) && iseven(y) && closure(GOOD, x, y) == 4) X putinitial(x, y, board[x][y]); X else if (isodd(x) && isodd(y)) X addch('*'); X } X if (mode == TWOPLAYER) { X mvaddstr(LINES - 3, 0, "Your Messages: "); X mvprintw(LINES - 2, 0, "%s's Messages: ", opponent); X } X} X Xchlevel(c) X{ X if (!sure(c)) X return; X level = (level + 1) % 3; X bottom_line(); X} X Xsure(c) Xchar c; X{ X register int count; X register char C; X X for (count = 0; count <= 3; ++count) X if ((C = getchar()) != c) { X ungetc(C, stdin); X return FALSE; X } X return TRUE; X} END_OF_board.c if test 3320 -ne `wc -c <board.c`; then echo shar: \"board.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f comp.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"comp.c\" else echo shar: Extracting \"comp.c\" \(8116 characters\) sed "s/^X//" >comp.c <<'END_OF_comp.c' X/* COMP.C */ X X#include "dots.h" X Xcompmove() X{ X bottom_line(); X close_boxes(); X if (!board_is_full()) X if (!find_good_move(GOOD)) X force_move(); X} X Xclose_boxes() X{ X Bingo.x = Bingo.y = 0; X dX_found = 0; X if (level == DUMB || cntrl_not_established() || find_good_move(BAD)) X close_EVERYTHING(); X else X first_pass(); X} X Xfind_good_move(BorG) Xint BorG; X{ X int x, y, xcount, ycount, x1, y1, x2, y2; X X if (no_good_moves) X return (0); X if (BorG == GOOD && level == KILLER && kill_4_loops()) X return (1); X for (xcount = 1, x = random() % (2 * Length - 1) + 1; xcount < Length * 2; X xcount++, x = x % (2 * Length - 1) + 1) X for (ycount = 1, y = random() % (2 * Width - 1) + 1; ycount < Width * 2; X ycount++, y = y % (2 * Width - 1) + 1) { X if (iseven(x + y)) X continue; X if (board[x][y] == USED) X continue; X find_adj_squares(x, y, &x1, &y1, &x2, &y2); X if (closure(GOOD, x1, y1) == 2) X continue; X if (closure(GOOD, x2, y2) == 2) X continue; X if (BorG == GOOD) { X xposit = x, yposit = y; X (void) entermove(); X } X return (1); X } X no_good_moves = 1; X return (0); X} X X/********************************************************************\ X|* check all dots and ruins potential 4 loops. *| X|* *| X|* Want to prevent: Find these: Before they turn into: *| X|* *---*---* *---* * *---* * *| X|* | | | | *| X|* * * * * * * * * * *| X|* | | | *| X|* *---*---* * *---* * *---* *| X|* Because 4 loops lose points and #3 guarantees 4-loops *| X\********************************************************************/ X Xkill_4_loops() X{ X int x, y, x1, y1, x2, y2, dx, dy, xcheck, ycheck; X X for (x = 3; x <= 2 * Length - 3; x += 2) X for (y = 3; y <= 2 * Width - 3; y += 2) { X if (closure(GOOD, x, y)) X continue; /* a line is connected to dot */ X for (dx = -1; dx <= 1; dx += 2) X for (dy = -1; dy <= 1; dy += 2) X if (closure(GOOD, x + dx, y + dy) == 2) X if (closure(GOOD, x - dx, y - dy) == 1) { X xcheck = x - dx, ycheck = y; X do_twice X { X find_adj_squares(xcheck, ycheck, &x1, &y1, &x2, &y2); X if (closure(GOOD, x1, y1) != 2 && closure(GOOD, x2, y2) != 2) { X xposit = xcheck, yposit = ycheck; X (void) entermove(); X return (1); X } else X xcheck = x, ycheck = y - dy; X } X } X } X return (0); X} X Xforce_move() X{ X int x, y, xcount, ycount, x1, y1, x2, y2; X int Badness, bestx, besty, Bestbad = 1000, Besttype; X X if (dX_found) { X if (comptally + persontally + segflag == OPENEND ? 2 : 4 == (Length - 1) * (Width - 1)) { X Bingo.x = Bingo.y = dX_found = 0; X close_EVERYTHING(); X return; X } X if (segflag == OPENEND) { X find_adj_squares(Bingo.x, Bingo.y, &x1, &y1, &x2, &y2); X if (closure(GOOD, x1, y1) == 2 && closure(GOOD, x2, y2) == 2) { X close_boxes(); X if (!board_is_full()) X force_move(); X return; X } X } X xposit = Bingo.x; X yposit = Bingo.y; X (void) entermove(); X return; X } X for (xcount = 1, x = random() % (2 * Length - 1) + 1; xcount < Length * 2; X xcount++, x = x % (2 * Length - 1) + 1) X for (ycount = 1, y = random() % (2 * Width - 1) + 1; ycount < Width * 2; X ycount++, y = y % (2 * Width - 1) + 1) X if (isodd(x + y) && board[x][y] == FREE) { X find_adj_squares(x, y, &x1, &y1, &x2, &y2); X if (closure(GOOD, x1, y1) != 3 && closure(GOOD, x2, y2) != 3) X if ((Badness = Howbad(GOOD, Bestbad, x, y)) < Bestbad) { X Bestbad = Badness; X bestx = x; X besty = y; X Besttype = segtype; X } X } X if (Bestbad >= 2 && Besttype == OPENEND) X goto_middle_of_path(GOOD, &bestx, &besty); X xposit = bestx; X yposit = besty; X (void) entermove(); X} X Xfirst_pass() X{ X int x, y, x1, y1, doubleX, doubleY; X int Badness; X int start_over; X X do { X start_over = 0; X for (x = 2; x <= 2 * Length - 2 && !start_over; x += 2) X for (y = 2; y <= 2 * Width - 2 && !start_over; y += 2) X if (closure(GOOD, x, y) == 3) { X x1 = x, y1 = y; X goto_adj_free_line(GOOD, &x1, &y1); X if (((Badness = Howbad(BAD, 1000, x1, y1)) == 2 && X segtype == OPENEND) X || (Badness == 4 && segtype == CLOSEDEND)) { X segflag = segtype; X dX_found = 1; X doubleX = x1; X doubleY = y1; X board[x1][y1] = USED; /* temporarily */ X goto_next_square(GOOD, &doubleX, &doubleY); X goto_adj_free_line(GOOD, &doubleX, &doubleY); X Bingo.x = doubleX; X Bingo.y = doubleY; X board[x1][y1] = FREE; /* SIGH */ X close_EVERYTHING(); X return; X } else if (Badness <= 2) { X xposit = x1, yposit = y1; X entermove(); X } else { X xposit = x1, yposit = y1; X entermove(); X start_over = 1; X } X } X } X while (start_over); X} X Xclose_EVERYTHING() X{ X int x, y, x_check, y_check, moved; X X do { X moved = 0; X for (x = 2; x <= 2 * Length - 2; x += 2) X for (y = 2; y <= 2 * Width - 2; y += 2) X if (closure(GOOD, x, y) == 3) { X x_check = x, y_check = y; X goto_adj_free_line(GOOD, &x_check, &y_check); X /* at the end of the game, ignore this line! */ X if (!board_is_almost_full() && too_close(x_check, y_check)) X continue; X xposit = x_check; X yposit = y_check; X entermove(); X moved = 1; X } X } X while (moved); X} X XHowbad(BorG, Max, xmove, ymove) Xint BorG, Max, xmove, ymove; X{ X int x, y, x1, y1, x2, y2, moved, badtotal = 0; X X for (x = 1; x < 2 * Length; x++) X for (y = isodd(x) ? 2 : 1; y < 2 * Width; y += 2) X badboard[x][y] = board[x][y]; X if (BorG == GOOD) X badboard[xmove][ymove] = USED; X segtype = OPENEND; X X do_twice { X x = xmove; X y = ymove; X do { X moved = 0; X if (!goto_next_square(BAD, &x, &y)) X break; X goto_adj_free_line(BAD, &x, &y); X badboard[x][y] = USED; X moved = 1; X find_adj_squares(x, y, &x1, &y1, &x2, &y2); X if (closure(BAD, x1, y1) == 4 && closure(BAD, x2, y2) == 4) X badtotal++, segtype = CLOSEDEND; /* add extra for two X * sides */ X badtotal++; X if (badtotal >= Max) X return (Max); X } X while (moved == 1); X } X return (badtotal); X} X X/***********************************************************************\ X|* This procedure returns true if the line passed is on either of the *| X|* boxes next to Bingo. *| X\***********************************************************************/ X Xtoo_close(x, y) Xint x, y; X{ X if (abs(x - Bingo.x) == 1 && abs(y - Bingo.y) == 1) { /* REAL close */ X if (isodd(Bingo.x)) { /* Bingo is vertical */ X if (closure(GOOD, x, Bingo.y) == 2) X return (1); X } else { /* Bingo is horizontal */ X if (closure(GOOD, Bingo.x, y) == 2) X return (1); X } X } X if (isodd(Bingo.x)) { /* Bingo is vertical */ X if ((abs(x - Bingo.x) == 2 && y == Bingo.y) X && (closure(GOOD, (x + Bingo.x) / 2, y) == 2)) X return (1); X } else { /* Bingo is horizontal */ X if ((abs(y - Bingo.y) == 2 && x == Bingo.x) X && (closure(GOOD, x, (y + Bingo.y) / 2) == 2)) X return (1); X } X return (0); X} X X/***************************************************************************\ X|* This function decides if there are still more open-ended paths of *| X|* length two or less still on the board. If there are, it returns 1, else *| X|* 0. *| X\***************************************************************************/ X Xcntrl_not_established() X{ X int x, y, x1, y1, x2, y2; X X if (control_already_established) X return (0); X for (x = 1; x < 2 * Length; x++) X for (y = isodd(x) ? 2 : 1; y < 2 * Width; y += 2) X if (board[x][y] == FREE) X if (Howbad(GOOD, 3, x, y) <= 2 && segtype == OPENEND) { X find_adj_squares(x, y, &x1, &y1, &x2, &y2); X if (closure(GOOD, x1, y1) <= 2 && closure(GOOD, x2, y2) <= 2) X return (1); X } X control_already_established = 1; X return (0); X} END_OF_comp.c if test 8116 -ne `wc -c <comp.c`; then echo shar: \"comp.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f comp2.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"comp2.c\" else echo shar: Extracting \"comp2.c\" \(2257 characters\) sed "s/^X//" >comp2.c <<'END_OF_comp2.c' X/* COMP2.C */ X X#include "dots.h" X Xgoto_next_square(BorG, x, y) /* returns 1 if there is one, 0 if not */ Xint BorG, *x, *y; X{ X int x1, y1, x2, y2; X X find_adj_squares(*x, *y, &x1, &y1, &x2, &y2); X if (x1 != NULL && closure(BorG, x1, y1) == 3) { X *x = x1, *y = y1; X return (1); X } X if (x2 != NULL && closure(BorG, x2, y2) == 3) { X *x = x2, *y = y2; X return (1); X } X return (0); X} X Xfind_adj_squares(x, y, x1, y1, x2, y2) Xint x, y, *x1, *y1, *x2, *y2; X{ X if (isodd(x)) { /* Vertical line */ X *x1 = x - 1; X *y1 = y; X *x2 = x + 1; X *y2 = y; X } else { /* Horizontal line */ X *x1 = x; X *y1 = y - 1; X *x2 = x; X *y2 = y + 1; X } X if (!is_on_board(*x1, *y1)) X *x1 = NULL, *y1 = NULL; X if (!is_on_board(*x2, *y2)) X *x2 = NULL, *y2 = NULL; X} X Xgoto_adj_free_line(BorG, x, y) Xint BorG; Xint *x, *y; X{ X int xtemp, ytemp; X X for (xtemp = *x - 1; xtemp <= *x + 1; xtemp += 2) X if ((BorG == BAD ? badboard[xtemp][*y] : board[xtemp][*y]) == FREE) { X *x = xtemp; X return; X } X for (ytemp = *y - 1; ytemp <= *y + 1; ytemp += 2) X if (board[*x][ytemp] == FREE) X if (((BorG == BAD)? badboard[*x][ytemp] : board[*x][ytemp]) X == FREE) { X *y = ytemp; X return; X } X printf("You fucked up, buddy!"); X fflush(stdout); X die(); X} X X/*****************************************************************************\ X|* right now, this function doesn't actually go to the middle of a path, *| X|* it simply goes one line away from the edge. If the length of the path is *| X|* two, the effect is the same. *| X\*****************************************************************************/ Xgoto_middle_of_path(BorG, x, y) Xint BorG, *x, *y; X{ X int origx, origy, x1, y1, x2, y2; X X find_adj_squares(*x, *y, &x1, &y1, &x2, &y2); X if (closure(BorG, x1, y1) == 2 && closure(BorG, x2, y2) == 2) X return; /* you're sitting on it to begin with */ X origx = *x, origy = *y; X if (BorG == GOOD) X board[origx][origy] = USED; X else X badboard[origx][origy] = USED; X /* Temporarily */ X goto_next_square(BorG, x, y); X goto_adj_free_line(BorG, x, y); X X if (BorG == GOOD) X board[origx][origy] = FREE; X else X badboard[origx][origy] = FREE; X /* SIGH! */ X} END_OF_comp2.c if test 2257 -ne `wc -c <comp2.c`; then echo shar: \"comp2.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f dots.doc -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"dots.doc\" else echo shar: Extracting \"dots.doc\" \(3304 characters\) sed "s/^X//" >dots.doc <<'END_OF_dots.doc' X . . . D O T S . . . X X X For points, create squares like this: X X *---* X | X | X *---* X X Whoever has more squares at the end of the game wins. X When a square is won, that player's initial will be X put inside the square as shown. X X To move the cursor, use one of three ways: X The "rogue/vi" keys, the number keys or the X keys surrounding the 's'. X X rogue: 's': numbers X X y k u q w e 7 8 9 X h l a s d 4 6 X b j n z x c 1 2 3 X X The circle represents which direction you would move away from X where the cursor would currently be located. The numbers are X good for terminals that have separate number key pads. The RETURN X key or the space-bar will enter a move at the current cursor position. X X When a player enters a move, if he did NOT close any boxes, then X it is the other player's turn. If the player DOES close a box, it X remains that players turn and he MUST move again even if he doesn't X have another scoring move. X X ^L will redraw the screen if it gets messed up (or try ^\). X 'S' will save your game. X X If you are playing the two player game, that is, another human, X not the computer, use the ESCAPE key to 'talk' to the other player. X You can ONLY do this when it's your turn. You cannot save games when X playing someone else. There is no high score file for two player games. X X Command line arguments: X X You can see the high-scores without playing by typing: X X % dots -s X X You can restart a saved game by typing: X X % dots -r X which will read "dots.save" from your home directory or: X X % dots -r saved_file_name X if you've saved it as something other than "dots.save". X Be sure to give the full pathname if the file is not in X your current directory. X X You can avoid the menu by giving the following information on X the command line: X X % dots LENGTH WIDTH LEVEL [C] X X where "length", "width", and "level" are values to use X for the length and width of the playing board and level X is the level of difficulty to play at (0-3). X 'C' is the initial to use if you don't want the first X letter of your account name in the middle of your squares. X X Example: X X % dots 5 9 0 F X X will play an easy game on a 5 X 9 board and your boxes will be X initialized with 'F'. X X X There is also a way to play others on the system. In the menu, X choose the '7' item. From the command line (avoiding the menu), X type: X X % dots 2 login name [tty] X X You may specify the tty if the same user is logged in more than X once. You would use the same format to respond to someone else's X request to play you. When you send (receive) a request, the X challenged will get a message every 30 seconds until that user replys X or until the challenger terminates (just like talk). X X END_OF_dots.doc if test 3304 -ne `wc -c <dots.doc`; then echo shar: \"dots.doc\" unpacked with wrong size! fi # end of overwriting check fi if test -f dots.h -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"dots.h\" else echo shar: Extracting \"dots.h\" \(2656 characters\) sed "s/^X//" >dots.h <<'END_OF_dots.h' X/* dots.h */ X X#include <curses.h> X#include <sys/types.h> X#include <sys/ioctl.h> X#if defined(lint) && defined(BSD) X#include <sys/uio.h> X#endif /* lint && BSD */ X#ifdef BSD X#include <sys/socket.h> X#endif /* BSD */ X#include <ctype.h> X#include <signal.h> X#include <setjmp.h> X#ifdef BSD X#include <strings.h> X#else X#include <string.h> X#endif /* BSD */ X X#ifdef BSD Xextern char *sprintf(); X#else Xextern int sprintf(); X#endif /* BSD */ X X/* Most BSD systems don't have vprintf, but sun versions 3.0 and up do have it. X * If you're system doesn't have it, comment out the define line. System-V X * systems do have it. X */ X#ifdef SYSV X#define VPRINTF X#endif /* SYSV */ X X#ifdef SYSV X#define SIGCHLD SIGCLD X#define srandom srand X#define random rand X#define index strchr X#define rindex strrchr X#endif /* SYSV */ X X#define PRIZE "cigar" X#define DOCFILE "/usr/games/lib/dots/dots.doc" X#define SAVE_FILE "dots.save" X#define SCOREFILE "/usr/games/lib/dots/dots.scores" /* should be full pathname */ X#define version "Dots version 2.0" X X#define when break;case X#define otherwise break;default X#define Upper(c) (c = islower(c) ? toupper(c) : c) X#define Lower(c) (c = isupper(c) ? tolower(c) : c) X#define max(a,b) ((a) > (b) ? (a) : (b)) X#define min(a,b) ((a) > (b) ? (b) : (a)) X#define erase_char '\b' X X#define ESC '\033' X#define DEMO 0 X#define INTERACTIVE 1 X#define TWOPLAYER 2 X#define GOOD 0 X#define BAD 1 X#define DUMB 0 X#define HARD 1 X#define KILLER 2 X#define FREE 0 X#define USED 1 X#define CLOSEDEND 0 /* used for segtype for creating doublecrosses */ X#define OPENEND 1 /* ditto */ X#define MAXL (COLS / 4) X#define MAXW (LINES / 2) X#define H_MINL 10 X#define H_MINW 10 X#define MINL 4 X#define MINW 4 X#define US 0 X#define THEM 1 X#define SAVE 0 X#define LOAD 1 X#define isodd(a) ((a)%2) X#define iseven(a) (!isodd(a)) X#define ism4(a) (!((a)%4)) X#define do_twice for(twicecount=1;twicecount<=2;++twicecount) X Xint X board[120][120], X badboard[120][120], X persontally, comptally, X Length, Width, X xposit, yposit, X x_start, y_start, X mover, /* 0 is person/US, 1 is computer/THEM */ X twicecount, X no_good_moves, X control_already_established, X segtype, /* OPENEND or CLOSEDEND ; set everytime Howbad is called */ X dX_found, X segflag, X mode, X level, X sd, /* socket descriptor */ X jmpbuf_set; X Xstruct { X int x, y; X} Bingo; X Xstruct tchars tchars; X Xchar *opponent, prize[30], save_file[50], *getenv(); Xchar Initial[2], *username; Xint onintr(), redraw(), oops(); X X/* jump to the menu so there's no big stacks (supposedly) */ Xjmp_buf menu_jmp; X Xextern int errno; Xextern char *sys_errlist[], *sys_siglist[]; END_OF_dots.h if test 2656 -ne `wc -c <dots.h`; then echo shar: \"dots.h\" unpacked with wrong size! fi # end of overwriting check fi if test -f findem.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"findem.c\" else echo shar: Extracting \"findem.c\" \(1475 characters\) sed "s/^X//" >findem.c <<'END_OF_findem.c' X/* findem.c find the login of the person we wanna play */ X X#include "dots.h" X#include <sys/stat.h> X#include <sgtty.h> X#include <utmp.h> X X#define UTMP "/etc/utmp" X Xstruct utmp utmp_buf; Xstruct stat stat_buf; Xstruct sgttyb sgtty_buf; X Xint fd; X Xfindem(argc, argv) Xchar **argv; X{ X char *ttyname(), to_tty[13]; X register char *login = argv[2], *where = "", *ourtty = ttyname(0) + 5; X register FILE *recipient; X X if (argc > 3) X where = argv[3]; X if (!strcmp(where, ourtty)) { X fprintf(stderr, "You can't play yourself.\n"); X return 0; X } X if ((fd = open(UTMP, 0)) == -1) { X perror(UTMP); X return 0; X } X X while (read(fd, (char *) &utmp_buf, sizeof(utmp_buf))) X if (!strcmp(utmp_buf.ut_name, login) && X (*where && !strcmp(utmp_buf.ut_line, where) || X (!*where && strcmp(where, ourtty)))) X break; X X (void) close(fd); X if (strcmp(login, utmp_buf.ut_name)) { X fprintf(stderr, "%s is not logged in.", login); X return 0; X } X if (*where && strcmp(where, utmp_buf.ut_line)) { X fprintf(stderr, "%s is not logged in on %s.\n", login, where); X return 0; X } X X (void) sprintf(to_tty, "/dev/%s", utmp_buf.ut_line); X if (!(recipient = fopen(to_tty, "w"))) { X perror(to_tty); X fprintf(stderr, "%s: Can't ask %s to play.\n", argv[0], argv[2]); X return 0; X } X setuid(getuid()); /* turns off set-uid attribute once tty is opened */ X setgid(getgid()); /* probably isn't necessary most of the time */ X X return invite(recipient); X} END_OF_findem.c if test 1475 -ne `wc -c <findem.c`; then echo shar: \"findem.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f main.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"main.c\" else echo shar: Extracting \"main.c\" \(5274 characters\) sed "s/^X//" >main.c <<'END_OF_main.c' X/* MAIN.C */ X X#include "dots.h" X Xchar *error_msg[] = { X "usages:\n", X "%s -s gives top scores.\n", X "%s -d reads the directions\n", X "%s -r [file] restart saved game (from file if given).\n", X "%s L W D [C] plays a game using integer arguments as\n", X " Length, Width and Difficulty levels, respectively.\n", X " 'C' is inital for boxes.\n", X "%s 2 user [tty] send request/reply to play someone else (2-user).\n", X "\nsetenv DOTSOPTS \"name=whoareyou,savefile=path,initial=X,prize=whatever\"\n", X 0 X}; X Xchar *getusername(); X Xbus_n_seg(sig) X{ X if (sig == SIGBUS) X fprintf(stderr, "Bus error.\n"); X else X fprintf(stderr, "Segmentation Fault.\n"); X die(); X} X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X register char *p; X extern char *UP; X X setbuf(stdout, (char *)NULL); X setbuf(stderr, (char *)NULL); X X username = getusername(); X X savetty(); X initscr(); X X (void) signal(SIGBUS, bus_n_seg); X (void) signal(SIGSEGV, bus_n_seg); X (void) signal(SIGINT, onintr); X (void) signal(SIGPIPE, onintr); X (void) signal(SIGCHLD, SIG_IGN); /* to return from shell esc */ X (void) signal(SIGQUIT, redraw); X X if (argc > 1 && argv[1][0] == '-' && argv[1][1] != 'r') X if (argv[1][1] == 'd') X readinst(1), exit(0); X else if (argv[1][1] == 's') X high_score(TRUE, FALSE), die(); X else if (argv[1][1] == 'x') X high_score(TRUE, TRUE), die(); X else X do_error(argv[0]), die(); X X if (COLS < 4 * H_MINL || LINES < 2 * H_MINW) { X printf("Window must be at least %d by %d.\n", 4 * H_MINL, 2 * H_MINW); X die(); X } X if (!*UP) { X printf("You need cursor movement capability on your terminal.\n"); X die(); X } X X srandom(getpid()); X mover = US, Initial[THEM] = '$'; X getopts(); X noecho(), crmode(); X X if (argc > 1) X parse_command(argc, argv); X else X menu(); X} X Xdo_error(arg) Xchar *arg; X{ X int count = 0; X X while (error_msg[count]) X fprintf(stderr, error_msg[count++], arg); X die(); X} X XDots(which) /* which? recovered game, start from command line, or menu */ Xint which; /* 0 = start from beginning, 1 = recovered game */ X{ X Upper(Initial[US]); X Lower(Initial[THEM]); X X if (mode == TWOPLAYER) { X mvprintw(LINES-5,0, "Your label is '%c' and %s's is '%c'.", X Initial[US], opponent, Initial[THEM]); X mvprintw(LINES-4,0, "%s will go first.", (mover==US)? "You" : opponent); X mvaddstr(LINES-3,0, "^Z stops game for you only. \"fg\" resumes game."); X mvaddstr(LINES-2,0, "ESC to talk to other player. ^L to redraw board."); X msg("--hit any key to continue-- "); X getchar(); X set_redraw_signal_key_to('\014'); /* change to ^L */ X free_board(); X } X if (!which) /* could be a restart of a saved game or a new game */ X setup(), free_board(); X drawboard(); X while (!board_is_full()) X if (mode != DEMO && (mode == TWOPLAYER || mover == US)) X mover = (personmove()) ? mover : !mover; /* switch if we got some */ X else if (mode != TWOPLAYER && (mode == DEMO || mover == THEM)) X if (!board_is_full()) X compmove(), mover = !mover; X end_of_game(); X} X Xgetopts() X{ X char *p, *opts, temp[BUFSIZ], *length, *index(); X X (void) strcpy(prize, PRIZE); X (void) strcpy(save_file, SAVE_FILE); X if (opts = getenv("DOTSOPTS")) { X length = opts + strlen(opts); X while (opts < length) { X (void) sscanf(opts, "%[^,]", temp); X if (p = index(temp, '=')) X if (!strncmp(temp, "name", 4)) X username = ++p; X else if (!(strncmp(temp, "savefile", 8))) X (void) strcpy(save_file, ++p); X else if (!(strncmp(temp, "prize", 5))) X (void) strcpy(prize, ++p); X else if (!(strncmp(temp, "initial", 7))) X Initial[US] = *++p; X opts += 1 + strlen(temp); X } X } X if (!Initial[US]) X Initial[US] = *username; X} X Xparse_command(argc, argv) Xint argc; Xchar **argv; X{ X if (!strcmp(argv[1], "2")) { X if (argc < 3) X printf(error_msg, argv[0]); X else X#ifdef BSD X mode = TWOPLAYER, sockit(argc, argv); X#else X printf(stderr,"Sorry - no sockets, no two player mode\n"); X#endif /* BSD */ X die(); X } X X mode = INTERACTIVE; X X if (!strcmp(argv[1], "-r")) { X if (argc == 3) X (void) strcpy(save_file, argv[2]); X if (recover(1)) X Dots(1); X else X die(); X menu(); X } X X if (argc < 4) X do_error(argv[0]); X X if ((level = atoi(argv[3])) < DUMB || level > KILLER) { X printf("%s: Invalid Difficulty Level (0,1, or 2)\n", argv[0]); X die(); X } X if ((Length = atoi(argv[1])) > MAXL || Length < (level? H_MINL : MINL)) { X printf("%s: (%d) Invalid Length.\n", argv[0], Length); X die(); X } X if ((Width = atoi(argv[2])) > MAXW || Width < (level? H_MINW : MINW)) { X printf("%s: (%d) Invalid Width.\n", argv[0], Width); X die(); X } X X if (argc > 4) X Initial[US] = *argv[4]; X comptally = persontally = 0; X xposit = 2, yposit = 1; X y_start = 1 + LINES / 2 - Width; X x_start = 1 + COLS / 2 - Length * 2; X Dots(2); X} X X#include <pwd.h> Xchar * Xgetusername() X{ X struct passwd *entry, *getpwuid(); X extern char *getlogin(); X register char *p; X X if ((p = getenv("NAME")) X || (p = getenv("SIGNATURE")) X || (p = getenv("USER")) X || (p = getlogin())) X return p; X if (!(entry = getpwuid(getuid()))) X puts("Who the hell are you?"), die(); X endpwent(); X return entry->pw_name; X} END_OF_main.c if test 5274 -ne `wc -c <main.c`; then echo shar: \"main.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f menu.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"menu.c\" else echo shar: Extracting \"menu.c\" \(4530 characters\) sed "s/^X//" >menu.c <<'END_OF_menu.c' X/* MENU.C */ X X#include "dots.h" X#include <utmp.h> X#include <sys/stat.h> X X#define ever (;;) X X/* in the function menu() I make it impossible to choose option #7 X unless BSD is defined because option #7 is challenge another user, X and that only works under BSD with sockets. X J.M.Libove X*/ Xmenu() X{ X int c, command = 1; X X jmpbuf_set = 1; X disp_menu(setjmp(menu_jmp) < 2); X for ever { X while ((c = getchar()) != '\n') X#ifdef BSD X if (c > '0' && c < '9') X#else X if (c > '0' && c < '9' && c != '7') X#endif /* BSD */ X putchar(c), putchar('\b'), command = c; X switch (command - '0') { X case 1: readinst(0), disp_menu(1); X when 2: level = DUMB, mode = INTERACTIVE, Dots(0); X when 3: level = HARD, mode = INTERACTIVE, Dots(0); X when 4: level = KILLER, mode = INTERACTIVE, Dots(0); X when 5: level = DUMB, mode = DEMO, Dots(0); X when 6: if (recover(0)) Dots(1); X when 7: challenge(); X when 8: goodbye(1); X } X } X} X Xdisp_menu(clear_it) X{ X int partition = LINES / 10, lines; X X if (clear_it) X clear(); X mvaddstr((lines = partition + LINES - 10 * partition), COLS / 2 - 10, ". . . D O T S . . ."); X mvaddstr((lines += partition), COLS / 6, "1. Read instructions."); X mvaddstr((lines += partition), COLS / 6, "2. Easy game."); X mvaddstr((lines += partition), COLS / 6, "3. Hard game."); X mvaddstr((lines += partition), COLS / 6, "4. Killer game."); X mvaddstr((lines = partition + LINES - 9 * partition), 4 * COLS / 6, "5. Demo game."); X mvaddstr((lines += partition), 4 * COLS / 6, "6. Recover saved game."); X#ifdef BSD X mvaddstr((lines += partition), 4 * COLS / 6, "7. Play someone else."); X#else X mvaddstr((lines += partition), 4 * COLS / 6, "7. Only under BSD."); X#endif /* BSD */ X mvaddstr((lines += partition), 4 * COLS / 6, "8. Leave game."); X mvaddstr((lines += partition), COLS / 2 - 9, "Enter command. [ ]\b\b"); X refresh(); X} X Xreadinst(before) Xbool before; /* before or after curses mode has been set */ X{ X int c, line_count = 0; X FILE *fp2; X X if (!before) X clear(), refresh(); X else X noecho(), crmode(); X if ((fp2 = fopen(DOCFILE, "r")) == NULL) X perror(DOCFILE); X else { X while ((c = getc(fp2)) != EOF) { X putchar(c); X if (c == '\n') X line_count++; X if (line_count == LINES - 1) { X printf("--more--(or 'q' to return)"); X if (getchar() == 'q') { X fclose(fp2); X if (before) X echo(), nocrmode(); X return; X } X printf("\015 \015"); X line_count = 0; X } X } X fclose(fp2); X } X if (!before) { X printf("Hit return to continue [ ]\b\b"); X while (getchar() != '\n'); X } else X echo(), nocrmode(); X} X Xwritable(line) Xchar *line; X{ X char ttyno[20]; X X sprintf(ttyno, "/dev/%s", line); X return !access(ttyno, 02); X} X Xchallenge() X{ X#ifdef BSD X struct utmp buf; X int count = 0, col = LINES / 3, l_len = 0; X char *p, *index(), *victim[4], string[20], *ttyname(), *tty = ttyname(0)+5; X FILE *file; X X victim[0] = "Dots"; X victim[1] = "2"; X clear(); X mvaddstr(col, 0, "Here are your potential opponents: "); X move(++col, 0); X X if ((file = fopen("/etc/utmp", "r")) == NULL) { X disp_menu(1); X msg("/etc/utmp: %s", sys_errlist[errno]); X return; X } X while (fread((char *)&buf, sizeof(struct utmp), 1, file) > 0) X if (buf.ut_name[0] && writable(buf.ut_line)) { X if (!strncmp(buf.ut_name, username, 8) && !strcmp(buf.ut_line, tty)) X continue; X if (count++) X addstr(", "); X if ((l_len + 10 + min(strlen(buf.ut_name), 8)) > COLS - 1) X clrtoeol(), move(++col, 0), l_len = 0; X l_len += 10 + min(strlen(buf.ut_name), 8); X printw("%-.8s (%s)", buf.ut_name, buf.ut_line); X } X (void) fclose(file); X if (!count) { X disp_menu(1); X msg("There doesn't seem to be anyone who can play."); X return; X } X mvaddstr(col += 2, 0, "RETURN for menu."); X mvaddstr(++col, 0, "Whom would you like to play (user [ttyxx])? "); X refresh(); X count = 2; X Getstr(string, min(20, COLS - 1)); X if (string[0] == NULL) { X disp_menu(1); X return; X } X move(++col, 0); X refresh(); X victim[count++] = string; X if ((p = index(string, ' ')) != NULL) { X *(p++) = '\0'; X victim[count - 1] = string; X victim[count++] = p; X } X mode = TWOPLAYER; X sockit(count, victim); /* shouldn't return. If so, there was an error */ X mode = DEMO; X putchar('\n'); /* don't overwrite any error messages */ X msg("Hit any key to continue."); X getchar(); X disp_menu(1); X#endif /* BSD */ X} END_OF_menu.c if test 4530 -ne `wc -c <menu.c`; then echo shar: \"menu.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f misc.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"misc.c\" else echo shar: Extracting \"misc.c\" \(8465 characters\) sed "s/^X//" >misc.c <<'END_OF_misc.c' X/* MISC.C */ X X#include "dots.h" X X/* has to be a function instead of define because signal calls this */ Xredraw() X{ X clearok(curscr, TRUE), wrefresh(curscr); X} X X/* returns the number of boxes closed, if any */ Xentermove() X{ X Cursor(xposit, yposit); X addstr(iseven(yposit) ? "|\b" : "\b---\b\b"); X board[xposit][yposit] = USED; X return he_got_some(); X} X Xclosure(BorG, x, y) Xregister int BorG, x, y; X{ X if (!is_on_board(x, y)) X return (-1); X if (BorG == GOOD) X return (board[x][y - 1] X + board[x][y + 1] X + board[x - 1][y] X + board[x + 1][y]); X else X return (badboard[x][y - 1] X + badboard[x][y + 1] X + badboard[x - 1][y] X + badboard[x + 1][y]); X} X Xhe_got_some() X{ X int total = 0, x1, y1, x2, y2; X X find_adj_squares(xposit, yposit, &x1, &y1, &x2, &y2); X if (closure(GOOD, x1, y1) == 4) { X putinitial(x1, y1, mover); X total++; X } X if (closure(GOOD, x2, y2) == 4) { X putinitial(x2, y2, mover); X total++; X } X if (mover == THEM) X comptally += total; X else X persontally += total; X bottom_line(); X X return total; X} X Xset_redraw_signal_key_to(c) Xchar c; X{ X static char oldquit = 0; X X#ifdef TIOCGETC X if (!oldquit) X if (ioctl(0, TIOCGETC, &tchars) == -1) X oops("ioctl get call"); X else X oldquit = tchars.t_quitc; X tchars.t_quitc = (c) ? c : oldquit; /* redraw screen anytime by signal */ X if (ioctl(0, TIOCSETC, &tchars) == -1) X oops("ioctl set call"); X#else X puts("Use your quit key to redraw."); X#endif /* TIOCGETC */ X} X Xbottom_line() X{ X char line[128], Opponent[12]; X register char *p = line; X X/* the reason for this (almost) duplication of code is that in every X case where BSD requires 'strlen(sprintf(..' sysV doesn't need the X 'strlen' because its return from sprintf is the length... X J.M.Libove X*/ X#ifdef BSD X (void) sprintf(Opponent, "%s's", opponent); X if (mode != DEMO) X p += strlen(sprintf(p, "%8s turn. ", X (mover == US) ? "Your" : (mode == TWOPLAYER) ? Opponent : "My")); X p += strlen(sprintf(p, "%s: %3d %s: %3d ", X (mode == DEMO) ? "Player 1" : "You", X persontally, (mode == TWOPLAYER) ? opponent : X (mode == DEMO) ? "Player 2" : "Me", comptally)); X if (mode != TWOPLAYER && mode != DEMO && strlen(line) + 13 < COLS - 1) X p += strlen(sprintf(p, "Level: %s ", X (level == DUMB) ? "EASY" : (level == HARD) ? "HARD" : "KILLER")); X if (p - line + 14 < COLS - 1 && mode != DEMO) X p += strlen(sprintf(p, " '?' for help.")); X if (mode == DEMO) X p += strlen(sprintf(p, " Demo Game.")); X if (mode == TWOPLAYER && p - line + 29 < COLS - 1) X (void) sprintf(p, " '^L' to redraw. ESC to talk."); X msg(line); X Cursor(xposit, yposit); X#else X (void) sprintf(Opponent, "%s's", opponent); X if (mode != DEMO) X p += sprintf(p, "%8s turn. ", X (mover == US) ? "Your" : (mode == TWOPLAYER) ? Opponent : "My"); X p += sprintf(p, "%s: %3d %s: %3d ", X (mode == DEMO) ? "Player 1" : "You", X persontally, (mode == TWOPLAYER) ? opponent : X (mode == DEMO) ? "Player 2" : "Me", comptally); X if (mode != TWOPLAYER && mode != DEMO && strlen(line) + 13 < COLS - 1) X p += sprintf(p, "Level: %s ", X (level == DUMB) ? "EASY" : (level == HARD) ? "HARD" : "KILLER"); X if (p - line + 14 < COLS - 1 && mode != DEMO) X p += sprintf(p, " '?' for help."); X if (mode == DEMO) X p += sprintf(p, " Demo Game."); X if (mode == TWOPLAYER && p - line + 29 < COLS - 1) X (void) sprintf(p, " '^L' to redraw. ESC to talk."); X msg(line); X Cursor(xposit, yposit); X#endif /* BSD */ X} X Xboard_is_almost_full() X{ X return (persontally + comptally >= (Length - 1) * (Width - 1) - 4); X} X Xboard_is_full() X{ X return (persontally + comptally == (Length - 1) * (Width - 1)); X} X Xend_of_game() X{ X char line[80], c; X register char *p = line; X X/* this (almost) duplication of code is needed because BSD 'sprintf' X returns the address of the string printed, but SysV returns the X number of characters printed, making the 'strlen(' invalid. X J.M.Libove X*/ X#ifdef BSD X move(LINES - 1, 0); X if (board_is_full()) { X p += strlen(sprintf(p, "Score: %d to %d. ", comptally, persontally)); X if (comptally == persontally) X p += strlen(sprintf(p, "No one won. ")); X else if (mode == DEMO) X p += strlen(sprintf(p, "%s won. ", (comptally > persontally) X ? "Player 2" : "Player 1")); X else X p += strlen(sprintf(p, "%s won. ", X (comptally > persontally) ? (mode == TWOPLAYER) ? X "They" : "I" : "You")); X#else X move(LINES - 1, 0); X if (board_is_full()) { X p += sprintf(p, "Score: %d to %d. ", comptally, persontally); X if (comptally == persontally) X p += sprintf(p, "No one won. "); X else if (mode == DEMO) X p += sprintf(p, "%s won. ", (comptally > persontally) X ? "Player 2" : "Player 1"); X else X p += sprintf(p, "%s won. ", X (comptally > persontally) ? (mode == TWOPLAYER) ? X "They" : "I" : "You"); X#endif /* BSD */ X addstr(line); X if (mode != DEMO) X if (comptally - persontally < 0) { X printw("You get a %s. ", prize); X if (mode != TWOPLAYER) X high_score(0, 0); X } else if (comptally != persontally) X printw("You lose a %s. ", prize); X } else X addstr("No score, you quit."); X Length = Width = 0; X if (mode == TWOPLAYER) X goodbye(1); X addstr("--more--"), clrtoeol(); X refresh(); X getchar(); X if (jmpbuf_set) X msg("RETURN for menu; 'Q' to exit. "); X if (!jmpbuf_set || (c = getchar()) == 'q' || c == 'Q') X goodbye(1); X longjmp(menu_jmp, 1); X} X Xgoodbye(When) Xbool When; X{ X if (When) X msg(""); X if (When && mode != TWOPLAYER) X high_score(TRUE, FALSE); X printf("\nThanx, %s.\n", username); X die(); X} X X/*VARARGS1*/ Xmsg(fmt, args) Xchar *fmt; X{ X char string[BUFSIZ]; X#ifdef VPRINTF X vsprintf(string, fmt, &args); X#else X FILE foo; X foo._cnt = BUFSIZ; X foo._base = foo._ptr = string; /* may have to be cast(unsigned char *) */ X foo._flag = _IOWRT+_IOSTRG; X _doprnt(fmt, &args, &foo); X (void) fputc(0, &foo); X#endif /* VPRINTF */ X mvaddstr(LINES-1, 0, string), clrtoeol(), refresh(); X} X X/*VARARGS1*/ Xoops(fmt, args) Xchar *fmt; X{ X#ifdef VPRINTF X vprintf(fmt, &args); X#else X _doprnt(fmt, &args, stdout); X#endif /* VPRINTF */ X perror(""); X} X Xdie() X{ X set_redraw_signal_key_to(0); /* reset to original, whatever it was */ X#ifdef BSD X if (mode == TWOPLAYER) X destroysocket(); X#endif /* BSD */ X nocrmode(), echo(), endwin(); X exit(0); X} X Xonintr(sig) X{ X int x, y; X X (void) signal(sig, onintr); X (void) alarm(0); X if (sig != SIGPIPE) { X getyx(stdscr, y, x); X msg("Really quit? "); X if (getchar() != 'y') { X move(y, x); X if (Length && Width) X bottom_line(); X else X refresh(); X return; X } X } X msg(""); X if (sig != SIGINT && sig != SIGQUIT) { X if (sig == SIGPIPE) X#ifdef BSD X destroysocket(), fprintf(stderr, "Your opponent terminated.\n"); X#else X fprintf (stderr, "Shouldn't have ever got here, but your opponent quit\n"); X#endif /* BSD */ X else X#ifdef BSD X printw("I got signal #%d: %s", sig, sys_siglist[sig]); X#else X printw("I got signal #%d", sig); X#endif /* BSD */ X clrtoeol(); X refresh(); X } X if (jmpbuf_set && sig != SIGINT && sig != SIGQUIT) X longjmp(menu_jmp, 1); X die(); X} X XCursor(a, b) Xint a, b; X{ X move(y_start + b - 1, x_start + a * 2 - 2), refresh(); X} X Xis_on_board(x, y) Xregister int x, y; X{ X return (x > 0 && y > 0 && x < 2 * Length && y < 2 * Width); X} X Xputinitial(x, y, owner) Xregister int x, y, owner; X{ X Cursor(x, y); X addch(Initial[owner]); X refresh(); X board[x][y] = owner; X} X Xshell() X{ X register char *SHELL; X register int pid, w; X int status, (*oq)(), (*oi)(), (*signal())(); X X clear(), refresh(); X printf("Which Shell, (sh / csh (s/c))? "); X SHELL = (getchar() == 'c') ? "/bin/csh" : "/bin/sh"; X echo(), nocrmode(); X X oi = signal(SIGINT, SIG_IGN); /* old interrupt (oi) and old quit (oq) */ X oq = signal(SIGQUIT, SIG_IGN); /* signals saved on return of signal() */ X X if ((pid = fork()) == 0) { X setuid(getuid()); X setgid(getgid()); X execl(SHELL, SHELL, 0); X oops("Couldn't execl(%s)", SHELL); X _exit(127); X } X while ((w = wait(&status)) != pid && w != -1) X ; X printf("[Hit return to continue]"); X while (getchar() != '\n') X ; X X (void) signal(SIGINT, oi); /* reset old signals */ X (void) signal(SIGQUIT, oq); X noecho(), crmode(); X drawboard(), bottom_line(); X return (status); X} END_OF_misc.c if test 8465 -ne `wc -c <misc.c`; then echo shar: \"misc.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f person.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"person.c\" else echo shar: Extracting \"person.c\" \(3829 characters\) sed "s/^X//" >person.c <<'END_OF_person.c' X/* PERSON.C */ X X#include "dots.h" X X#define ever (;;) X Xpersonmove() X{ X char c; X int fd = ((mover == US) ? 0 : sd); X X Cursor(xposit, yposit); /* do this so raw mode won't destroy screen */ X raw(); X noraw(); /* flush type-ahead */ X bottom_line(); X do { X for ever { X if (read(fd, &c, 1) <= 0) X onintr(SIGPIPE); /* someone terminated */ X if (mode == TWOPLAYER) X if (c == '!' || c == 'S' || c == '.' || c == '/' || c == 'Q') X continue; X else if (c != 'r' && fd != sd) X (void) write(sd, &c, 1); /* send info to other player */ X if (c == '\n' || c == ' ') X break; X Cursor(xposit, yposit); X switch (c) { X case ESC: X if (mode == TWOPLAYER) X talk(); X X when '?': X if (mover == US) X readinst(0), drawboard(); X if (mode == TWOPLAYER) X if (mover == THEM) { X msg("%s is reading the instructions.", opponent); X if (read(fd, &c, 1) <= 0) /* wait for a char */ X onintr(SIGPIPE); X } else X (void) write(sd, &c, sizeof(c)); X bottom_line(); X when '!': X if (shell() == -1) X perror("shell"); X when 'Q': X if (mode != TWOPLAYER) X end_of_game(); X else X onintr(SIGPIPE); X when 'S': Save_game(); X when 'r': redraw(); X when '7': case 'q': case 'y': X if (is_on_board(xposit - 1, yposit - 1)) X xposit -= 1, yposit -= 1; X when '8': case 'w': case 'k': X if (is_on_board(xposit, yposit - 2)) X yposit -= 2; X when '9': case 'e': case 'u': X if (is_on_board(xposit + 1, yposit - 1)) X xposit += 1, yposit -= 1; X when '4': case 'a': case 'h': X if (is_on_board(xposit - 2, yposit)) X xposit -= 2; X when '6': case 'd': case 'l': X if (is_on_board(xposit + 2, yposit)) X xposit += 2; X when '1': case 'z': case 'b': X if (is_on_board(xposit - 1, yposit + 1)) X xposit -= 1, yposit += 1; X when '2': case 'x': case 'j': X if (is_on_board(xposit, yposit + 2)) X yposit += 2; X when '3': case 'c': case 'n': X if (is_on_board(xposit + 1, yposit + 1)) X xposit += 1, yposit += 1; X when '.': chlevel(c); X } X Cursor(xposit, yposit); X } X if (board[xposit][yposit] == USED && mover == US) { X mvaddstr(LINES - 1, 0, "It's taken. "); X Cursor(xposit, yposit); X } X } X while (board[xposit][yposit] == USED); X return entermove(); X} X X#define Addch(c) addch(c); if (mode == TWOPLAYER) (void) write(sd, &c, 1) X#define backspace() Addch(back_char); Addch(space); Addch(back_char); refresh() X XGetstr(String, length) Xchar *String; Xint length; X{ X char garbage, space = ' ', back_char = erase_char; X extern struct sgttyb _tty; /* curses library has this */ X int count = 0; X X while ((garbage = getchar()) != '\n' && garbage != 4 && garbage != ESC) X if (garbage == _tty.sg_erase && count) { X backspace(); X String[count--] = 0; X } else if (garbage == _tty.sg_kill && count) X do { X backspace(); X } while (--count); X else if (garbage == '\027' && count) /* ^W */ X do { X backspace(); X String[count--] = 0; X if (!count || (String[count-1]==' ' && !isspace(String[count]))) X break; X } while (count); X else if (count == length) X fputc('\007', stderr); X else if (garbage > 31 && garbage != 127) { X String[count++] = garbage; X Addch(garbage); X refresh(); X } X String[count] = 0; X} X Xtalk() X{ X char c, dummy[128], cr = '\n'; X int nread = 0; X X if (mover == US) { X move(LINES - 3, 15); X clrtoeol(), refresh(); X Getstr(dummy, COLS - 16); X (void) write(sd, &cr, 1); X } else { X move(LINES - 2, strlen(opponent) + 3 + strlen("Messages: ")); X clrtoeol(); X refresh(); X while ((nread = read(sd, &c, 1)) > 0 && c != cr) X addch(c), refresh(); X if (nread == -1) X oops("bad socket read"); X } X} END_OF_person.c if test 3829 -ne `wc -c <person.c`; then echo shar: \"person.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f save.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"save.c\" else echo shar: Extracting \"save.c\" \(4337 characters\) sed "s/^X//" >save.c <<'END_OF_save.c' X/* SAVE.C */ X X#include "dots.h" X XSave_game() X{ X int c; X FILE *fp; X char buf[40]; X X buf[0] = 0; X X msg("File: %s? ", save_file); X if ((c = getchar()) != 'Y' && c != 'y') { X if (c != ESC) { X msg("File: "); X Getstr(buf, min(40, COLS - 8)); X if (strlen(buf) > 1) X (void) strcpy(save_file, buf); X } X } else X (void) strcpy(buf, save_file); X if (*buf) X if (!(fp = fopen(buf, "w"))) { X msg("Couldn't open %s: %s --more--", save_file, sys_errlist[errno]); X while (getchar() != ' ') X fputc(7, stderr); X } else { X c = save(fp, SAVE); X (void) fclose(fp); X if (c) X fputc('\n', stdout), die(); X } X bottom_line(); X} X Xrecover(before) Xbool before; X{ X int c, xspot, yspot; X FILE *fp; X X if (!before) { X getyx(stdscr, yspot, xspot); X msg("File: %s? ", save_file); X if ((c = getchar()) != 'Y' && c != 'y') X if (c != ESC) { X char buf[40]; X msg("Input Filename: "); X Getstr(buf, min(40, COLS - 17)); X move(LINES - 1, 0); X refresh(); X if (strlen(buf) < 2) { X move(yspot, xspot); X refresh(); X return 0; X } else X (void) strcpy(save_file, buf); X } else X return 0; X } X if (!(fp = fopen(save_file, "r"))) X if (before) X perror(save_file); X else X msg("Couldn't open %s: %s", save_file, sys_errlist[errno]); X else if (save(fp, LOAD)) { X (void) fclose(fp); X if (unlink(save_file) < 0) X oops("Couldn't unlink savefile"), puts("Are you trying to cheat?"); X return 1; X } else { X (void) fclose(fp); X if (before) X putchar('\n'), die(); X } X if (!before) X move(yspot, xspot), refresh(); X return 0; X} X Xsave(fp, funct) XFILE *fp; X{ X register int x, y; X int i; X X if (funct == LOAD) { X char V[80], *p; X X if (fgets(V, 80, fp) && (p = index (V, '\n'))) X *p = 0; X if (strcmp(V, version)) { X printf("Sorry, file is wrong version."); X return FALSE; X } X if (fscanf (fp, "persontally = %d\n", &persontally) < 1 || X fscanf (fp, "comptally = %d\n", &comptally) < 1 || X fscanf (fp, "Length = %d\n", &Length) < 1 || X fscanf (fp, "Width = %d\n", &Width) < 1) X goto bad; X for (x = 0; x < Length * 2; ++x) X for (y = 0; y < Width * 2; ++y) { X if (fscanf (fp, "board[%*d][%*d] = %d\n", &i) < 1) X goto bad; X board[x][y] = i; X } X if (fscanf (fp, "xposit = %d\n", &xposit) < 1 || X fscanf (fp, "yposit = %d\n", &yposit) < 1 || X fscanf (fp, "x_start = %d\n", &x_start) < 1 || X fscanf (fp, "y_start = %d\n", &y_start) < 1 || X fscanf (fp, "no_good_moves = %d\n", &no_good_moves) < 1 || X fscanf (fp, "control_already_established = %d\n", X &control_already_established) < 1 || X fscanf (fp, "segtype = %d\n", &segtype) < 1 || X fscanf (fp, "dX_found = %d\n", &dX_found) < 1 || X fscanf (fp, "segflag = %d\n", &segflag) < 1 || X fscanf (fp, "mode = %d\n", &mode) < 1 || X fscanf (fp, "level = %d\n", &level) < 1 || X fscanf (fp, "Bingo.x = %d, Bingo.y = %d\n", X &Bingo.x, &Bingo.y) < 2 || X fscanf (fp, "Initial = %2c\n", Initial) < 1 || X fscanf (fp, "mover = %d\n", &mover) < 1) X goto bad; X if (Length < 4 || Width < 4) { Xbad: X msg("File has been corrupted."); X return FALSE; X } X } else { X (void) fprintf(fp, "%s\n", version); X fprintf (fp, "persontally = %d\n", persontally); X fprintf (fp, "comptally = %d\n", comptally); X fprintf (fp, "Length = %d\n", Length); X fprintf (fp, "Width = %d\n", Width); X for (x = 0; x < Length * 2; ++x) X for (y = 0; y < Width * 2; ++y) X fprintf (fp, "board[%d][%d] = %d\n", x, y, board[x][y]); X fprintf (fp, "xposit = %d\n", xposit); X fprintf (fp, "yposit = %d\n", yposit); X fprintf (fp, "x_start = %d\n", x_start); X fprintf (fp, "y_start = %d\n", y_start); X fprintf (fp, "no_good_moves = %d\n", no_good_moves); X fprintf (fp, "control_already_established = %d\n", X control_already_established); X fprintf (fp, "segtype = %d\n", segtype); X fprintf (fp, "dX_found = %d\n", dX_found); X fprintf (fp, "segflag = %d\n", segflag); X fprintf (fp, "mode = %d\n", mode); X fprintf (fp, "level = %d\n", level); X fprintf (fp, "Bingo.x = %d, Bingo.y = %d\n", Bingo.x, Bingo.y); X fprintf (fp, "Initial = %.2s\n", Initial); X fprintf (fp, "mover = %d\n", mover); X } X return TRUE; X} END_OF_save.c if test 4337 -ne `wc -c <save.c`; then echo shar: \"save.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f score.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"score.c\" else echo shar: Extracting \"score.c\" \(2371 characters\) sed "s/^X//" >score.c <<'END_OF_score.c' X/* SCORE.C */ X X#include "dots.h" X X#define NAMELEN 30 X Xstruct scores { X int sc_person; X int sc_comp; X char sc_name[NAMELEN]; X int sc_level; X int sc_width; X int sc_length; X char sc_login[9]; X} top_ten[10]; X Xhigh_score(Read, names) Xbool Read, names; X{ X struct scores *scp, *temp; X int fd; X X for (scp = top_ten; scp < &top_ten[10]; scp++) { X scp->sc_name[0] = 0; X scp->sc_login[0] = 0; X scp->sc_length = 0; X scp->sc_width = 0; X scp->sc_person = 0; X scp->sc_comp = 0; X scp->sc_level = 0; X } X X /* read the top ten file into the array and close the file */ X if ((fd = open(SCOREFILE, 2)) < 0) { X printf("no score file\n"); X return; X } X (void) read(fd, (char *) top_ten, sizeof(top_ten)); X X /* Print the list */ X if (Read) { X printf("Top Players:\n"); X printf("Level\tDimensions Computer Human\tName\n"); X for (scp = top_ten; scp < &top_ten[10]; scp++) X if (scp->sc_person) { X printf("%s\t %2d X %2d %3d %3d\t%s", X (scp->sc_level == DUMB) ? X "Easy" : (scp->sc_level == HARD ? X "Hard" : "Killer"), X scp->sc_width, X scp->sc_length, scp->sc_comp, scp->sc_person, scp->sc_name); X if (names) X printf("(%s)", scp->sc_login); X putchar('\n'); X } else X break; X } X /* check to see if current score made it */ X else { X for (scp = top_ten; scp < &top_ten[10]; scp++) X if (value_cmp(scp)) X break; X if (scp < &top_ten[10]) { X char *getlogin(), *login = getlogin(); X X for (temp = &top_ten[9]; temp > scp; temp--) X *temp = *(temp - 1); X scp->sc_width = Width; X scp->sc_length = Length; X scp->sc_person = persontally; X scp->sc_comp = comptally; X scp->sc_level = level; X (void) strcpy(scp->sc_login, login); X addstr("--more--"), clrtoeol(); X refresh(); X raw(), noraw(); X while (getchar() != ' ') X fputc(7, stderr); X msg("You made the top ten! Enter a name: "); X Getstr(scp->sc_name, NAMELEN - 1); X if (strlen(scp->sc_name) > 1) { X (void) lseek(fd, (long)0, 0); X (void) write(fd, (char *)top_ten, sizeof top_ten); X } else X msg("Nothing entered."); X } X (void) close(fd); X } X} X Xvalue_cmp(entry) Xstruct scores *entry; X{ X int value; X X value = (level - entry->sc_level) * 500; X value += persontally + Length * Width; X return (value > entry->sc_length * entry->sc_width + entry->sc_person); X} END_OF_score.c if test 2371 -ne `wc -c <score.c`; then echo shar: \"score.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f sockt.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"sockt.c\" else echo shar: Extracting \"sockt.c\" \(4229 characters\) sed "s/^X//" >sockt.c <<'END_OF_sockt.c' X/* sockt.c */ X/* All the stuff that deals with sockets is here */ X X#include "dots.h" X#include <sys/un.h> /* unix domain sockets */ X#include <errno.h> X X#define SOCKNAME "/tmp/dots" X X#define namelen(sockt) (sizeof (sockt.sun_family) + strlen(sockt.sun_path)) X Xint len; Xstatic int (*oldint)(), (*oldquit)(); Xstruct sockaddr_un sockt; X Xsockit(argc, argv) Xchar **argv; X{ X setbuf(stdout, (char *)NULL); X X mover = THEM; X opponent = argv[2]; X Initial[THEM] = *opponent; X X (void) strcpy(sockt.sun_path, SOCKNAME); X len = namelen(sockt); X X if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { /* create a socket */ X oops("Socket error"); X return; X } X X /* try to respond to a possible connection already established */ X while (connect(sd, (struct sockaddr *)&sockt, namelen(sockt)) == -1) X /* X * check to see if we can't connect because of "correct" errors X */ X if (errno != ENOENT) { /* no such file or directory */ X perror("connect on socket"); X puts("Trying again..."); X (void) close(sd); X sockit(argc, argv); X } else { X mover = US; /* challenger goes first */ X if (!findem(argc, argv)) X return; X else X break; X } X getsizes(); /* get the window sizes of both players */ X Dots(2); /* we are connected and won't return */ X} X X/* send an invitation */ X X#include <sys/time.h> Xstruct itimerval waittime; Xjmp_buf jmpbuf; X Xreinvite(sig) X{ X if (sig == SIGALRM) { X printf("\nre"); X longjmp(jmpbuf, 1); X } X timerclear(&waittime.it_interval); X timerclear(&waittime.it_value); X (void) setitimer(ITIMER_REAL, &waittime, (struct itimerval *) 0); X destroysocket(); X (void) signal(SIGINT, oldint); X (void) signal(SIGQUIT, oldquit); X longjmp(jmpbuf, 2); X} X Xinvite(recipient) XFILE *recipient; X{ X int newsok; X X waittime.it_value.tv_sec = 30; X waittime.it_value.tv_usec = 0; X waittime.it_interval = waittime.it_value; X X /* X * we're a server, so we give a name to the socket to the client knows X * what to connect with. bind() is used to give a name to a socket. X */ X if (bind(sd, (struct sockaddr *)&sockt, len) == -1) { X oops("Can't bind %s", SOCKNAME); X return 0; X } X if (listen(sd, 5) == -1) { X oops("Can't listen %s", SOCKNAME); X return 0; X } X X setbuf(recipient, (char *)NULL); X X /* X * accept() will hang around and do nothing unless someone requests a X * connection. So, we wait.. signal again every 30 secs with setitmer X */ X (void) signal(SIGALRM, reinvite); X oldint = signal(SIGINT, reinvite); X oldquit = signal(SIGQUIT, reinvite); X (void) setitimer(ITIMER_REAL, &waittime, (struct itimerval *) 0); X if (setjmp(jmpbuf) == 2) X return 0; X printf("sending challenge..."); X fprintf(recipient, "Message from the \"dots\" game...\007\007\007\n"); X fprintf(recipient, "%s would like to play \"dots.\"\n", username); X fprintf(recipient, "respond with \"dots 2 %s\"\n", username); X X while ((newsok = accept(sd, (struct sockaddr *)0, (int *)0)) == -1) X if (errno != EINTR) { X oops("Can't accept %s", SOCKNAME); X return 0; X } else X continue; X X timerclear(&waittime.it_interval); X timerclear(&waittime.it_value); X (void) setitimer(ITIMER_REAL, &waittime, (struct itimerval *) 0); X (void) close(sd); X sd = newsok; X return 1; X} X X /* find lines and cols of the other guy */ Xgetsizes() X{ X int their_lines, their_cols; X X do_twice { X if (mover == US) { X (void) write(sd, (char *)&COLS, sizeof(int)); X (void) write(sd, (char *)&LINES, sizeof(int)); X } else { X (void) read(sd, (char *)&their_cols, sizeof(int)); X (void) read(sd, (char *)&their_lines, sizeof(int)); X } X mover = !mover; X } X Length = min(COLS, their_cols) / 4; X Width = min(LINES, their_lines) / 2 - 2; X comptally = persontally = 0; X xposit = 2, yposit = 1; X y_start = 1 + (LINES - 2) / 2 - Width; X x_start = 1 + COLS / 2 - Length * 2; X X (void) signal(SIGINT, oldint); X (void) signal(SIGQUIT, oldquit); X} X Xdestroysocket() X{ X if (!access(SOCKNAME, 0)) { X if (shutdown(sd, 2) == -1) /* dissallow further sends and recieves */ X oops("shutdown failed cuz"); X if (unlink(SOCKNAME) == -1) X oops("Can't unlink %s", SOCKNAME); X } X} END_OF_sockt.c if test 4229 -ne `wc -c <sockt.c`; then echo shar: \"sockt.c\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of shell archive. exit 0