Path: utzoo!attcan!uunet!munnari!gwydir!gara!wtoomey From: wtoomey@gara.une.oz (Warren Toomey) Newsgroups: comp.os.minix Subject: Curses(3) source, plus tic-tac-toe Keywords: Hack subset kludge Message-ID: <354@gara.une.oz> Date: 3 Oct 88 13:41:26 GMT Organization: University of New England, Armidale, Australia Lines: 540 Here is a set of Curses routines, which I purloined from a Public Domain spreadsheet a friend has. It doesn't have all the functions, however. I have also hacked it to use Termcap, instead of hard-wired Ansi codes, and the whole thing really needs rewriting, as some of the code is terrible! However, some Curses is better than no Curses. I've also included a tic-tac-toe program which uses Curses, and it compiles under 1.2 okay, except that the display is upside down; this won't happen on 1.3, as it uses Ansi codes & the screen origin is in the top-left corner. I must point out that I'll be busy doing my Honours thesis until mid-November, so if you have any problems, post to the net for help. If anybody has the desire to rewrite Curses fully & properly, go right ahead! I'll try & finish it off in November if no one else has. Cheers! +--------------------------------------------------------------------------+ |Warren Toomey | |Dept. of Computing Science ACSNET: wtoomey@gara.une.oz | |University of New England UUCP: ...!uunet!munnari!gara.une.oz!wtoomey | |Armidale Australia 2351 ARPA: wtoomey%gara.une.oz@uunet.uu.net | +--------------------------------------------------------------------------+ | "Life isn't as trivial as it seems, it only appears to be." | +--------------------------------------------------------------------------+ -----------cut, tear, mangle, rip, shred, tatter, score here---------------- echo x - MANIFEST gres '^X' '' > MANIFEST << '/' Xtotal 12 X-rwxr--r-- 1 src 403 Oct 3 22:58 Makefile X-rwxr--r-- 1 src 4095 Oct 3 21:31 curses.c X-rwxr--r-- 1 src 6422 Oct 3 22:59 ttt.c / echo x - Makefile gres '^X' '' > Makefile << '/' X# To make ttt without libcurses.a, just make X# X# To make ttt AND the libcurses.c, make lib (you might need to make clr too) X# XLIB = /usr/lib/libcurses.a XCFLAGS = -F -T. X X Xttt : ttt.s curses.s X cc -o ttt $(CFLAGS) ttt.s curses.s -ltermcap X X Xlib : libcurses ttt.s X ar r $(LIB) curses.s X cc -o ttt $(CFLAGS) ttt.s -lcurses -ltermcap X Xlibcurses : curses.c X cc -c $(CFLAGS) -LIB curses.c X Xclr : X rm *.s ttt / echo x - curses.c gres '^X' '' > curses.c << '/' X/************************************************************************ X * * X * Tiny pseudo "curses" package * X * * X * v1.0 870117 DBW - D. Wecker, initial hack * X * v1.1 881003 W. Toomey, hacked to get it to use * X * Termcap, and to not foul input. * X * Borrowed a bit of code from Alistair * X * Crooks' `show.c' posted on 870730. * X * * X ************************************************************************/ X X/* #include - the ioctl calls seem to stop input */ X#include X#include X#include Xstruct sgttyb old_tty,new_tty; X Xextern char *tgetstr(); /* termcap getstring capability */ Xextern char *tgoto(); /* termcap goto (x, y) */ Xextern char *getenv(); /* get an environment variable */ X X X#define ROWS 24 X#define COLS 80 X#define NORMAL 0x00 X#define BOLD 0x80 X Xchar termcap[1024]; /* termcap buffer */ Xchar tc[100]; /* area to hold string capabilities */ Xchar *ttytype; /* terminal type from env */ Xchar *arp; /* pointer for use in tgetstr */ Xchar *cp; /* character pointer */ X Xchar *cl; /* clear screen capability */ Xchar *cm; /* cursor motion capability */ Xchar *so; /* start standout capability */ Xchar *se; /* end standout capability */ X X Xchar nscrn[ROWS][COLS], X cscrn[ROWS][COLS], X row, X col, X mode; Xchar str[256]; X X X/* X * fatal - report error and die. Never returns X */ Xvoid Xfatal(s) Xchar *s; X{ X (void) fprintf(stderr, "curses: %s\n", s); X exit(1); X} X X X/* X * outc - call putchar, necessary because putchar is a macro. X */ Xint Xoutc(c) Xint c; X{ X putchar(c); X} X X Xmove(y,x) Xint y,x; X { X row = y; X col = x; X } X Xclrtoeol() { X int i; X X for (i = col; i < COLS; i++) nscrn[row][i] = ' ' | mode; X } X Xprintw(fmt,a1,a2,a3,a4,a5) Xchar *fmt,*a1,*a2,*a3,*a4,*a5; X { X int i,j,k; X X sprintf(str,fmt,a1,a2,a3,a4,a5); X j = 0; k=row; X for (i = col; i < COLS && k < ROWS && str[j] != '\000'; i++) X if (str[j] != '\n') X nscrn[k][i] = str[j++] | mode; X else { i=0; j++; k++; } X col = i; row=k; X } X Xclrtobot() { X int i,j; X X clrtoeol(); X for (i = row+1; i < ROWS; i++) X for (j = 0; j < COLS; j++) X nscrn[i][j] = ' ' | mode; X } X Xstandout() { X mode = BOLD; X } X Xstandend() { X mode = NORMAL; X } X Xaddstr(s) Xchar *s; X { X printw("%s",s); X } X Xinitscr() { X int i,j; X/* X ioctl(0,TIOCGETP,&old_tty); I don't have a clue X ioctl(0,TIOCGETP,&new_tty); why these are used, X new_tty.sg_flags |= RAW; but I've commented them X new_tty.sg_flags &= ~ECHO; out to get stdin working. X ioctl(0,TIOCSETP,&new_tty); X*/ X if ((ttytype = getenv("TERM")) == NULL) X fatal("No terminal type set in environment"); X X if (tgetent(termcap, ttytype) != 1) X fatal("No termcap entry for terminal"); X arp = tc; X cl = tgetstr("cl", &arp); X so = tgetstr("so", &arp); X se = tgetstr("se", &arp); X cm = tgetstr("cm", &arp); X X row = 0; X col = 0; X mode = NORMAL; X for (i = 0; i < ROWS; i++) X for (j = 0; j < COLS; j++) X nscrn[i][j] = cscrn[i][j] = ' '; X tputs(cl,1,outc); X } X Xclear() { X row = 0; X col = 0; X clrtobot(); X } X Xendwin() { X move(ROWS-1,0); X refresh(); X/* X ioctl(0,TIOCSETP,&old_tty); X */ X } X Xchar inch() { X return(nscrn[row][col] & 0x7F); X } X Xtouchwin() { X int i,j; X X for (i=0; i ttt.c << '/' X/***** Noughts and Crosses ****/ X X/* Copyright (C) 1988 Warren Toomey. X You may use, copy, modify, or give this away provided you X 1. make the source available with every copy. X 2. include this notice. X 3. don't use this for military purposes. X (but you can take credit for improvements, etc.) X*/ X X/* Compile with cc -o tic tic.c -lcurses -ltermcap */ X X#define CURSES X#ifdef CURSES X/* #include Used by the real curses */ X#endif X X#ifndef CURSES X#define printw printf X#endif X X Xtypedef struct { int value; /* The move returned by the */ X int path; /* alphabeta consists of a value */ X } MOVE; /* and an actual move (path) */ X X X /* Static evaluator. Returns 100 if we have 3 in a row X -100 if they have 3 in a row X X Game board is array of 9 ints, where 0=empty square X 1=our move X 4= their move X X and board is indices 0 1 2 X 3 4 5 X 6 7 8 X */ X X Xint stateval(board,whosemove) X int board[]; X X { X static int row[8][3]= { {0,1,2}, {3,4,5}, {6,7,8}, /* Indices of 3in-a-rows */ X {0,3,6}, {1,4,7}, {2,5,8}, X {0,4,8}, {2,4,6} }; X X int temp; /* Temp row results */ X int i,j; /* Loop counters */ X int side; /* Depth multiplier */ X int win,lose; X X if (whosemove==1) {win=100; lose= -100; side= 1;} /* Multiply by -1 if */ X else {win= -100; lose=100; side= -1;} /* not out move */ X for (i=0;i<8;i++) /* For every 3-in-a-row */ X { X temp=0; X for (j=0;j<3;j++) /* Add up the board values */ X temp += board[row[i][j]]; X X if (temp==3) return(win); /* We've got 3 in a row */ X if (temp==12) return(lose); /* They've got 3 in a row */ X } X return(0); /* Finally return sum */ X } X X XMOVE alphabeta(board,whosemove,alpha,beta) /* Alphabeta: takes a board, */ X int board[]; /* whose move, alpha & beta cutoffs, */ X int whosemove; /* and returns a move to make and */ X int alpha; /* the value that the move has */ X int beta; X { X MOVE result,successor; X int best_score,i,best_path,mademove; X X result.value=stateval(board,whosemove); /* Work out the board's */ X /* static value */ X if ((result.value==100)|| /* If a win or loss already */ X (result.value==-100)) return(result); /* return the result */ X X best_score= beta; /* Ok, set worst score */ X mademove=0; /* to the beta cutoff */ X for (i=0;i<9;i++) X { if (board[i]==0) /* For all valid moves */ X { mademove=1; X board[i]=whosemove; /* make the move on board */ X successor=alphabeta(board,5-whosemove,-best_score-1,-alpha-1); X /* Get value of the move */ X board[i]=0; /* Take move back */ X if (-successor.value>best_score) /* If a better score */ X { best_score= -successor.value; /* update our score */ X best_path=i; /* and move */ X if (best_score>alpha) break; /* If we've beaten alpha */ X } /* return immediately */ X } X } X if (mademove) X { result.value=best_score; /* Finally return best score */ X result.path=best_path; /* and best move */ X } X return(result); /* If no move, return static result */ X } X X Xdraw(board) /* Draw the board */ X int board[]; X { X int i,j,row; X static char out[]=" X O"; /* Lookup table for character */ X X row=6; X#ifdef CURSES X move(row,0); X#endif X for (j=0;j<9;j+=3) X { X printw(" %d | %d | %d ",j,j+1,j+2); X for (i=0;i<3;i++) X { printw("%c ",out[board[j+i]]); X if (i<2) printw("| "); X } X if (j<4) X { X#ifdef CURSES X move(++row,0); X#else X printw("\n"); X#endif X printw("---+---+--- ---+---+---"); X } X#ifdef CURSES X move(++row,0); X#else X printw("\n"); X#endif X } X#ifdef CURSES X refresh(); X#else X printw("\n"); X#endif X } X X Xgetmove(board) /* Get a player's move */ X int board[]; X { X int Move; X X do X { X do { X#ifdef CURSES X move(9,40); X printw("Your move: "); /* Prompt for move */ X refresh(); X#else X printw("Your move: "); /* Prompt for move */ X#endif X } X while (scanf("%d",&Move)!=1); /* Input the move */ X } X while (board[Move]); X board[Move]=4; /* If legal, add to board */ X draw(board); /* Draw the board */ X } X X Xint endofgame(board) /* Determine end of the game */ X int board[]; X { X int eval; X int count; X X eval=stateval(board,1); X#ifdef CURSES X move(20,25); X#endif X if (eval==100) { printw("I have beaten you.\n"); return(1);} X if (eval==-100) { printw("Bus error (core dumped)\n"); return(1);} X count=0; X for (eval=0;eval<9;eval++) if (board[eval]!=0) count++; X if (count==9) { printw("A draw!\n"); return(1);} X#ifdef CURSES X refresh(); X#endif X return(0); X } X X Xint randommove() /* Make an initial random move */ X { X long time(); /* based on current time */ X int i; X X i=abs((int) time((long *)0)); X return(i%9); X } X X Xmain() /* The actual game */ X { X int i,board[9]; X char ch; X MOVE ourmove; X X for (i=0;i<9;i++) board[i]=0; /* Initialise the board */ X#ifdef CURSES X initscr(); X clear(); X refresh(); X#endif X printw(" NOUGHTS & CROSSES\n\n"); X printw(" Your moves are 'O'\n"); X printw(" My moves are 'X'\n\n"); X#ifdef CURSES X move(5,0); X printw("Do you wish to move first: "); X refresh(); X while (scanf("%c",&ch)!=1); X move(5,0); X printw(" ......."); /* Kludge to get rid */ X refresh(); X move(5,0); X printw(" "); /* of input letter */ X refresh(); X#else X do printw("Do you wish to move first: "); X while (scanf("%c",&ch)!=1); X#endif X if ((ch!='y')&& (ch!='Y')) X { i=randommove(); /* If we move first */ X board[i]=1; /* make it random */ X#ifdef CURSES X move(7,42); X printw("My move: %d\n",i); X refresh(); X#else X printw("My move: %d\n",i); X#endif X } X draw(board); X getmove(board); X X while (1) X { ourmove=alphabeta(board,1,99,-99); /* Get a move for us; return wins */ X /* immediately & ignore losses */ X board[ourmove.path]=1; /* and make it */ X#ifdef CURSES X move(7,42); X printw("My move: %d\n",ourmove.path); X refresh(); X#else X printw("My move: %d\n",ourmove.path); X#endif X draw(board); X if (endofgame(board)) break; /* If end of game, exit */ X getmove(board); /* Get opponent's move */ X if (endofgame(board)) break; /* If end of game, exit */ X } X#ifdef CURSES X endwin(); X#endif X } /