From decwrl!wuarchive!cs.utexas.edu!uunet!zephyr.ens.tek.com!tekred!saab!billr Fri Apr 6 18:41:12 PDT 1990 Article 858 of comp.sources.games: Path: decwrl!wuarchive!cs.utexas.edu!uunet!zephyr.ens.tek.com!tekred!saab!billr From: billr@saab.CNA.TEK.COM (Bill Randle) Newsgroups: comp.sources.games Subject: v09i035: luffa - a full screen X and O's game, Part01/01 Message-ID: <5416@tekred.CNA.TEK.COM> Date: 5 Apr 90 21:17:30 GMT Sender: news@tekred.CNA.TEK.COM Lines: 1033 Approved: billr@saab.CNA.TEK.COM Submitted-by: Jon W{tte Posting-number: Volume 9, Issue 35 Archive-name: luffa/Part01 [I renamed a few files and made a simple Makefile to make things a little more standardized. Works on my Sun 3/60 (OS 3.5). -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 'README' <<'END_OF_FILE' XLuffa - a full screen game X XThe game is played on a grid, and the object of the game is to Xget five of your marks (X'es or O's) in a row. A special rule Xsays that you may not place your second mark within two squares Xof the first mark if you begin the game, to even out the odds. X XLuffa accepts most terminals that curses know of. XLuffa accepts the following options: X -g Play on a grid X -o Play O's X -e Use ! in grid X -c Let computer begin X -h toggle hilite mode X -x Play X's (this is default) X -b Use | for grids (this is default) X XLuffa accepts the following input: X h,H,4 Move cursor left X l,L,6 Move cursor right X j,J,2 Move cursor down X k,K,8 Move cursor up X SPACE Place mark X ^L,^R Redraw screen X !, ^Z Shell escape X ^C Quit X S Save game X XLuffa was written by Jon W{tte at kth (h+@nada.kth.se) 890414-15 XLuffa has been successfully compiled on a PYRAMID 98xx running BSD 4.3 Xand on a STRIDE 460 (M68k) running UniStride 2.1, which is compatible Xwith V.2 and BSD 4.3 X XPlaying strength is far from professional, but at least you won't lose Xall the time :-) X XLuffa is copyright 1989 Jon Watte, but may be freely redistributed Xas is and including this copyright notice. If you make any changes, Xit's your problem and you'd better keep me out of it ! END_OF_FILE if test 1267 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(206 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' X# simple makefile for luffa X# flags and libs for Sys V X#CFLAGS = X#LIBS = -lcurses X X# flags and libs for BSD XCFLAGS = -D_BSD_ XLIBS = -lcurses -ltermcap X Xluffa: luffa.c X cc $(CFLAGS) -o luffa luffa.c $(LIBS) END_OF_FILE if test 206 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'luffa.6' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'luffa.6'\" else echo shar: Extracting \"'luffa.6'\" \(1942 characters\) sed "s/^X//" >'luffa.6' <<'END_OF_FILE' X.TH LUFFA 6 X.SH NAME Xluffa \- a full screen X's and O's game X X.SH SYNOPSIS Xluffa [-goxbechd] X X.SH OPTIONS XThe options let you do the following: X X.I -g X-- play on a grid (default is blank screen) X X.I -o X-- play the O's (default is X's) X X.I -x X-- play the X's (this is default) X X.I -e X-- use ! (exclamation mark) in the grid X X.I -b X-- use | (vertical bar) in the grid (this is default) X X.I -c X-- Let the computer begin the game X X.I -h X-- toggle hilite mode X X X.SH DESCRIPTION X.I Luffa Xis a full screen game where the object is to get Xfive X-es in a line. Of course, the computer tries to Xget five O-s in a line. The first one to accomplish this Xis the winner. Simple as that. X X.I Luffa Xwill run with most terminals, provided direct addressing and standout Xis available to the CURSES library. You control the cursor movement Xwith the hjkl keys, or the numeric keypad keys 8, 4, 6 and 2. You Xplace your mark with the space bar, unless the selected position is Xillegal. This is marked with a "Out of bounds" message. ^L or ^R Xredraws the screen, ^C quits. ! or ^Z is used for shell escape. s Xsaves the current game and exits. Luffa will check for a saved game Xupon invocation, and, if present, load and unlink the saved game. X X.I Luffa Xruns under the world championship rules: the one who begins may not Xplace his second mark within two squares of the first. This is to Xeven out the odds. Attempting to do this gives a "Not as second move" Xmessage. X X.SH FILES X~/.luffasav -- game save file X X.SH DIAGNOSTICS Xusage: luffa [-goxbechd] -- Bad option line format X X.SH WARNINGS XOut of bounds: Not allowed to place mark there XAlready occupied: You can't place a mark on top of another XNot as second move: Violation of the W.C. rules X X.SH BUGS AND CAVEATS XThere are ways to win... Also, there is no way to suppress Xthe loading of a saved game, except renaming the save file X X.SH AUTHOR XJon W{tte (H+) X X.\" @(#)luffa.l 890415 X X END_OF_FILE if test 1942 -ne `wc -c <'luffa.6'`; then echo shar: \"'luffa.6'\" unpacked with wrong size! fi # end of 'luffa.6' fi if test -f 'luffa.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'luffa.c'\" else echo shar: Extracting \"'luffa.c'\" \(14694 characters\) sed "s/^X//" >'luffa.c' <<'END_OF_FILE' X/* X * luffa.c X * X * This program, which is a full-screen game, can be made by typing X * cc luffa.c -o luffa -lcurses X * on a sysV system, or by typing X * cc luffa.c -o luffa -lcurses -ltermcap -D_BSD_ X * on BSD 4 X * X * It was written by Jon W{tte (h+@nada.kth.se) X * X * Options: X * -g Play on a grid X * -o Play O's X * -x Play X's (default) X * -b Play with bars (default) X * -e Play with exclamation marks. X * -c The computer begins X * -h Toggle hilight (i.e. hilite on plain, normal on grid) X * -d enable debug mode (enter with 'd') X * X * Diagnostics: X * Usage: Error While parsing options X * X * input: h, j, k, l, 8, 4, 6, 2 to move cursor. X * SPACE to place mark X * ^L or ^R to redraw screen X * s to save game and quit (except when in debug mode) X * ^C to quit. X * ! and ^Z for shell escape X * X * it also features a debugging mode, where the player may put as X * many marks as he like, and check what value a location has. X * This is toggeled by pressing 'd', and value is shown on 's' X * X * Happy gaming ! X */ X X/* X * The listing was, in the beginning, three different files: X * X */ X X/* X * Newgame.h X * X * By Jon W{tte 1989 X * X * This file includes include code for the new game X * X */ X X/* Define this to make it smarter but slower */ X/* #define _SMART_ */ X X#define SIZE_X 22 X#define SIZE_Y 22 X#define PLAYER 1 X#define COMPUTER 2 X#define NO_PLAYER 0 X#define NO_PROBLEM ((int) -1) X X#define WELCOME 0 X#define OUT_BOUNDS 1 X#define IS_OCCUPIED 2 X#define YOU_WIN 3 X#define I_WIN 4 X#define NOT_SECOND 5 X#define DEBUGGING_MODE 6 X X#define until(x) while(!(x)) X#define max(a,b) ((a)>(b)?(a):(b)) X#define min(a,b) ((a)<(b)?(a):(b)) X Xextern int game_map[SIZE_X][SIZE_Y]; Xextern int QUIT; X/* X * Gameconst.h X * By Jon W{tte X * X * This file contains constants definitions for the new game X * They affect how the game plays X * X */ X X#define NOT_HERE 0 X#define FREE_0 2 X X#define FREE_NEXT_HIM 5 X#define FNH_PLUS 1 X#define FNH_DIV 4 X X#define FREE_NEXT_ME 4 X#define FNM_PLUS 1 X#define FNM_DIV 1 X X#define I_WINS_NEXT_MOVE 90 X#define HE_WINS 100 X#define I_WINS 127 /* I know there's a spelling error here */ X X#define HE_MIGHT_WIN 30 X#define I_MIGHT_WIN 26 X X#define IMPORTANT_ADD 5 X X#define CHECK_TWO_PLUS 10 X#define CHECK_TWO_MUL 14 X/* X * Newgame.c X * X * This file contains the main part of the new game X * X */ X X#include X#include X#include X#include X X#define ERRCNT 1 X#define NOT_VALID 42 X X Xint game_map[SIZE_X][SIZE_Y]; Xint add_coordinate[8] = { X 0, 1, 1, 1, 0, -1, -1, -1 X }; Xchar E_MESG[][30] = { X "Welcome to luffa! (c) h+", X "Out of bounds", X "Already occupied", X "Congratulations: YOU WIN !!!", X "Too bad: You lose.", X "Not as second move", X "Not debugging", X "Debugging" X}; Xchar * PLAYERSIGN = "><"; Xchar * COMPUTERSIGN = "()"; Xchar * GRID_STR = "__|"; Xchar PROGNAME[256]; Xint QUIT; Xint ERRFLG; Xint IMPORTANT; Xint GRID; Xint HILITE; Xint DEBUGGING; Xint DEBUG_ABLE; Xint fx, fy; Xint movecnt; X X Xvoid init_grid() X{ X int x, y; X X for (x=0;x1); X} /* end int check_cross */ X X Xint check_fours(x, y) Xint x, y; X{ X register int r, d; X int flag, dis, dat; X int drng[4]; X X dis=get_im(x, y, 0, 0); X for(d=0; d<4; d++) drng[d]=0; X for(d=0; d<8; d++) { X flag=1; X for(r=1; r<=3; r++) { X dat = get_im(x, y, d, r); X if (dat == dis) { X drng[d % 4] += flag; X } else if((dat == NO_PLAYER) || !flag) { X flag=0; X } else { X flag=0; X drng[d % 4] = -15; X } X } X if(flag) drng[d % 4] -= 2; X } X flag=0; X for(d=0; d<4; d++) { X if(drng[d]>2) { X flag=1; X } X } X return flag; X} /* end int check_fours */ X X#endif X X Xint check_two(x, y) Xint x, y; X{ X int d, pcnt, mcnt, q, p; X X pcnt = 0; X mcnt = 0; X for(d=0; d<8; d++) { X q = get_im(x,y,d,1); X p = get_im(x,y,d,3); X if((q == get_im(x,y,d,2)) && X ((p == NO_PLAYER) || (p == q))) { X if (q == PLAYER) { X pcnt++; X } else if(q == COMPUTER) { X mcnt++; X } X } X } X X return max(pcnt, mcnt); X} X X Xint check_neighbours(x, y, sign) Xint x, y, sign; X{ X int ret, d; X X ret = 0; X for(d=0; d<8; d++) X if(get_im(x, y, d, 1) == sign) X ret++; X X return ret; X} /* end int check_neigbours(int a, b, sign) */ X X Xint calc_gain(x, y) Xint x, y; X{ X int ret, s; X register int q; X X#ifdef _SMART_ X char str[10]; X#endif X X if(game_map[x][y]!=NO_PLAYER) { X return NOT_HERE; X } else { X ret = FREE_0; X X q = check_neighbours(x, y, PLAYER); X if(q) { X q = FREE_NEXT_HIM+((FNH_PLUS+q) / FNH_DIV); X } X ret = max(ret,q); X X q = check_neighbours(x, y, COMPUTER); X if(q) { X q = FREE_NEXT_ME+((FNM_PLUS+q) / FNM_DIV); X } X ret = max(ret,q); X X game_map[x][y]=PLAYER; X X#ifdef _SMART_ X if(DEBUGGING) { X q = (check_win(x, y, 0) == PLAYER); X move(5,74); X sprintf(str,"%d",q); X addstr(str); X } X#endif X X if(check_win(x, y, 2) == PLAYER) { X ret = max(ret,HE_MIGHT_WIN); X } X X#ifdef _SMART_ X if(DEBUGGING) { X q = check_cross(x, y); X move(7,74); X sprintf(str,"CC:%d",q); X addstr(str); X } X if(DEBUGGING) { X q = check_fours(x, y); X move(8,74); X sprintf(str,"Cf:%d",q); X addstr(str); X } X if(check_cross(x, y) || check_fours(x, y)) { X ret = max(ret,HE_WINS); X } X#endif X X if(check_win(x, y, 0) == PLAYER) { X ret = max(ret,HE_WINS); X } X if(IMPORTANT) { X ret = max(ret,HE_MIGHT_WIN+IMPORTANT * IMPORTANT_ADD); X } X game_map[x][y]=COMPUTER; X if(check_win(x, y, 2) == COMPUTER) { X ret = max(ret,I_MIGHT_WIN); X } X X#ifdef _SMART_ X if(check_cross(x, y) || check_fours(x, y)) { X ret = max(ret,I_WINS_NEXT_MOVE); X } X#endif X X if(check_win(x, y, 0) == COMPUTER) { X ret = max(ret,I_WINS); X } X X#ifdef _SMART_ X if(DEBUGGING) { X q = (check_win(x, y, 0) == COMPUTER); X move(6,74); X sprintf(str,"%d",q); X addstr(str); X } X#endif X X if(IMPORTANT) { X ret = max(ret,I_MIGHT_WIN+IMPORTANT * IMPORTANT_ADD); X } X game_map[x][y]=NO_PLAYER; X X q = check_two(x, y); X if (q) { X ret = max(ret,q * CHECK_TWO_MUL + CHECK_TWO_PLUS); X } X X return ret; X } X} /* end int calc_gain(int x, y); */ X X Xint get_im(x, y, r, d) Xint x, y, r, d; X{ X x += add_coordinate[r]*d; X y += add_coordinate[(r+2) % 8]*d; X X if((x>=SIZE_X) || (x<0) || (y>=SIZE_Y) || (y<0)){ X return NOT_VALID; X } else { X if(movecnt==2) { X if((abs(x-fx)<3) && (abs(y-fy)<3)) { X return NOT_VALID; X } X } X r = game_map[x][y]; X if(r == NO_PROBLEM) { X r = NO_PLAYER; X } X return r; X } X} X X Xvoid ask_luser(x, y) Xint *x, *y; X{ X int c, decided, xx, yy, foo; X char str[10]; X char filename[256]; X X do { X decided = 0; X X do { X move(*x, *y * 3); X refresh(); X c=getch(); X if(ERRFLG) { X ERRFLG--; X if(!ERRFLG) { X move(22,0); X if(HILITE) standend(); X addstr(" "); X if(HILITE) standout(); X refresh(); X } X } X switch(c) { X case 'd' : X case 'D' : { X DEBUGGING = DEBUG_ABLE * !DEBUGGING; X myerr(DEBUGGING_MODE + DEBUGGING); X break; X } X case 's' : X case 'S' : if(DEBUGGING) { X c=calc_gain(*x, *y); X move(4,74); X sprintf(str,"%3d",c); X addstr(str); X refresh(); X } else { /* Save file */ X#ifdef _BSD_ X strcpy(filename,getenv("HOME")); X strcat(filename,"/.luffasav"); X c=open(filename,O_CREAT | O_TRUNC, 384); X close(c); X c=open(filename,O_WRONLY, 384); X write(c, (char *) game_map, sizeof(int) * SIZE_X * SIZE_Y); X write(c, (char *) &movecnt, sizeof(int)); X close(c); X#endif X QUIT=1; X } X break; X case 'h' : X case '4' : X case 'H' : { X *y-=1; X break; X } X case 'l' : X case '6' : X case 'L' : { X *y+=1; X break; X } X case 'j' : X case '2' : X case 'J' : { X *x+=1; X break; X } X case 'k' : X case '8' : X case 'K' : { X *x-=1; X break; X } X case 12 : /* ^L */ X case 18 : { /* ^R */ X rebuild_screen(); X break; X } X case 'Z' - 64 : /* ^Z */ X case '!' : { X setuid(getuid()); X getgid(getgid()); X move(23,0); X addstr("Type exit to get back"); X noraw(); X nl(); X echo(); X nocrmode(); X#ifdef _BSD_ X resetty(); X#else X resetterm(); X#endif X refresh(); X system(getenv("SHELL")); X crmode(); X noecho(); X nonl(); X raw(); X setuid(geteuid()); X setgid(getegid()); X rebuild_screen(); X break; X } X default : X break; X } X X if(*x<0) { X myerr(OUT_BOUNDS); X *x=0; X } X if(*x>=SIZE_X) { X myerr(OUT_BOUNDS); X *x=SIZE_X-1; X } X if(*y<0) { X myerr(OUT_BOUNDS); X *y=0; X } X if(*y>=SIZE_Y) { X myerr(OUT_BOUNDS); X *y=SIZE_Y-1; X } X X foo = get_im(*x, *y, 0, 0); X sprintf(str, "%2d,%2d", *y, *x); X move(0,73); X addstr(str); X move(*x, *y * 3); X refresh(); X } until((c==3) || (c==32) || (c==13)); X X if(c==3) QUIT=1; X if(get_im(*x, *y, 0, 0) == NO_PLAYER) { X decided=1; X } else { X if(!QUIT) { X if(movecnt>3) { X myerr(IS_OCCUPIED); X } else { X myerr(NOT_SECOND); X } X } X } X } until(decided || QUIT); X X game_map[*x][*y] = PLAYER; X for(xx=max((*x)-2,0); xx c) || X (((rand() % 10) < 4) && (move_map[a][b] == c))) { X dx=a; X dy=b; X c=move_map[a][b]; X } X *x=dx; X *y=dy; X} /* end void check_move(int *x, *y) */ X X Xint check_win(x, y, swit) Xint x, y, swit; X{ X register int d, r; X int flag, cnt, win, foo, num_xs[4]; X X IMPORTANT = 0; X for (r=0; r<8; r++) { X flag = 1; X if(r<4) { X num_xs[r]=0; X } X cnt = 1; X for (d=1; d<5; d++) { X foo = get_im(x, y, r, d); X if(game_map[x][y] == foo) { X num_xs[r % 4]+=flag; X } else { X if ((swit == 0) && (d == 4) && (foo == NO_PLAYER) && (flag > 0)) { X IMPORTANT++; X } else if ((swit == 2) && (foo == NO_PLAYER) && X (cnt > 0) && (d > 1)) { X cnt--; X num_xs[r % 4]+=flag; X } X if(flag) flag--; X } X } X } X X win = NO_PLAYER; X for(r=0; r<4; r++) X if(num_xs[r] > 3) { X win = game_map[x][y]; X } X X if((win == PLAYER) && (1==swit)) { X myerr(YOU_WIN); X } else if((win == COMPUTER) && (1==swit)) { X myerr(I_WIN); X } X X return win; X} /* end int check_win(int x, y, swit) */ X X Xmain(argc, argv) Xint argc; Xint * argv []; X{ X int x, y, winner, begflag; X register int xx, yy; X char foo[256]; X X strcpy(PROGNAME,argv[0]); X X init_grid(); X QUIT=0; X GRID=0; X ERRFLG=0; X HILITE=0; X DEBUGGING=0; X DEBUG_ABLE=0; X begflag=1; X movecnt=0; X winner=0; X X strcpy(foo,getenv("HOME")); X strcat(foo,"/.luffasav"); X /* Check for existing save file */ X#ifdef _BSD_ X if((x=open(foo, O_RDONLY, 384)) != -1) { X printf("Restoring file %s\n",foo); X read(x, game_map, sizeof(int) * SIZE_X * SIZE_Y); X read(x, &movecnt, sizeof(int)); X close(x); X unlink(foo); X } X#endif X X for(x=1; x<"); X strcpy(COMPUTERSIGN,"()"); X break; X } X case 'c' : begflag=0; X break; X case 'o' : { X strcpy(PLAYERSIGN,"()"); X strcpy(COMPUTERSIGN,"><"); X break; X } X case 'b' : { X strcpy(GRID_STR,"__|"); X break; X } X case 'e' : { X strcpy(GRID_STR,"__!"); X break; X } X default : usage_err(); X break; X } X y++; X } X } X } X X HILITE=GRID?!HILITE:HILITE; X X if(!QUIT) { X initscr(); X savetty(); X crmode(); X nonl(); X noecho(); X raw(); X clear(); X rebuild_screen(); X srand((int) (time((long *) 0) % 65536)); X myerr(WELCOME); X x=SIZE_X/2; X y=SIZE_Y/2; X X do { X if(begflag || movecnt) { X move(1,73); X sprintf(foo,"%d",movecnt); X addstr(foo); X refresh(); X ask_luser(&x, &y); X if(!QUIT) { X move(x, y*3); X addstr(PLAYERSIGN); X winner=check_win(x, y, 1); X refresh(); X } X } X if(!(winner || QUIT || DEBUGGING)) { X check_move(&x, &y); X move(x, y*3); X addstr(COMPUTERSIGN); X game_map[x][y] = COMPUTER; X for(xx=max(x-2,0); xx