diff options
Diffstat (limited to 'libslang/src/curses')
-rw-r--r-- | libslang/src/curses/Makefile | 51 | ||||
-rw-r--r-- | libslang/src/curses/README | 11 | ||||
-rw-r--r-- | libslang/src/curses/battle.c | 710 | ||||
-rw-r--r-- | libslang/src/curses/blue.c | 415 | ||||
-rw-r--r-- | libslang/src/curses/bs.c | 1253 | ||||
-rw-r--r-- | libslang/src/curses/firework.c | 123 | ||||
-rw-r--r-- | libslang/src/curses/gdc.c | 212 | ||||
-rw-r--r-- | libslang/src/curses/hanoi.c | 292 | ||||
-rw-r--r-- | libslang/src/curses/knight.c | 555 | ||||
-rw-r--r-- | libslang/src/curses/rain.c | 97 | ||||
-rw-r--r-- | libslang/src/curses/tclock.c | 177 | ||||
-rw-r--r-- | libslang/src/curses/view.c | 143 | ||||
-rw-r--r-- | libslang/src/curses/worm.c | 361 |
13 files changed, 4400 insertions, 0 deletions
diff --git a/libslang/src/curses/Makefile b/libslang/src/curses/Makefile new file mode 100644 index 0000000..0ca340b --- /dev/null +++ b/libslang/src/curses/Makefile @@ -0,0 +1,51 @@ +COMPILE = $(CC) $(CFLAGS) -g -DSLANG -I.. +LFLAGS = -L../$(ARCH)objs -lslang + +CURSES_H = ../curses.h + +EXECS = rain blue hanoi firework \ + bs battle gdc tclock worm view +#knight newdemo testcurs xmas + +all: $(CURSES_H) $(EXECS) + +$(CURSES_H): + echo '#include <slcurses.h>' > $(CURSES_H) + +view: view.c + $(COMPILE) $@.c -o $@ $(LFLAGS) +bs: $(CURSES_H) bs.c + $(COMPILE) $@.c -o $@ $(LFLAGS) +gdc: $(CURSES_H) gdc.c + $(COMPILE) $@.c -o $@ $(LFLAGS) +battle: $(CURSES_H) battle.c + $(COMPILE) $@.c -o $@ $(LFLAGS) +hanoi: $(CURSES_H) hanoi.c + $(COMPILE) $@.c -o $@ $(LFLAGS) +blue: $(CURSES_H) blue.c + $(COMPILE) $@.c -o $@ $(LFLAGS) +rain: $(CURSES_H) rain.c + $(COMPILE) $@.c -o $@ $(LFLAGS) +firework: $(CURSES_H) firework.c + $(COMPILE) $@.c -o $@ $(LFLAGS) +tclock: $(CURSES_H) tclock.c + $(COMPILE) $@.c -o $@ $(LFLAGS) -lm +worm: worm.c + $(COMPILE) $@.c -o $@ $(LFLAGS) -lm +knight: knight.c + $(COMPILE) $@.c -o $@ $(LFLAGS) -lm +xmas: xmas.c + $(COMPILE) $@.c -o $@ $(LFLAGS) -lm +newdemo: newdemo.c + $(COMPILE) $@.c -o $@ $(LFLAGS) -lm +testcurs: testcurs.c + $(COMPILE) $@.c -o $@ $(LFLAGS) -lm +lrtest: lrtest.c + $(COMPILE) $@.c -o $@ $(LFLAGS) -lm +t: t.c + $(COMPILE) $@.c -o $@ $(LFLAGS) -lm +key: key.c + $(COMPILE) $@.c -o $@ $(LFLAGS) -lm + +clean: + /bin/rm $(EXECS) diff --git a/libslang/src/curses/README b/libslang/src/curses/README new file mode 100644 index 0000000..68af77e --- /dev/null +++ b/libslang/src/curses/README @@ -0,0 +1,11 @@ +The files in this directory serve to illustrate the S-Lang library curses +emulation. The emulation is far from complete; however, for many simple +programs, it is adequate. + +The C files in the directory come from the ncurses test directory. The only +modifications I have made to them involve adding code to stop gcc warnings, +e.g., + +./bs.c: In function `main': +./bs.c:1250: warning: control reaches end of non-void function + diff --git a/libslang/src/curses/battle.c b/libslang/src/curses/battle.c new file mode 100644 index 0000000..3bfbe5a --- /dev/null +++ b/libslang/src/curses/battle.c @@ -0,0 +1,710 @@ +/* + * battle.c - original author: Bruce Holloway + * mods by: Chuck A DeGaul + */ + +#include <unistd.h> +#include <stdlib.h> +#include <ctype.h> +#include <time.h> +#include <signal.h> +#ifdef SLANG +# include <slcurses.h> +#else +# include <curses.h> +#endif + +#define OTHER 1-turn + +char numbers[] = " 0 1 2 3 4 5 6 7 8 9"; + +char carrier[] = "Aircraft Carrier"; +char battle[] = "Battleship"; +char sub[] = "Submarine"; +char destroy[] = "Destroyer"; +char ptboat[] = "PT Boat"; + +char name[40]; +char dftname[] = "Stranger"; + +struct _ships { + char *name; + char symbol; + char length; + char start; /* Coordinates - 0,0=0; 10,10=100. */ + char dir; /* Direction - 0 = right; 1 = down. */ + char hits; /* How many times has this ship been hit? (-1==sunk) */ +}; + +struct _ships plyship[] = { + { carrier,'A',5,0,0,0 }, + { battle,'B',4,0,0,0 }, + { destroy,'D',3,0,0,0 }, + { sub,'S',3,0,0,0 }, + { ptboat,'P',2,0,0,0 }, +}; + +struct _ships cpuship[] = { + { carrier,'A',5,0,0,0 }, + { battle,'B',4,0,0,0 }, + { destroy,'D',3,0,0,0 }, + { sub,'S',3,0,0,0 }, + { ptboat,'P',2,0,0,0 }, +}; + +char hits[2][100], board[2][100]; /* "Hits" board, and main board. */ + +int srchstep; +int cpuhits; +int cstart, cdir; +int plywon=0, cpuwon=0; /* How many games has each won? */ +int turn; /* 0=player, 1=computer */ +int huntoffs; /* Offset on search strategy */ + +int salvo, blitz, ask, seemiss; /* options */ + +void intro(void); +void initgame(void); +int rnd(int); +void plyplace(struct _ships *); +int getdir(void); +void placeship(struct _ships *, int, int); +int checkplace(struct _ships *, int, int); +void error(char *); +void prompt(void); +char getcoord(void); +void cpuplace(struct _ships *); +int awinna(void); +int plyturn(void); +int hitship(int); +int cputurn(void); +int playagain(void); +void uninitgame(); +int sgetc(char *); +int do_options(int, char *[]); +int scount(int); + +int +main(int argc, char **argv) +{ + do_options(argc, argv); + + intro(); + do { + initgame(); + while(awinna() == -1) { + if (!blitz) { + if (!salvo) { + if (turn) + cputurn(); + else plyturn(); + } else { + register int i; + + i = scount(turn); + while (i--) { + if (turn) + if (cputurn()) + if (awinna() != -1) + i = 0; + else + if(plyturn()) + if (awinna() != -1) + i = 0; + } + } + } else { + while((turn) ? cputurn() : plyturn()); + } + turn = OTHER; + } + } while(playagain()); + uninitgame(); + exit(0); +} + +#define PR addstr + +void +intro() +{ +char *tmpname; + + srand(time(0L)); /* Kick the random number generator */ + + signal(SIGINT,uninitgame); + if(signal(SIGQUIT,SIG_IGN) != SIG_IGN) signal(SIGQUIT,uninitgame); +#if 1 + /* for some bizzare reason, getlogin or cuserid cause havoc with the terminal */ + if ((tmpname = getlogin()) != NULL) { + strcpy(name, tmpname); + } else +#endif + strcpy(name,dftname); + name[0] = toupper(name[0]); + + initscr(); + savetty(); + nonl(); + cbreak(); + noecho(); + clear(); + mvaddstr(4,29,"Welcome to Battleship!"); + move(8,0); +PR(" \\\n"); +PR(" \\ \\ \\\n"); +PR(" \\ \\ \\ \\ \\_____________\n"); +PR(" \\ \\ \\_____________ \\ \\/ |\n"); +PR(" \\ \\/ \\ \\/ |\n"); +PR(" \\/ \\_____/ |__\n"); +PR(" ________________/ |\n"); +PR(" \\ S.S. Penguin |\n"); +PR(" \\ /\n"); +PR(" \\___________________________________________________/\n"); + mvaddstr(20,27,"Hit any key to continue..."); refresh(); + getch(); +} + +void +initgame() +{ +int i; + + clear(); + mvaddstr(0,35,"BATTLESHIP"); + mvaddstr(4,12,"Main Board"); + mvaddstr(6,0,numbers); + move(7,0); + for(i=0; i<10; ++i){ + printw("%c . . . . . . . . . . %c\n",i+'A',i+'A'); + } + mvaddstr(17,0,numbers); + mvaddstr(4,55,"Hit/Miss Board"); + mvaddstr(6,45,numbers); + for(i=0; i<10; ++i){ + mvprintw(7+i,45,"%c . . . . . . . . . . %c",i+'A',i+'A'); + } + mvaddstr(17,45,numbers); + for(turn=0; turn<2; ++turn) + for(i=0; i<100; ++i){ + hits[turn][i] = board[turn][i] = 0; + } + for(turn=0; turn<2; ++turn){ + for(i=0; i<5; ++i) + if (!turn) + plyplace(&plyship[i]); + else + cpuplace(&cpuship[i]); + } + turn = rnd(2); + cstart = cdir = -1; + cpuhits = 0; + srchstep = 3; + huntoffs = rnd(srchstep); +} + +int +rnd(int n) +{ + return(((rand() & 0x7FFF) % n)); +} + +void +plyplace(ss) +struct _ships *ss; +{ +int c, d; + + do { + prompt(); + printw("Place your %s (ex.%c%d) ? ",ss->name,rnd(10)+'A',rnd(10)); + c = getcoord(); + d = getdir(); + } while(!checkplace(ss,c,d)); + placeship(ss,c,d); +} + +int +getdir() +{ + + prompt(); + addstr("What direction (0=right, 1=down) ? "); + return(sgetc("01")-'0'); +} + +void +placeship(ss,c,d) +struct _ships *ss; +int c, d; +{ +int x, y, l, i; + + for(l=0; l<ss->length; ++l){ + i = c + l * ((d) ? 10 : 1); + board[turn][i] = ss->symbol; + x = (i % 10) * 3 + 3; + y = (i / 10) + 7; + if(!turn) mvaddch(y,x,ss->symbol); + } + ss->start = c; + ss->dir = d; + ss->hits = 0; +} + +int +checkplace(ss,c,d) +struct _ships *ss; +int c, d; +{ +int x, y, l; + + x = c%10; y = c/10; + if(((x+ss->length) > 10 && !d) || ((y+ss->length) > 10 && d==1)){ + if(!turn) + switch(rnd(3)){ + case 0: + error("Ship is hanging from the edge of the world"); + break; + case 1: + error("Try fitting it on the board"); + break; + case 2: + error("Figure I won't find it if you put it there?"); + break; + } + return(0); + } + for(l=0; l<ss->length; ++l){ + x = c + l * ((d) ? 10 : 1); + if(board[turn][x]){ + if(!turn) + switch(rnd(3)){ + case 0: + error("There's already a ship there"); + break; + case 1: + error("Collision alert! Aaaaaagh!"); + break; + case 2: + error("Er, Admiral, what about the other ship?"); + break; + } + return(0); + } + } + return(1); +} + +void +error(s) +char *s; +{ + prompt(); + beep(); + printw("%s -- hit any key to continue --",s); + refresh(); + getch(); +} + +void +prompt(){ + move(22,0); + clrtoeol(); +} + +char +getcoord() +{ +int ch, x, y; + +redo: + y = sgetc("ABCDEFGHIJ"); + do { + ch = getch(); + if (ch == 0x7F || ch == 8) { + addstr("\b \b"); + refresh(); + goto redo; + } + } while(ch < '0' || ch > '9'); + addch(x = ch); + refresh(); + return((y-'A')*10+x-'0'); +} + +void +cpuplace(ss) +struct _ships *ss; +{ +int c, d; + + do{ + c = rnd(100); + d = rnd(2); + } while(!checkplace(ss,c,d)); + placeship(ss,c,d); +} + +int +awinna() +{ +int i, j; +struct _ships *ss; + + for (i = 0; i < 2; ++i) { + ss = (i) ? cpuship : plyship; + for(j=0; j<5; ++j, ++ss) + if(ss->length != ss->hits) + break; + if(j == 5) return(OTHER); + } + return(-1); +} + +int +plyturn() +{ +int c, res; +char *m; + + prompt(); + addstr("Where do you want to shoot? "); + c = getcoord(); + if(!(res = hits[turn][c])){ + hits[turn][c] = res = (board[OTHER][c]) ? 'H' : 'M'; + mvaddch(7+c/10,48+3*(c%10),(res=='H') ? 'H' : 'o'); + if(0 != (c = hitship(c))){ + prompt(); + switch(rnd(3)){ + case 0: + m = "You sank my %s!"; + break; + case 1: + m = "I have this sinking feeling about my %s...."; + break; + case 2: + m = "Have some mercy for my %s!"; + break; + } + move(23,0); + clrtoeol(); + beep(); + printw(m,cpuship[c-1].name); refresh(); + return(awinna() == -1); + } + } + prompt(); + move(23,0); clrtoeol(); + printw("You %s.",(res=='M')?"missed":"scored a hit"); refresh(); + return(res == 'H'); +} + +int +hitship(c) +int c; +{ +struct _ships *ss; +int sym, i, j; + + ss = (turn) ? plyship : cpuship; + if (!(sym = board[OTHER][c])) return(0); + for (i = 0; i < 5; ++i, ++ss) + if (ss->symbol == sym) { + j = ss->hits; + ++j; + ss->hits = j; + if (j == ss->length) + return(i+1); + return(0); + } + return 0; +} + +int +cputurn() +{ +int c, res, x, y, i, d; + +redo: + if (cstart == -1){ + if (cpuhits){ + for(i=0, c=rnd(100); i<100; ++i, c = (c+1) % 100) + if(hits[turn][c] == 'H') + break; + if(i != 100){ + cstart = c; + cdir = -1; + goto fndir; + } + } + do { + i = 0; + do{ + while(hits[turn][c=rnd(100)]); + x = c % 10; y = c / 10; + if(++i == 1000) break; + } while(((x+huntoffs) % srchstep) != (y % srchstep)); + if(i == 1000) --srchstep; + } while(i == 1000); + } + else if(cdir == -1){ +fndir: for(i=0, d=rnd(4); i++ < 4; d = (d+1) % 4){ + x = cstart%10; y = cstart/10; + switch(d){ + case 0: ++x; break; + case 1: ++y; break; + case 2: --x; break; + case 3: --y; break; + } + if(x<0 || x>9 || y<0 || y>9) continue; + if(hits[turn][c=y*10+x]) continue; + cdir = -2; + break; + } + if(i == 4){ + cstart = -1; + goto redo; + } + } + else{ + x = cstart%10; y = cstart/10; + switch(cdir){ + case 0: ++x; break; + case 1: ++y; break; + case 2: --x; break; + case 3: --y; break; + } + if(x<0 || x>9 || y<0 || y>9 || hits[turn][y*10+x]){ + cdir = (cdir+2) % 4; + for(;;){ + switch(cdir){ + case 0: ++x; break; + case 1: ++y; break; + case 2: --x; break; + case 3: --y; break; + } + if(x<0 || x>9 || y<0 || y>9){ cstart = -1; + goto redo; + } + if(!hits[turn][y*10+x]) break; + } + } + c = y*10 + x; + } + + if (!ask) { + res = (board[OTHER][c]) ? 'H' : 'M'; + move(21,0); clrtoeol(); + printw("I shoot at %c%d. I %s!",c/10+'A',c%10,(res=='H')?"hit":"miss"); + } else { + for(;;){ + prompt(); + printw("I shoot at %c%d. Do I (H)it or (M)iss? ",c/10+'A',c%10); + res = sgetc("HM"); + if((res=='H' && !board[OTHER][c]) || (res=='M' && board[OTHER][c])){ + error("You lie!"); + continue; + } + break; + } + addch(res); + } + hits[turn][c] = res; + if(res == 'H') { + ++cpuhits; + if(cstart == -1) cdir = -1; + cstart = c; + if(cdir == -2) cdir = d; + mvaddch(7+(c/10),3+3*(c%10),'*'); + if (blitz && !ask) { + refresh(); + sleep(1); + } + } + else { + if (seemiss) { + mvaddch(7+(c/10),3+3*(c%10),' '); + } else { + if(cdir == -2) cdir = -1; + } + } + if(0 != (c=hitship(c))){ + cstart = -1; + cpuhits -= plyship[c-1].length; + x = plyship[c-1].start; + d = plyship[c-1].dir; + y = plyship[c-1].length; + for(i=0; i<y; ++i){ + hits[turn][x] = '*'; + x += (d) ? 10 : 1; + } + } + if (salvo && !ask) { + refresh(); + sleep(1); + } + if(awinna() != -1) return(0); + return(res == 'H'); +} + +int +playagain() +{ +int i, x, y, dx, dy, j; + + for(i=0; i<5; ++i){ + x = cpuship[i].start; y = x/10+7; x = (x % 10) * 3 + 48; + dx = (cpuship[i].dir) ? 0 : 3; + dy = (cpuship[i].dir) ? 1 : 0; + for(j=0; j < cpuship[i].length; ++j){ + mvaddch(y,x,cpuship[i].symbol); + x += dx; y += dy; + } + } + + if(awinna()) ++cpuwon; else ++plywon; + i = 18 + strlen(name); + if(plywon >= 10) ++i; + if(cpuwon >= 10) ++i; + mvprintw(2,(80-i)/2,"%s: %d Computer: %d",name,plywon,cpuwon); + + prompt(); + printw((awinna()) ? "Want to be humiliated again, %s? " + : "Going to give me a chance for revenge, %s? ",name); + return(sgetc("YN") == 'Y'); +} + +void +uninitgame(int sig) +{ + refresh(); + endwin(); + exit(0); +} + +int +sgetc(s) +char *s; +{ +char *s1; +int ch; + + refresh(); + for (;;) { + ch = toupper(getch()); + for (s1 = s; *s1 && ch != *s1; ++s1); + if (*s1) { + addch(ch); + refresh(); + return(ch); + } + } +} + +/* + * I should use getopts() from libc.a, but I'm leary that other UNIX + * systems might not have it, although I'd love to use it. + */ + +int +do_options(c,op) +int c; +char *op[]; +{ +register int i; + + if (c > 1) { + for (i=1; i<c; i++) { + switch(op[i][0]) { + default: + case '?': + fprintf(stderr, "Usage: battle [ -s | -b ] [ -a ] [ -m ]\n"); + fprintf(stderr, "\tWhere the options are:\n"); + fprintf(stderr, "\t-s : play a salvo game (mutex with -b)\n"); + fprintf(stderr, "\t-b : play a blitz game (mutex with -s)\n"); + fprintf(stderr, "\t-a : computer asks you for hit/miss\n"); + fprintf(stderr, "\t-m : computer misses are displayed\n"); + exit(1); + break; + case '-': + switch(op[i][1]) { + case 'b': + blitz = 1; + if (salvo == 1) { + fprintf(stderr, + "Bad Arg: -b and -s are mutually exclusive\n"); + exit(1); + } + break; + case 's': + salvo = 1; + if (blitz == 1) { + fprintf(stderr, + "Bad Arg: -s and -b are mutually exclusive\n"); + exit(1); + } + break; + case 'a': + ask = 1; + break; + case 'm': + seemiss = 1; + break; + default: + fprintf(stderr, + "Bad Arg: type \"%s ?\" for usage message\n", op[0]); + exit(1); + } + } + } + fprintf(stdout, "Playing optional game ("); + if (salvo) + fprintf(stdout, "salvo, noblitz, "); + else if (blitz) + fprintf(stdout, "blitz, nosalvo, "); + else + fprintf(stdout, "noblitz, nosalvo, "); + + if (ask) + fprintf(stdout, "ask, "); + else + fprintf(stdout, "noask, "); + + if (seemiss) + fprintf(stdout, "seemiss)\n"); + else + fprintf(stdout, "noseemiss)\n"); + } + else + fprintf(stdout, + "Playing standard game (no blitz, no slavo, no ask, no seemiss)\n"); + sleep(2); + return(0); +} + +int +scount(who) +int who; +{ +int i, shots; +struct _ships *sp; + + if (who) { + /* count cpu shots */ + sp = cpuship; + } else { + /* count player shots */ + sp = plyship; + } + for (i=0, shots = 0; i<5; i++, sp++) { + /* extra test for machines with unsigned chars! */ + if (sp->hits == (char) -1 || sp->hits >= sp->length) { + continue; /* dead ship */ + } else { + shots++; + } + } + return(shots); +} + diff --git a/libslang/src/curses/blue.c b/libslang/src/curses/blue.c new file mode 100644 index 0000000..27d9815 --- /dev/null +++ b/libslang/src/curses/blue.c @@ -0,0 +1,415 @@ +/***************************************************************************** + * * + * B l u e M o o n * + * ================= * + * V2.2 * + * A patience game by T.A.Lister * + * Integral screen support by Eric S. Raymond * + * * + *****************************************************************************/ + +/* + * Compile this with the command `cc -O blue.c -lcurses -o blue'. For best + * results, use the portable freeware ncurses(3) library. On non-Intel + * machines, SVr4 curses is just as good. + */ + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <time.h> + +#if HAVE_TERMIOS_H +#include <sys/termios.h> +#endif + +#include <curses.h> +#ifndef SLANG +#include <term.h> +#endif + +#define NOCARD (-1) + +#define ACE 0 +#define KING 12 +#define SUIT_LENGTH 13 + +#define HEARTS 0 +#define SPADES 1 +#define DIAMONDS 2 +#define CLUBS 3 +#define NSUITS 4 + +#define GRID_WIDTH 14 /* 13+1 */ +#define GRID_LENGTH 56 /* 4*(13+1) */ +#define PACK_SIZE 52 + +#define BASEROW 1 +#define PROMPTROW 11 + +static int deck_size = PACK_SIZE; /* initial deck */ +static int deck[PACK_SIZE]; + +static int grid[GRID_LENGTH]; /* card layout grid */ +static int freeptr[4]; /* free card space pointers */ + +static int deal_number=0; + +static chtype ranks[SUIT_LENGTH][2] = +{ + {' ', 'A'}, + {' ', '2'}, + {' ', '3'}, + {' ', '4'}, + {' ', '5'}, + {' ', '6'}, + {' ', '7'}, + {' ', '8'}, + {' ', '9'}, + {'1', '0'}, + {' ', 'J'}, + {' ', 'Q'}, + {' ', 'K'} +}; + +static chtype letters[] = +{ + 'h' | COLOR_PAIR(COLOR_RED), /* hearts */ + 's' | COLOR_PAIR(COLOR_GREEN), /* spades */ + 'd' | COLOR_PAIR(COLOR_RED), /* diamonds */ + 'c' | COLOR_PAIR(COLOR_GREEN), /* clubs */ +}; + +#if defined(__i386__) +static chtype glyphs[] = +{ + '\003' | A_ALTCHARSET | COLOR_PAIR(COLOR_RED), /* hearts */ + '\006' | A_ALTCHARSET | COLOR_PAIR(COLOR_GREEN), /* spades */ + '\004' | A_ALTCHARSET | COLOR_PAIR(COLOR_RED), /* diamonds */ + '\005' | A_ALTCHARSET | COLOR_PAIR(COLOR_GREEN), /* clubs */ +}; +#endif /* __i386__ */ + +static chtype *suits = letters; /* this may change to glyphs below */ + +static void die(int onsig) +{ + signal(onsig, SIG_IGN); + endwin(); + exit(0); +} + +static void init_vars(void) +{ + int i; + + deck_size = PACK_SIZE; + for (i=0; i < PACK_SIZE; i++) + deck[i]=i; + for (i = 0; i < 4; i++) + freeptr[i]=i * GRID_WIDTH; +} + +static void shuffle(int size) +{ + int i,j,numswaps,swapnum,temp; + + numswaps=size*10; /* an arbitrary figure */ + + for (swapnum=0;swapnum<numswaps;swapnum++) + { + i=rand() % size; + j=rand() % size; + temp=deck[i]; + deck[i]=deck[j]; + deck[j]=temp; + } +} + +static void deal_cards(void) +{ + int ptr, card=0, value, csuit, crank, suit, aces[4]; + + for (suit=HEARTS;suit<=CLUBS;suit++) + { + ptr=freeptr[suit]; + grid[ptr++]=NOCARD; /* 1st card space is blank */ + while ((ptr % GRID_WIDTH) != 0) + { + value=deck[card++]; + crank=value % SUIT_LENGTH; + csuit=value / SUIT_LENGTH; + if (crank==ACE) + aces[csuit]=ptr; + grid[ptr++]=value; + } + } + + if (deal_number==1) /* shift the aces down to the 1st column */ + for (suit=HEARTS;suit<=CLUBS;suit++) + { + grid[suit * GRID_WIDTH] = suit * SUIT_LENGTH; + grid[aces[suit]]=NOCARD; + freeptr[suit]=aces[suit]; + } +} + +static void printcard(int value) +{ + (void) addch(' '); + if (value == NOCARD) + (void) addstr(" "); + else + { + addch(ranks[value % SUIT_LENGTH][0] | COLOR_PAIR(COLOR_BLUE)); + addch(ranks[value % SUIT_LENGTH][1] | COLOR_PAIR(COLOR_BLUE)); + addch(suits[value / SUIT_LENGTH]); + } + (void) addch(' '); +} + +static void display_cards(int deal) +{ + int row, card; + + clear(); + (void)printw( + "Blue Moon 2.1 - by Tim Lister & Eric Raymond - Deal %d.\n", + deal); + for(row=HEARTS;row<=CLUBS;row++) + { + move(BASEROW + row + row + 2, 1); + for(card=0;card<GRID_WIDTH;card++) + printcard(grid[row * GRID_WIDTH + card]); + } + + move(PROMPTROW + 2, 0); refresh(); +#define P(x) (void)printw("%s\n", x) +P(" This 52-card solitaire starts with the entire deck shuffled and dealt"); +P("out in four rows. The aces are then moved to the left end of the layout,"); +P("making 4 initial free spaces. You may move to a space only the card that"); +P("matches the left neighbor in suit, and is one greater in rank. Kings are"); +P("high, so no cards may be placed to their right (they create dead spaces)."); +P(" When no moves can be made, cards still out of sequence are reshuffled"); +P("and dealt face up after the ends of the partial sequences, leaving a card"); +P("space after each sequence, so that each row looks like a partial sequence"); +P("followed by a space, followed by enough cards to make a row of 14. "); +P(" A moment's reflection will show that this game cannot take more than 13"); +P("deals. A good score is 1-3 deals, 4-7 is average, 8 or more is poor. "); +#undef P + refresh(); +} + +static int find(int card) +{ + int i; + + if ((card<0) || (card>=PACK_SIZE)) + return(NOCARD); + for(i = 0; i < GRID_LENGTH; i++) + if (grid[i] == card) + return i; + return(NOCARD); +} + +static void movecard(int src, int dst) +{ + grid[dst]=grid[src]; + grid[src]=NOCARD; + + move( BASEROW + (dst / GRID_WIDTH)*2+2, (dst % GRID_WIDTH)*5 + 1); + printcard(grid[dst]); + + move( BASEROW + (src / GRID_WIDTH)*2+2, (src % GRID_WIDTH)*5 + 1); + printcard(grid[src]); + + refresh(); +} + +static void play_game(void) +{ + int dead=0, i, j; + char c; + int select[4], card; + + while (dead<4) + { + dead=0; + for (i=0;i<4;i++) + { + card=grid[freeptr[i]-1]; + + if ( ((card % SUIT_LENGTH)==KING) + || + (card==NOCARD) ) + select[i]=NOCARD; + else + select[i]=find(card+1); + + if (select[i]==NOCARD) + dead++; + }; + + if (dead < 4) + { + char live[NSUITS+1], *lp = live; + + for (i=0;i<4;i++) + { + if (select[i] != NOCARD) + { + move(BASEROW + (select[i] / GRID_WIDTH)*2+3, + (select[i] % GRID_WIDTH)*5); + (void)printw(" %c ", *lp++ = 'a' + i); + } + }; + *lp = '\0'; + + if (strlen(live) == 1) + { + move(PROMPTROW,0); + (void)printw( + "Making forced moves... "); + refresh(); + (void) sleep(1); + c = live[0]; + } + else + { + char buf[BUFSIZ]; + + (void)sprintf(buf, + "Type [%s] to move, r to redraw, q or INTR to quit: ", + live); + + do { + move(PROMPTROW,0); + (void) addstr(buf); + move(PROMPTROW, (int)strlen(buf)); + clrtoeol(); + (void) addch(' '); + } while + (((c = getch())<'a' || c>'d') && (c!='r') && (c!='q')); + } + + for (j = 0; j < 4; j++) + if (select[j]!=NOCARD) + { + move(BASEROW + (select[j] / GRID_WIDTH)*2+3, + (select[j] % GRID_WIDTH)*5); + (void)printw(" "); + } + + if (c == 'r') + display_cards(deal_number); + else if (c == 'q') + die(SIGINT); + else + { + i = c-'a'; + if (select[i] == NOCARD) + beep(); + else + { + movecard(select[i], freeptr[i]); + freeptr[i]=select[i]; + } + } + } + } + + move(PROMPTROW, 0); + standout(); + (void)printw("Finished deal %d - type any character to continue...", deal_number); + standend(); + (void) getch(); +} + +static int collect_discards(void) +{ + int row, col, cardno=0, finish, gridno; + + for (row=HEARTS;row<=CLUBS;row++) + { + finish=0; + for (col=1;col<GRID_WIDTH;col++) + { + gridno=row * GRID_WIDTH + col; + + if ((grid[gridno]!=(grid[gridno-1]+1))&&(finish==0)) + { + finish=1; + freeptr[row]=gridno; + }; + + if ((finish!=0)&&(grid[gridno]!=NOCARD)) + deck[cardno++]=grid[gridno]; + } + } + return cardno; +} + +static void game_finished(int deal) +{ + clear(); + (void)printw("You finished the game in %d deals. This is ",deal); + standout(); + if (deal<2) + (void)addstr("excellent"); + else if (deal<4) + (void)addstr("good"); + else if (deal<8) + (void)addstr("average"); + else + (void)addstr("poor"); + standend(); + (void) addstr(". "); + refresh(); +} + +int main(int argc, char *argv[]) +{ + (void) signal(SIGINT, die); + initscr(); + + /* + * We use COLOR_GREEN because COLOR_BLACK is wired to the wrong thing. + */ + start_color(); + init_pair(COLOR_RED, COLOR_RED, COLOR_WHITE); + init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_WHITE); + init_pair(COLOR_GREEN, COLOR_BLACK, COLOR_WHITE); + +#if defined(__i386__) && defined(A_ALTCHARSET) + if (tigetstr("smpch")) + suits = glyphs; +#endif /* __i386__ && A_ALTCHARSET */ + + cbreak(); + + if (argc == 2) + srand((unsigned)atoi(argv[1])); + else + srand((unsigned)time((time_t *)0)); + + init_vars(); + + do{ + deal_number++; + shuffle(deck_size); + deal_cards(); + display_cards(deal_number); + play_game(); + } + while + ((deck_size=collect_discards()) != 0); + + game_finished(deal_number); + + die(SIGINT); + /*NOTREACHED*/ + return 1; +} + +/* blue.c ends here */ diff --git a/libslang/src/curses/bs.c b/libslang/src/curses/bs.c new file mode 100644 index 0000000..cdb926e --- /dev/null +++ b/libslang/src/curses/bs.c @@ -0,0 +1,1253 @@ +/* + * bs.c - original author: Bruce Holloway + * salvo option by: Chuck A DeGaul + * with improved user interface, autoconfiguration and code cleanup + * by Eric S. Raymond <esr@snark.thyrsus.com> + * v1.2 with color support and minor portability fixes, November 1990 + * v2.0 featuring strict ANSI/POSIX conformance, November 1993. + * v2.1 with ncurses mouse support, September 1995 + */ +/* #define _POSIX_SOURCE -- incompatible with solaris termios.h */ + +#include <signal.h> +#include <ctype.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <assert.h> +#include <time.h> + +#if HAVE_TERMIOS_H +#include <sys/termios.h> /* required before solaris curses.h */ +#endif + +#include <curses.h> + +#ifndef SIGIOT +#define SIGIOT SIGABRT +#endif + +#ifndef A_UNDERLINE /* BSD curses */ +#define beep() write(1,"\007",1); +#define cbreak crmode +#define saveterm savetty +#define resetterm resetty +#define nocbreak nocrmode +#define strchr index +#endif /* !A_UNDERLINE */ + +static int getcoord(int); + +/* + * Constants for tuning the random-fire algorithm. It prefers moves that + * diagonal-stripe the board with a stripe separation of srchstep. If + * no such preferred moves are found, srchstep is decremented. + */ +#define BEGINSTEP 3 /* initial value of srchstep */ + +/* miscellaneous constants */ +#define SHIPTYPES 5 +#define OTHER (1-turn) +#define PLAYER 0 +#define COMPUTER 1 +#define MARK_HIT 'H' +#define MARK_MISS 'o' +#define CTRLC '\003' /* used as terminate command */ +#define FF '\014' /* used as redraw command */ + +/* coordinate handling */ +#define BWIDTH 10 +#define BDEPTH 10 + +/* display symbols */ +#define SHOWHIT '*' +#define SHOWSPLASH ' ' +#define IS_SHIP(c) isupper(c) + +/* how to position us on player board */ +#define PYBASE 3 +#define PXBASE 3 +#define PY(y) (PYBASE + (y)) +#define PX(x) (PXBASE + (x)*3) +#define pgoto(y, x) (void)move(PY(y), PX(x)) + +/* how to position us on cpu board */ +#define CYBASE 3 +#define CXBASE 48 +#define CY(y) (CYBASE + (y)) +#define CX(x) (CXBASE + (x)*3) +#define CYINV(y) ((y) - CYBASE) +#define CXINV(x) (((x) - CXBASE) / 3) +#define cgoto(y, x) (void)move(CY(y), CX(x)) + +#define ONBOARD(x, y) (x >= 0 && x < BWIDTH && y >= 0 && y < BDEPTH) + +/* other board locations */ +#define COLWIDTH 80 +#define PROMPTLINE 21 /* prompt line */ +#define SYBASE CYBASE + BDEPTH + 3 /* move key diagram */ +#define SXBASE 63 +#define MYBASE SYBASE - 1 /* diagram caption */ +#define MXBASE 64 +#define HYBASE SYBASE - 1 /* help area */ +#define HXBASE 0 + +/* this will need to be changed if BWIDTH changes */ +static char numbers[] = " 0 1 2 3 4 5 6 7 8 9"; + +static char carrier[] = "Aircraft Carrier"; +static char battle[] = "Battleship"; +static char sub[] = "Submarine"; +static char destroy[] = "Destroyer"; +static char ptboat[] = "PT Boat"; + +static char name[40]; +static char dftname[] = "stranger"; + +/* direction constants */ +#define E 0 +#define SE 1 +#define S 2 +#define SW 3 +#define W 4 +#define NW 5 +#define N 6 +#define NE 7 +static int xincr[8] = {1, 1, 0, -1, -1, -1, 0, 1}; +static int yincr[8] = {0, 1, 1, 1, 0, -1, -1, -1}; + +/* current ship position and direction */ +static int curx = (BWIDTH / 2); +static int cury = (BDEPTH / 2); + +typedef struct +{ + char *name; /* name of the ship type */ + unsigned hits; /* how many times has this ship been hit? */ + char symbol; /* symbol for game purposes */ + char length; /* length of ship */ + char x, y; /* coordinates of ship start point */ + unsigned char dir; /* direction of `bow' */ + bool placed; /* has it been placed on the board? */ +} +ship_t; + +static bool checkplace(int b, ship_t *ss, int vis); + +ship_t plyship[SHIPTYPES] = +{ + { carrier, 0, 'A', 5}, + { battle, 0, 'B', 4}, + { destroy, 0, 'D', 3}, + { sub, 0, 'S', 3}, + { ptboat, 0, 'P', 2}, +}; + +ship_t cpuship[SHIPTYPES] = +{ + { carrier, 0, 'A', 5}, + { battle, 0, 'B', 4}, + { destroy, 0, 'D', 3}, + { sub, 0, 'S', 3}, + { ptboat, 0, 'P', 2}, +}; + +/* "Hits" board, and main board. */ +static char hits[2][BWIDTH][BDEPTH], board[2][BWIDTH][BDEPTH]; + +static int turn; /* 0=player, 1=computer */ +static int plywon=0, cpuwon=0; /* How many games has each won? */ + +static int salvo, blitz, closepack; + +#define PR (void)addstr + +static void uninitgame(int sig) +/* end the game, either normally or due to signal */ +{ + clear(); + (void)refresh(); + (void)resetterm(); + (void)echo(); + (void)endwin(); + exit(sig); +} + +static void announceopts(void) +/* announce which game options are enabled */ +{ + if (salvo || blitz || closepack) + { + (void) printw("Playing optional game ("); + if (salvo) + (void) printw("salvo, "); + else + (void) printw("nosalvo, "); + if (blitz) + (void) printw("blitz "); + else + (void) printw("noblitz, "); + if (closepack) + (void) printw("closepack)"); + else + (void) printw("noclosepack)"); + } + else + (void) printw( + "Playing standard game (noblitz, nosalvo, noclosepack)"); +} + +static void intro(void) +{ + extern char *getlogin(void); + char *tmpname; + + srand((unsigned)(time(0L)+getpid())); /* Kick the random number generator */ + + (void) signal(SIGINT,uninitgame); + (void) signal(SIGINT,uninitgame); + (void) signal(SIGIOT,uninitgame); /* for assert(3) */ + if(signal(SIGQUIT,SIG_IGN) != SIG_IGN) + (void)signal(SIGQUIT,uninitgame); + + if((tmpname = getlogin()) != 0) + { + (void)strcpy(name,tmpname); + name[0] = toupper(name[0]); + } + else + (void)strcpy(name,dftname); + + (void)initscr(); +#ifdef KEY_MIN + keypad(stdscr, TRUE); +#endif /* KEY_MIN */ + (void)saveterm(); + (void)nonl(); + (void)cbreak(); + (void)noecho(); + +#ifdef PENGUIN + (void)clear(); + (void)mvaddstr(4,29,"Welcome to Battleship!"); + (void)move(8,0); + PR(" \\\n"); + PR(" \\ \\ \\\n"); + PR(" \\ \\ \\ \\ \\_____________\n"); + PR(" \\ \\ \\_____________ \\ \\/ |\n"); + PR(" \\ \\/ \\ \\/ |\n"); + PR(" \\/ \\_____/ |__\n"); + PR(" ________________/ |\n"); + PR(" \\ S.S. Penguin |\n"); + PR(" \\ /\n"); + PR(" \\___________________________________________________/\n"); + + (void) mvaddstr(22,27,"Hit any key to continue..."); (void)refresh(); + (void) getch(); +#endif /* PENGUIN */ + +#ifdef A_COLOR + start_color(); + + init_pair(COLOR_BLACK, COLOR_BLACK, COLOR_BLACK); + init_pair(COLOR_GREEN, COLOR_GREEN, COLOR_BLACK); + init_pair(COLOR_RED, COLOR_RED, COLOR_BLACK); + init_pair(COLOR_CYAN, COLOR_CYAN, COLOR_BLACK); + init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK); + init_pair(COLOR_MAGENTA, COLOR_MAGENTA, COLOR_BLACK); + init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_BLACK); + init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK); +#endif /* A_COLOR */ + +#ifdef NCURSES_MOUSE_VERSION + (void) mousemask(BUTTON1_CLICKED, (mmask_t *)NULL); +#endif /* NCURSES_MOUSE_VERSION*/ +} + +/* VARARGS1 */ +static void prompt(int n, char *f, char *s) +/* print a message at the prompt line */ +{ + (void) move(PROMPTLINE + n, 0); + (void) clrtoeol(); + (void) printw(f, s); + (void) refresh(); +} + +static void error(char *s) +{ + (void) move(PROMPTLINE + 2, 0); + (void) clrtoeol(); + if (s) + { + (void) addstr(s); + (void) beep(); + } +} + +static void placeship(int b, ship_t *ss, int vis) +{ + int l; + + for(l = 0; l < ss->length; ++l) + { + int newx = ss->x + l * xincr[ss->dir]; + int newy = ss->y + l * yincr[ss->dir]; + + board[b][newx][newy] = ss->symbol; + if (vis) + { + pgoto(newy, newx); + (void) addch((chtype)ss->symbol); + } + } + ss->hits = 0; +} + +static int rnd(int n) +{ + return(((rand() & 0x7FFF) % n)); +} + +static void randomplace(int b, ship_t *ss) +/* generate a valid random ship placement into px,py */ +{ + register int bwidth = BWIDTH - ss->length; + register int bdepth = BDEPTH - ss->length; + + do { + ss->y = rnd(bdepth); + ss->x = rnd(bwidth); + ss->dir = rnd(2) ? E : S; + } while + (!checkplace(b, ss, FALSE)); +} + +static void initgame(void) +{ + int i, j, unplaced; + ship_t *ss; + + (void) clear(); + (void) mvaddstr(0,35,"BATTLESHIPS"); + (void) move(PROMPTLINE + 2, 0); + announceopts(); + + memset(board, 0, sizeof(char) * BWIDTH * BDEPTH * 2); + memset(hits, 0, sizeof(char) * BWIDTH * BDEPTH * 2); + for (i = 0; i < SHIPTYPES; i++) + { + ss = cpuship + i; + ss->x = ss->y = ss->dir = ss->hits = ss->placed = 0; + ss = plyship + i; + ss->x = ss->y = ss->dir = ss->hits = ss->placed = 0; + } + + /* draw empty boards */ + (void) mvaddstr(PYBASE - 2, PXBASE + 5, "Main Board"); + (void) mvaddstr(PYBASE - 1, PXBASE - 3,numbers); + for(i=0; i < BDEPTH; ++i) + { + (void) mvaddch(PYBASE + i, PXBASE - 3, (chtype)(i + 'A')); +#ifdef A_COLOR + if (has_colors()) + attron(COLOR_PAIR(COLOR_BLUE)); +#endif /* A_COLOR */ + (void) addch(' '); + for (j = 0; j < BWIDTH; j++) + (void) addstr(" . "); +#ifdef A_COLOR + attrset(0); +#endif /* A_COLOR */ + (void) addch(' '); + (void) addch((chtype)(i + 'A')); + } + (void) mvaddstr(PYBASE + BDEPTH, PXBASE - 3,numbers); + (void) mvaddstr(CYBASE - 2, CXBASE + 7,"Hit/Miss Board"); + (void) mvaddstr(CYBASE - 1, CXBASE - 3, numbers); + for(i=0; i < BDEPTH; ++i) + { + (void) mvaddch(CYBASE + i, CXBASE - 3, (chtype)(i + 'A')); +#ifdef A_COLOR + if (has_colors()) + attron(COLOR_PAIR(COLOR_BLUE)); +#endif /* A_COLOR */ + (void) addch(' '); + for (j = 0; j < BWIDTH; j++) + (void) addstr(" . "); +#ifdef A_COLOR + attrset(0); +#endif /* A_COLOR */ + (void) addch(' '); + (void) addch((chtype)(i + 'A')); + } + + (void) mvaddstr(CYBASE + BDEPTH,CXBASE - 3,numbers); + + (void) mvprintw(HYBASE, HXBASE, + "To position your ships: move the cursor to a spot, then"); + (void) mvprintw(HYBASE+1,HXBASE, + "type the first letter of a ship type to select it, then"); + (void) mvprintw(HYBASE+2,HXBASE, + "type a direction ([hjkl] or [4862]), indicating how the"); + (void) mvprintw(HYBASE+3,HXBASE, + "ship should be pointed. You may also type a ship letter"); + (void) mvprintw(HYBASE+4,HXBASE, + "followed by `r' to position it randomly, or type `R' to"); + (void) mvprintw(HYBASE+5,HXBASE, + "place all remaining ships randomly."); + + (void) mvaddstr(MYBASE, MXBASE, "Aiming keys:"); + (void) mvaddstr(SYBASE, SXBASE, "y k u 7 8 9"); + (void) mvaddstr(SYBASE+1, SXBASE, " \\|/ \\|/ "); + (void) mvaddstr(SYBASE+2, SXBASE, "h-+-l 4-+-6"); + (void) mvaddstr(SYBASE+3, SXBASE, " /|\\ /|\\ "); + (void) mvaddstr(SYBASE+4, SXBASE, "b j n 1 2 3"); + + /* have the computer place ships */ + for(ss = cpuship; ss < cpuship + SHIPTYPES; ss++) + { + randomplace(COMPUTER, ss); + placeship(COMPUTER, ss, FALSE); + } + + ss = (ship_t *)NULL; + do { + char c, docked[SHIPTYPES + 2], *cp = docked; + + /* figure which ships still wait to be placed */ + *cp++ = 'R'; + for (i = 0; i < SHIPTYPES; i++) + if (!plyship[i].placed) + *cp++ = plyship[i].symbol; + *cp = '\0'; + + /* get a command letter */ + prompt(1, "Type one of [%s] to pick a ship.", docked+1); + do { + c = getcoord(PLAYER); + } while + (!strchr(docked, c)); + + if (c == 'R') + (void) ungetch('R'); + else + { + /* map that into the corresponding symbol */ + for (ss = plyship; ss < plyship + SHIPTYPES; ss++) + if (ss->symbol == c) + break; + + prompt(1, "Type one of [hjklrR] to place your %s.", ss->name); + pgoto(cury, curx); + } + + do { + c = getch(); + } while + (!strchr("hjklrR", c) || c == FF); + + if (c == FF) + { + (void)clearok(stdscr, TRUE); + (void)refresh(); + } + else if (c == 'r') + { + prompt(1, "Random-placing your %s", ss->name); + randomplace(PLAYER, ss); + placeship(PLAYER, ss, TRUE); + error((char *)NULL); + ss->placed = TRUE; + } + else if (c == 'R') + { + prompt(1, "Placing the rest of your fleet at random...", ""); + for (ss = plyship; ss < plyship + SHIPTYPES; ss++) + if (!ss->placed) + { + randomplace(PLAYER, ss); + placeship(PLAYER, ss, TRUE); + ss->placed = TRUE; + } + error((char *)NULL); + } + else if (strchr("hjkl8462", c)) + { + ss->x = curx; + ss->y = cury; + + switch(c) + { + case 'k': case '8': ss->dir = N; break; + case 'j': case '2': ss->dir = S; break; + case 'h': case '4': ss->dir = W; break; + case 'l': case '6': ss->dir = E; break; + } + + if (checkplace(PLAYER, ss, TRUE)) + { + placeship(PLAYER, ss, TRUE); + error((char *)NULL); + ss->placed = TRUE; + } + } + + for (unplaced = i = 0; i < SHIPTYPES; i++) + unplaced += !plyship[i].placed; + } while + (unplaced); + + turn = rnd(2); + + (void) mvprintw(HYBASE, HXBASE, + "To fire, move the cursor to your chosen aiming point "); + (void) mvprintw(HYBASE+1, HXBASE, + "and strike any key other than a motion key. "); + (void) mvprintw(HYBASE+2, HXBASE, + " "); + (void) mvprintw(HYBASE+3, HXBASE, + " "); + (void) mvprintw(HYBASE+4, HXBASE, + " "); + (void) mvprintw(HYBASE+5, HXBASE, + " "); + + (void) prompt(0, "Press any key to start...", ""); + (void) getch(); +} + +static int getcoord(int atcpu) +{ + int ny, nx, c; + + if (atcpu) + cgoto(cury,curx); + else + pgoto(cury, curx); + (void)refresh(); + for (;;) + { + if (atcpu) + { + (void) mvprintw(CYBASE + BDEPTH+1, CXBASE+11, "(%d, %c)", curx, 'A'+cury); + cgoto(cury, curx); + } + else + { + (void) mvprintw(PYBASE + BDEPTH+1, PXBASE+11, "(%d, %c)", curx, 'A'+cury); + pgoto(cury, curx); + } + + switch(c = getch()) + { + case 'k': case '8': +#ifdef KEY_MIN + case KEY_UP: +#endif /* KEY_MIN */ + ny = cury+BDEPTH-1; nx = curx; + break; + case 'j': case '2': +#ifdef KEY_MIN + case KEY_DOWN: +#endif /* KEY_MIN */ + ny = cury+1; nx = curx; + break; + case 'h': case '4': +#ifdef KEY_MIN + case KEY_LEFT: +#endif /* KEY_MIN */ + ny = cury; nx = curx+BWIDTH-1; + break; + case 'l': case '6': +#ifdef KEY_MIN + case KEY_RIGHT: +#endif /* KEY_MIN */ + ny = cury; nx = curx+1; + break; + case 'y': case '7': +#ifdef KEY_MIN + case KEY_A1: +#endif /* KEY_MIN */ + ny = cury+BDEPTH-1; nx = curx+BWIDTH-1; + break; + case 'b': case '1': +#ifdef KEY_MIN + case KEY_C1: +#endif /* KEY_MIN */ + ny = cury+1; nx = curx+BWIDTH-1; + break; + case 'u': case '9': +#ifdef KEY_MIN + case KEY_A3: +#endif /* KEY_MIN */ + ny = cury+BDEPTH-1; nx = curx+1; + break; + case 'n': case '3': +#ifdef KEY_MIN + case KEY_C3: +#endif /* KEY_MIN */ + ny = cury+1; nx = curx+1; + break; + case FF: + nx = curx; ny = cury; + (void)clearok(stdscr, TRUE); + (void)refresh(); + break; +#ifdef NCURSES_MOUSE_VERSION + case KEY_MOUSE: + { + MEVENT myevent; + + getmouse(&myevent); + if (atcpu + && myevent.y >= CY(0) && myevent.y <= CY(BDEPTH) + && myevent.x >= CX(0) && myevent.x <= CX(BDEPTH)) + { + curx = CXINV(myevent.x); + cury = CYINV(myevent.y); + return(' '); + } + else + { + beep(); + continue; + } + } + /* no fall through */ +#endif /* NCURSES_MOUSE_VERSION */ + + default: + if (atcpu) + (void) mvaddstr(CYBASE + BDEPTH + 1, CXBASE + 11, " "); + else + (void) mvaddstr(PYBASE + BDEPTH + 1, PXBASE + 11, " "); + return(c); + } + + curx = nx % BWIDTH; + cury = ny % BDEPTH; + } +} + +static int collidecheck(int b, int y, int x) +/* is this location on the selected zboard adjacent to a ship? */ +{ + int collide; + + /* anything on the square */ + if ((collide = IS_SHIP(board[b][x][y])) != 0) + return(collide); + + /* anything on the neighbors */ + if (!closepack) + { + int i; + + for (i = 0; i < 8; i++) + { + int xend, yend; + + yend = y + yincr[i]; + xend = x + xincr[i]; + if (ONBOARD(xend, yend)) + collide += IS_SHIP(board[b][xend][yend]); + } + } + return(collide); +} + +static bool checkplace(int b, ship_t *ss, int vis) +{ + int l, xend, yend; + + /* first, check for board edges */ + xend = ss->x + ss->length * xincr[ss->dir]; + yend = ss->y + ss->length * yincr[ss->dir]; + if (!ONBOARD(xend, yend)) + { + if (vis) + switch(rnd(3)) + { + case 0: + error("Ship is hanging from the edge of the world"); + break; + case 1: + error("Try fitting it on the board"); + break; + case 2: + error("Figure I won't find it if you put it there?"); + break; + } + return(0); + } + + for(l = 0; l < ss->length; ++l) + { + if(collidecheck(b, ss->y+l*yincr[ss->dir], ss->x+l*xincr[ss->dir])) + { + if (vis) + switch(rnd(3)) + { + case 0: + error("There's already a ship there"); + break; + case 1: + error("Collision alert! Aaaaaagh!"); + break; + case 2: + error("Er, Admiral, what about the other ship?"); + break; + } + return(FALSE); + } + } + return(TRUE); +} + +static int awinna(void) +{ + int i, j; + ship_t *ss; + + for(i=0; i<2; ++i) + { + ss = (i) ? cpuship : plyship; + for(j=0; j < SHIPTYPES; ++j, ++ss) + if(ss->length > ss->hits) + break; + if (j == SHIPTYPES) + return(OTHER); + } + return(-1); +} + +static ship_t *hitship(int x, int y) +/* register a hit on the targeted ship */ +{ + ship_t *sb, *ss; + char sym; + int oldx, oldy; + + getyx(stdscr, oldy, oldx); + sb = (turn) ? plyship : cpuship; + if(!(sym = board[OTHER][x][y])) + return((ship_t *)NULL); + for(ss = sb; ss < sb + SHIPTYPES; ++ss) + if(ss->symbol == sym) + { + if (++ss->hits < ss->length) /* still afloat? */ + return((ship_t *)NULL); + else /* sunk! */ + { + int i, j; + + if (!closepack) + for (j = -1; j <= 1; j++) + { + int bx = ss->x + j * xincr[(ss->dir + 2) % 8]; + int by = ss->y + j * yincr[(ss->dir + 2) % 8]; + + for (i = -1; i <= ss->length; ++i) + { + int x1, y1; + + x1 = bx + i * xincr[ss->dir]; + y1 = by + i * yincr[ss->dir]; + if (ONBOARD(x1, y1)) + { + hits[turn][x1][y1] = MARK_MISS; + if (turn % 2 == PLAYER) + { + cgoto(y1, x1); +#ifdef A_COLOR + if (has_colors()) + attron(COLOR_PAIR(COLOR_GREEN)); +#endif /* A_COLOR */ + (void)addch(MARK_MISS); +#ifdef A_COLOR + attrset(0); +#endif /* A_COLOR */ + } + } + } + } + + for (i = 0; i < ss->length; ++i) + { + int x1 = ss->x + i * xincr[ss->dir]; + int y1 = ss->y + i * yincr[ss->dir]; + + hits[turn][x1][y1] = ss->symbol; + if (turn % 2 == PLAYER) + { + cgoto(y1, x1); + (void) addch((chtype)(ss->symbol)); + } + } + + (void) move(oldy, oldx); + return(ss); + } + } + (void) move(oldy, oldx); + return((ship_t *)NULL); +} + +static int plyturn(void) +{ + ship_t *ss; + bool hit; + char *m = NULL; + + prompt(1, "Where do you want to shoot? ", ""); + for (;;) + { + (void) getcoord(COMPUTER); + if (hits[PLAYER][curx][cury]) + { + prompt(1, "You shelled this spot already! Try again.", ""); + beep(); + } + else + break; + } + hit = IS_SHIP(board[COMPUTER][curx][cury]); + hits[PLAYER][curx][cury] = hit ? MARK_HIT : MARK_MISS; + cgoto(cury, curx); +#ifdef A_COLOR + if (has_colors()) + if (hit) + attron(COLOR_PAIR(COLOR_RED)); + else + attron(COLOR_PAIR(COLOR_GREEN)); +#endif /* A_COLOR */ + (void) addch((chtype)hits[PLAYER][curx][cury]); +#ifdef A_COLOR + attrset(0); +#endif /* A_COLOR */ + + prompt(1, "You %s.", hit ? "scored a hit" : "missed"); + if(hit && (ss = hitship(curx, cury))) + { + switch(rnd(5)) + { + case 0: + m = " You sank my %s!"; + break; + case 1: + m = " I have this sinking feeling about my %s...."; + break; + case 2: + m = " My %s has gone to Davy Jones's locker!"; + break; + case 3: + m = " Glub, glub -- my %s is headed for the bottom!"; + break; + case 4: + m = " You'll pick up survivors from my my %s, I hope...!"; + break; + } + (void)printw(m, ss->name); + (void)beep(); + return(awinna() == -1); + } + return(hit); +} + +static int sgetc(char *s) +{ + char *s1; + int ch; + + (void)refresh(); + for(;;) + { + ch = getch(); + if (islower(ch)) + ch = toupper(ch); + if (ch == CTRLC) + uninitgame(0); + for (s1=s; *s1 && ch != *s1; ++s1) + continue; + if (*s1) + { + (void) addch((chtype)ch); + (void)refresh(); + return(ch); + } + } +} + + +static void randomfire(int *px, int *py) +/* random-fire routine -- implements simple diagonal-striping strategy */ +{ + static int turncount = 0; + static int srchstep = BEGINSTEP; + static int huntoffs; /* Offset on search strategy */ + int ypossible[BWIDTH * BDEPTH], xpossible[BWIDTH * BDEPTH], nposs; + int ypreferred[BWIDTH * BDEPTH], xpreferred[BWIDTH * BDEPTH], npref; + int x, y, i; + + if (turncount++ == 0) + huntoffs = rnd(srchstep); + + /* first, list all possible moves */ + nposs = npref = 0; + for (x = 0; x < BWIDTH; x++) + for (y = 0; y < BDEPTH; y++) + if (!hits[COMPUTER][x][y]) + { + xpossible[nposs] = x; + ypossible[nposs] = y; + nposs++; + if (((x+huntoffs) % srchstep) != (y % srchstep)) + { + xpreferred[npref] = x; + ypreferred[npref] = y; + npref++; + } + } + + if (npref) + { + i = rnd(npref); + + *px = xpreferred[i]; + *py = ypreferred[i]; + } + else if (nposs) + { + i = rnd(nposs); + + *px = xpossible[i]; + *py = ypossible[i]; + + if (srchstep > 1) + --srchstep; + } + else + { + error("No moves possible?? Help!"); + exit(1); + /*NOTREACHED*/ + } +} + +#define S_MISS 0 +#define S_HIT 1 +#define S_SUNK -1 + +static bool cpufire(int x, int y) +/* fire away at given location */ +{ + bool hit, sunk; + ship_t *ss = NULL; + + hits[COMPUTER][x][y] = (hit = (board[PLAYER][x][y])) ? MARK_HIT : MARK_MISS; + (void) mvprintw(PROMPTLINE, 0, + "I shoot at %c%d. I %s!", y + 'A', x, hit ? "hit" : "miss"); + if ((sunk = (hit && (ss = hitship(x, y))))) + (void) printw(" I've sunk your %s", ss->name); + (void)clrtoeol(); + + pgoto(y, x); +#ifdef A_COLOR + if (has_colors()) + if (hit) + attron(COLOR_PAIR(COLOR_RED)); + else + attron(COLOR_PAIR(COLOR_GREEN)); +#endif /* A_COLOR */ + (void)addch((chtype)(hit ? SHOWHIT : SHOWSPLASH)); +#ifdef A_COLOR + attrset(0); +#endif /* A_COLOR */ + + return(hit ? (sunk ? S_SUNK : S_HIT) : S_MISS); +} + +/* + * This code implements a fairly irregular FSM, so please forgive the rampant + * unstructuredness below. The five labels are states which need to be held + * between computer turns. + */ +static bool cputurn(void) +{ +#define POSSIBLE(x, y) (ONBOARD(x, y) && !hits[COMPUTER][x][y]) +#define RANDOM_FIRE 0 +#define RANDOM_HIT 1 +#define HUNT_DIRECT 2 +#define FIRST_PASS 3 +#define REVERSE_JUMP 4 +#define SECOND_PASS 5 + static int next = RANDOM_FIRE; + static bool used[4]; + static ship_t ts; + int navail, x, y, d, n, hit = S_MISS; + + switch(next) + { + case RANDOM_FIRE: /* last shot was random and missed */ + refire: + randomfire(&x, &y); + if (!(hit = cpufire(x, y))) + next = RANDOM_FIRE; + else + { + ts.x = x; ts.y = y; + ts.hits = 1; + next = (hit == S_SUNK) ? RANDOM_FIRE : RANDOM_HIT; + } + break; + + case RANDOM_HIT: /* last shot was random and hit */ + used[E/2] = used[S/2] = used[W/2] = used[N/2] = FALSE; + /* FALLTHROUGH */ + + case HUNT_DIRECT: /* last shot hit, we're looking for ship's long axis */ + for (d = navail = 0; d < 4; d++) + { + x = ts.x + xincr[d*2]; y = ts.y + yincr[d*2]; + if (!used[d] && POSSIBLE(x, y)) + navail++; + else + used[d] = TRUE; + } + if (navail == 0) /* no valid places for shots adjacent... */ + goto refire; /* ...so we must random-fire */ + else + { + for (d = 0, n = rnd(navail) + 1; n; n--) + while (used[d]) + d++; + + assert(d <= 4); + + used[d] = FALSE; + x = ts.x + xincr[d*2]; + y = ts.y + yincr[d*2]; + + assert(POSSIBLE(x, y)); + + if (!(hit = cpufire(x, y))) + next = HUNT_DIRECT; + else + { + ts.x = x; ts.y = y; ts.dir = d*2; ts.hits++; + next = (hit == S_SUNK) ? RANDOM_FIRE : FIRST_PASS; + } + } + break; + + case FIRST_PASS: /* we have a start and a direction now */ + x = ts.x + xincr[ts.dir]; + y = ts.y + yincr[ts.dir]; + if (POSSIBLE(x, y) && (hit = cpufire(x, y))) + { + ts.x = x; ts.y = y; ts.hits++; + next = (hit == S_SUNK) ? RANDOM_FIRE : FIRST_PASS; + } + else + next = REVERSE_JUMP; + break; + + case REVERSE_JUMP: /* nail down the ship's other end */ + d = ts.dir + 4; + x = ts.x + ts.hits * xincr[d]; + y = ts.y + ts.hits * yincr[d]; + if (POSSIBLE(x, y) && (hit = cpufire(x, y))) + { + ts.x = x; ts.y = y; ts.dir = d; ts.hits++; + next = (hit == S_SUNK) ? RANDOM_FIRE : SECOND_PASS; + } + else + next = RANDOM_FIRE; + break; + + case SECOND_PASS: /* kill squares not caught on first pass */ + x = ts.x + xincr[ts.dir]; + y = ts.y + yincr[ts.dir]; + if (POSSIBLE(x, y) && (hit = cpufire(x, y))) + { + ts.x = x; ts.y = y; ts.hits++; + next = (hit == S_SUNK) ? RANDOM_FIRE: SECOND_PASS; + break; + } + else + next = RANDOM_FIRE; + break; + } + + /* check for continuation and/or winner */ + if (salvo) + { + (void)refresh(); + (void)sleep(1); + } + if (awinna() != -1) + return(FALSE); + +#ifdef DEBUG + (void) mvprintw(PROMPTLINE + 2, 0, + "New state %d, x=%d, y=%d, d=%d", + next, x, y, d); +#endif /* DEBUG */ + return(hit); +} + +static +int playagain(void) +{ + int j; + ship_t *ss; + + for (ss = cpuship; ss < cpuship + SHIPTYPES; ss++) + for(j = 0; j < ss->length; j++) + { + cgoto(ss->y + j * yincr[ss->dir], ss->x + j * xincr[ss->dir]); + (void)addch((chtype)ss->symbol); + } + + if(awinna()) + ++cpuwon; + else + ++plywon; + j = 18 + strlen(name); + if(plywon >= 10) + ++j; + if(cpuwon >= 10) + ++j; + (void) mvprintw(1,(COLWIDTH-j)/2, + "%s: %d Computer: %d",name,plywon,cpuwon); + + prompt(2, (awinna()) ? "Want to be humiliated again, %s [yn]? " + : "Going to give me a chance for revenge, %s [yn]? ",name); + return(sgetc("YN") == 'Y'); +} + +static void do_options(int c, char *op[]) +{ + register int i; + + if (c > 1) + { + for (i=1; i<c; i++) + { + switch(op[i][0]) + { + default: + case '?': + (void) fprintf(stderr, "Usage: battle [-s | -b] [-c]\n"); + (void) fprintf(stderr, "\tWhere the options are:\n"); + (void) fprintf(stderr, "\t-s : play a salvo game\n"); + (void) fprintf(stderr, "\t-b : play a blitz game\n"); + (void) fprintf(stderr, "\t-c : ships may be adjacent\n"); + exit(1); + break; + case '-': + switch(op[i][1]) + { + case 'b': + blitz = 1; + if (salvo == 1) + { + (void) fprintf(stderr, + "Bad Arg: -b and -s are mutually exclusive\n"); + exit(1); + } + break; + case 's': + salvo = 1; + if (blitz == 1) + { + (void) fprintf(stderr, + "Bad Arg: -s and -b are mutually exclusive\n"); + exit(1); + } + break; + case 'c': + closepack = 1; + break; + default: + (void) fprintf(stderr, + "Bad arg: type \"%s ?\" for usage message\n", op[0]); + exit(1); + } + } + } + } +} + +static int scount(int who) +{ + register int i, shots; + register ship_t *sp; + + if (who) + sp = cpuship; /* count cpu shots */ + else + sp = plyship; /* count player shots */ + + for (i=0, shots = 0; i < SHIPTYPES; i++, sp++) + { + if (sp->hits >= sp->length) + continue; /* dead ship */ + else + shots++; + } + return(shots); +} + +int main(int argc, char *argv[]) +{ + do_options(argc, argv); + + intro(); + do { + initgame(); + while(awinna() == -1) + { + if (!blitz) + { + if (!salvo) + { + if(turn) + (void) cputurn(); + else + (void) plyturn(); + } + else + { + register int i; + + i = scount(turn); + while (i--) + { + if (turn) + { + if (cputurn() && awinna() != -1) + i = 0; + } + else + { + if (plyturn() && awinna() != -1) + i = 0; + } + } + } + } + else + while(turn ? cputurn() : plyturn()) + continue; + turn = OTHER; + } + } while + (playagain()); + uninitgame(0); + /*NOTREACHED*/ + return 1; +} + +/* bs.c ends here */ diff --git a/libslang/src/curses/firework.c b/libslang/src/curses/firework.c new file mode 100644 index 0000000..f4aa51a --- /dev/null +++ b/libslang/src/curses/firework.c @@ -0,0 +1,123 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <signal.h> +#include <curses.h> +#include <ctype.h> +#include <time.h> + +static int get_colour(void); +static void explode(int row, int col); +static void showit(void); + +int main(int argc, char *argv[]) +{ +int start,end,row,diff,flag = 0,direction; +unsigned seed; + + initscr(); + if (has_colors()) + start_color(); + seed = time((time_t *)0); + srand(seed); + cbreak(); + for (;;) { + do { + start = rand() % (COLS -3); + end = rand() % (COLS - 3); + start = (start < 2) ? 2 : start; + end = (end < 2) ? 2 : end; + direction = (start > end) ? -1 : 1; + diff = abs(start-end); + } while (diff<2 || diff>=LINES-2); + attrset(A_NORMAL); + for (row=1;row<diff;row++) { + mvprintw(LINES - row,start + (row * direction), + (direction < 0) ? "\\" : "/"); + if (flag++) { + showit(); + erase(); + flag = 0; + } + } + if (flag++) { + showit(); + flag = 0; + } + seed = time((time_t *)0); + srand(seed); + explode(LINES-row,start+(diff*direction)); + erase(); + showit(); + } +} + +static +void explode(int row, int col) +{ + erase(); + mvprintw(row,col,"-"); + showit(); + + init_pair(1,get_colour(),COLOR_BLACK); + attrset(COLOR_PAIR(1)); + mvprintw(row-1,col-1," - "); + mvprintw(row,col-1,"-+-"); + mvprintw(row+1,col-1," - "); + showit(); + + init_pair(1,get_colour(),COLOR_BLACK); + attrset(COLOR_PAIR(1)); + mvprintw(row-2,col-2," --- "); + mvprintw(row-1,col-2,"-+++-"); + mvprintw(row, col-2,"-+#+-"); + mvprintw(row+1,col-2,"-+++-"); + mvprintw(row+2,col-2," --- "); + showit(); + + init_pair(1,get_colour(),COLOR_BLACK); + attrset(COLOR_PAIR(1)); + mvprintw(row-2,col-2," +++ "); + mvprintw(row-1,col-2,"++#++"); + mvprintw(row, col-2,"+# #+"); + mvprintw(row+1,col-2,"++#++"); + mvprintw(row+2,col-2," +++ "); + showit(); + + init_pair(1,get_colour(),COLOR_BLACK); + attrset(COLOR_PAIR(1)); + mvprintw(row-2,col-2," # "); + mvprintw(row-1,col-2,"## ##"); + mvprintw(row, col-2,"# #"); + mvprintw(row+1,col-2,"## ##"); + mvprintw(row+2,col-2," # "); + showit(); + + init_pair(1,get_colour(),COLOR_BLACK); + attrset(COLOR_PAIR(1)); + mvprintw(row-2,col-2," # # "); + mvprintw(row-1,col-2,"# #"); + mvprintw(row, col-2," "); + mvprintw(row+1,col-2,"# #"); + mvprintw(row+2,col-2," # # "); + showit(); +} + +static +int get_colour(void) +{ + int attr; + attr = (rand() % 16)+1; + if (attr == 1 || attr == 9) + attr = COLOR_RED; + if (attr > 8) + attr |= A_BOLD; + return(attr); +} + +static void +showit(void) +{ + refresh(); + napms(120); +} diff --git a/libslang/src/curses/gdc.c b/libslang/src/curses/gdc.c new file mode 100644 index 0000000..4e549f4 --- /dev/null +++ b/libslang/src/curses/gdc.c @@ -0,0 +1,212 @@ +/* + * Grand digital clock for curses compatible terminals + * Usage: gdc [-s] [n] -- run for n seconds (default infinity) + * Flags: -s: scroll + * + * modified 10-18-89 for curses (jrl) + * 10-18-89 added signal handling + */ + +#include <time.h> +#include <signal.h> +#include <curses.h> +#include <stdlib.h> +#include <string.h> +#ifndef NONPOSIX +#include <unistd.h> +#endif + +#define YBASE 10 +#define XBASE 10 +#define XLENGTH 54 +#define YDEPTH 5 + +/* it won't be */ +time_t now; /* yeah! */ +struct tm *tm; + +short disp[11] = { + 075557, 011111, 071747, 071717, 055711, + 074717, 074757, 071111, 075757, 075717, 002020 +}; +long old[6], next[6], new[6], mask; +char scrol; + +int sigtermed=0; + +int hascolor = 0; + +void set(int, int); +void standt(int); +void movto(int, int); + +static +void sighndl(int signo) +{ + signal(signo, sighndl); + sigtermed=signo; +} + +int +main(int argc, char *argv[]) +{ +long t, a; +int i, j, s, k; +int n = 0; + + signal(SIGINT,sighndl); + signal(SIGTERM,sighndl); + signal(SIGKILL,sighndl); + + initscr(); + cbreak(); + noecho(); + nodelay(stdscr, 1); + + hascolor = has_colors(); + + if(hascolor) { + start_color(); + init_pair(1, COLOR_BLACK, COLOR_RED); + init_pair(2, COLOR_RED, COLOR_BLACK); + init_pair(3, COLOR_WHITE, COLOR_BLACK); + attrset(COLOR_PAIR(2)); + } + + clear(); + refresh(); + while(--argc > 0) { + if(**++argv == '-') + scrol = 1; + else + n = atoi(*argv); + } + + if(hascolor) { + attrset(COLOR_PAIR(3)); + + mvaddch(YBASE - 1, XBASE - 1, ACS_ULCORNER); + hline(ACS_HLINE, XLENGTH); + mvaddch(YBASE - 1, XBASE + XLENGTH, ACS_URCORNER); + + mvaddch(YBASE + YDEPTH, XBASE - 1, ACS_LLCORNER); + hline(ACS_HLINE, XLENGTH); + mvaddch(YBASE + YDEPTH, XBASE + XLENGTH, ACS_LRCORNER); + + move(YBASE, XBASE - 1); + vline(ACS_VLINE, YDEPTH); + + move(YBASE, XBASE + XLENGTH); + vline(ACS_VLINE, YDEPTH); + + attrset(COLOR_PAIR(2)); + } + do { + char buf[30]; + + mask = 0; + time(&now); + tm = localtime(&now); + set(tm->tm_sec%10, 0); + set(tm->tm_sec/10, 4); + set(tm->tm_min%10, 10); + set(tm->tm_min/10, 14); + set(tm->tm_hour%10, 20); + set(tm->tm_hour/10, 24); + set(10, 7); + set(10, 17); + for(k=0; k<6; k++) { + if(scrol) { + for(i=0; i<5; i++) + new[i] = (new[i]&~mask) | (new[i+1]&mask); + new[5] = (new[5]&~mask) | (next[k]&mask); + } else + new[k] = (new[k]&~mask) | (next[k]&mask); + next[k] = 0; + for(s=1; s>=0; s--) { + standt(s); + for(i=0; i<6; i++) { + if((a = (new[i]^old[i])&(s ? new : old)[i]) != 0) { + for(j=0,t=1<<26; t; t>>=1,j++) { + if(a&t) { + if(!(a&(t<<1))) { + movto(YBASE + i, XBASE + 2*j); + } + addstr(" "); + } + } + } + if(!s) { + old[i] = new[i]; + } + } + if(!s) { + refresh(); + } + } + } + + /* this depends on the detailed format of ctime(3) */ + (void) strcpy(buf, ctime(&now)); + (void) strcpy(buf + 10, buf + 19); + mvaddstr(16, 30, buf); + + movto(6, 0); + refresh(); + sleep(1); + while(wgetch(stdscr) != ERR) + continue; + if (sigtermed) { + standend(); + clear(); + refresh(); + endwin(); + fprintf(stderr, "gdc terminated by signal %d\n", sigtermed); + exit(1); + } + } while(--n); + standend(); + clear(); + refresh(); + endwin(); + return(0); +} + +void +set(int t, int n) +{ +int i, m; + + m = 7<<n; + for(i=0; i<5; i++) { + next[i] |= ((disp[t]>>(4-i)*3)&07)<<n; + mask |= (next[i]^old[i])&m; + } + if(mask&m) + mask |= m; +} + +void +standt(int on) +{ + if (on) { + if(hascolor) { + attron(COLOR_PAIR(1)); + } else { + attron(A_STANDOUT); + } + } else { + if(hascolor) { + attron(COLOR_PAIR(2)); + } else { + attroff(A_STANDOUT); + } + } +} + +void +movto(int line, int col) +{ + move(line, col); +} + diff --git a/libslang/src/curses/hanoi.c b/libslang/src/curses/hanoi.c new file mode 100644 index 0000000..4f81a59 --- /dev/null +++ b/libslang/src/curses/hanoi.c @@ -0,0 +1,292 @@ +/* + * Name: Towers of Hanoi. + * + * Desc: + * This is a playable copy of towers of hanoi. + * Its sole purpose is to demonstrate my Amiga Curses package. + * This program should compile on any system that has Curses. + * 'hanoi' will give a manual game with 7 playing pieces. + * 'hanoi n' will give a manual game with n playing pieces. + * 'hanoi n a' will give an auto solved game with n playing pieces. + * + * Author: Simon J Raybould (sie@fulcrum.bt.co.uk). + * (This version has been slightly modified by the ncurses maintainers.) + * + * Date: 05.Nov.90 + * + */ + +#include <curses.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#define NPEGS 3 /* This is not configurable !! */ +#define MINTILES 3 +#define MAXTILES 9 +#define DEFAULTTILES 7 +#define TOPLINE 6 +#define BASELINE 16 +#define STATUSLINE (LINES-3) +#define LEFTPEG 19 +#define MIDPEG 39 +#define RIGHTPEG 59 + +#define LENTOIND(x) (((x)-1)/2) +#define OTHER(a,b) (3-((a)+(b))) + +struct Peg { + size_t Length[MAXTILES]; + int Count; +}; + +struct Peg Pegs[NPEGS]; +int PegPos[] = { LEFTPEG, MIDPEG, RIGHTPEG }; +int TileColour[] = { + COLOR_GREEN, /* Length 3 */ + COLOR_MAGENTA, /* Length 5 */ + COLOR_RED, /* Length 7 */ + COLOR_BLUE, /* Length 9 */ + COLOR_CYAN, /* Length 11 */ + COLOR_YELLOW, /* Length 13 */ + COLOR_GREEN, /* Length 15 */ + COLOR_MAGENTA, /* Length 17 */ + COLOR_RED, /* Length 19 */ +}; +int NMoves = 0; + +void InitTiles(int NTiles); +void DisplayTiles(void); +void MakeMove(int From, int To); +void AutoMove(int From, int To, int Num); +void Usage(void); +int Solved(int NumTiles); +int GetMove(int *From, int *To); +int InvalidMove(int From, int To); + +int +main(int argc, char **argv) +{ +int NTiles, FromCol, ToCol; +unsigned char AutoFlag = 0; + + switch(argc) { + case 1: + NTiles = DEFAULTTILES; + break; + case 2: + NTiles = atoi(argv[1]); + if (NTiles > MAXTILES || NTiles < MINTILES) { + fprintf(stderr, "Range %d to %d\n", MINTILES, MAXTILES); + exit(1); + } + break; + case 3: + if (strcmp(argv[2], "a")) { + Usage(); + exit(1); + } + NTiles = atoi(argv[1]); + if (NTiles > MAXTILES || NTiles < MINTILES) { + fprintf(stderr, "Range %d to %d\n", MINTILES, MAXTILES); + exit(1); + } + AutoFlag = TRUE; + break; + default: + Usage(); + exit(1); + } +#ifdef NCURSES_VERSION + trace(TRACE_MAXIMUM); +#endif + initscr(); + if (!has_colors()) { + endwin(); + puts("terminal doesn't support color."); + exit(1); + } + start_color(); + { + int i; + for (i = 0; i < 9; i++) + init_pair(i+1, COLOR_BLACK, TileColour[i]); + } + cbreak(); + if (LINES < 24) { + endwin(); + fprintf(stderr, "Min screen length 24 lines\n"); + exit(1); + } + if(AutoFlag) + leaveok(stdscr, TRUE); /* Attempt to remove cursor */ + InitTiles(NTiles); + DisplayTiles(); + if(AutoFlag) { + do { + noecho(); + AutoMove(0, 2, NTiles); + } while(!Solved(NTiles)); + sleep(2); + } else { + for(;;) { + if(GetMove(&FromCol, &ToCol)) + break; + if(InvalidMove(FromCol, ToCol)) { + mvaddstr(STATUSLINE, 0, "Invalid Move !!"); + refresh(); + beep(); + continue; + } + MakeMove(FromCol, ToCol); + if(Solved(NTiles)) { + mvprintw(STATUSLINE, 0, "Well Done !! You did it in %d moves", NMoves); + refresh(); + sleep(5); + break; + } + } + } + curs_set(1); + endwin(); + exit(0); +} + +int +InvalidMove(int From, int To) +{ + if(From >= NPEGS) + return TRUE; + if(From < 0) + return TRUE; + if(To >= NPEGS) + return TRUE; + if(To < 0) + return TRUE; + if(From == To) + return TRUE; + if(!Pegs[From].Count) + return TRUE; + if(Pegs[To].Count && + Pegs[From].Length[Pegs[From].Count-1] > + Pegs[To].Length[Pegs[To].Count-1]) + return TRUE; + return FALSE; +} + +void +InitTiles(int NTiles) +{ +int Size, SlotNo; + + for(Size=NTiles*2+1, SlotNo=0; Size>=3; Size-=2) + Pegs[0].Length[SlotNo++] = Size; + + Pegs[0].Count = NTiles; + Pegs[1].Count = 0; + Pegs[2].Count = 0; +} + +void +DisplayTiles() +{ + int Line, Peg, SlotNo; + char TileBuf[BUFSIZ]; + + erase(); + mvaddstr(1, 24, "T O W E R S O F H A N O I"); + mvaddstr(3, 34, "SJR 1990"); + mvprintw(19, 5, "Moves : %d", NMoves); + attrset(A_REVERSE); + mvaddstr(BASELINE, 8, " "); + + for(Line=TOPLINE; Line<BASELINE; Line++) { + mvaddch(Line, LEFTPEG, ' '); + mvaddch(Line, MIDPEG, ' '); + mvaddch(Line, RIGHTPEG, ' '); + } + mvaddch(BASELINE, LEFTPEG, '1'); + mvaddch(BASELINE, MIDPEG, '2'); + mvaddch(BASELINE, RIGHTPEG, '3'); + attrset(A_NORMAL); + + /* Draw tiles */ + for(Peg=0; Peg<NPEGS; Peg++) { + for(SlotNo=0; SlotNo<Pegs[Peg].Count; SlotNo++) { + memset(TileBuf, ' ', Pegs[Peg].Length[SlotNo]); + TileBuf[Pegs[Peg].Length[SlotNo]] = '\0'; + attrset(COLOR_PAIR(LENTOIND(Pegs[Peg].Length[SlotNo]))); + mvaddstr(BASELINE-(SlotNo+1), + (int)(PegPos[Peg] - Pegs[Peg].Length[SlotNo]/2), + TileBuf); + } + } + attrset(A_NORMAL); + refresh(); +} + +int +GetMove(int *From, int *To) +{ + mvaddstr(STATUSLINE, 0, "Next move ('q' to quit) from "); + clrtoeol(); + refresh(); + if((*From = getch()) == 'q') + return TRUE; + addch(*From); + *From -= ('0'+1); + addstr(" to "); + clrtoeol(); + refresh(); + if((*To = getch()) == 'q') + return TRUE; + addch(*To); + *To -= ('0'+1); + move(STATUSLINE, 0); + clrtoeol(); + refresh(); + return FALSE; +} + +void +MakeMove(int From, int To) +{ + + Pegs[From].Count--; + Pegs[To].Length[Pegs[To].Count] = Pegs[From].Length[Pegs[From].Count]; + Pegs[To].Count++; + NMoves++; + DisplayTiles(); +} + +void +AutoMove(int From, int To, int Num) +{ + + if(Num == 1) { + MakeMove(From, To); + return; + } + AutoMove(From, OTHER(From, To), Num-1); + MakeMove(From, To); + AutoMove(OTHER(From, To), To, Num-1); +} + +int +Solved(int NumTiles) +{ +int i; + + for(i = 1; i < NPEGS; i++) + if (Pegs[i].Count == NumTiles) + return TRUE; + return FALSE; +} + +void +Usage() +{ + fprintf(stderr, "Usage: hanoi [<No Of Tiles>] [a]\n"); + fprintf(stderr, "The 'a' option causes the tower to be solved automatically\n"); +} + diff --git a/libslang/src/curses/knight.c b/libslang/src/curses/knight.c new file mode 100644 index 0000000..7314eac --- /dev/null +++ b/libslang/src/curses/knight.c @@ -0,0 +1,555 @@ +/* + * Knight's Tour - a brain game + * + * The original of this game was anonymous. It had an unbelievably bogus + * interface, you actually had to enter square coordinates! Redesign by + * Eric S. Raymond <esr@snark.thyrsus.com> July 22 1995. Mouse support + * added September 20th 1995. + */ + +#include <curses.h> +#include <ctype.h> +#include <signal.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +/* board size */ +#define BDEPTH 8 +#define BWIDTH 8 + +/* where to start the instructions */ +#define INSTRY 2 +#define INSTRX 35 + +/* corner of board */ +#define BOARDY 2 +#define BOARDX 0 + +/* notification line */ +#define NOTIFYY 21 + +/* virtual color values */ +#define TRAIL_COLOR 1 +#define PLUS_COLOR 2 +#define MINUS_COLOR 3 + +#define CX(x) (2 + 4 * (x)) +#define CY(y) (1 + 2 * (y)) +#define cellmove(y, x) wmove(boardwin, CY(y), CX(x)) +#define CXINV(x) (((x) - 1) / 4) +#define CYINV(y) (((y) - 2) / 2) + +typedef struct +{ + short x, y; +} +cell; + +static short board[BDEPTH][BWIDTH]; /* the squares */ +static int rw,col; /* current row and column */ +static int lastrow,lastcol; /* last location visited */ +static cell history[BDEPTH*BWIDTH]; /* choice history */ +static int movecount; /* count of moves so far */ +static WINDOW *boardwin; /* the board window */ +static WINDOW *helpwin; /* the help window */ +static WINDOW *msgwin; /* the message window */ +static chtype trail = '#'; /* trail character */ +static chtype plus = '+'; /* cursor hot-spot character */ +static chtype minus = '-'; /* possible-move character */ +static chtype oldch; + +static void init(void); +static void play(void); +static void dosquares(void); +static void drawmove(char, int, int, int, int); +static bool evalmove(int, int); +static bool chkmoves(void); +static bool chksqr(int, int); +static int iabs(int); + +int main(int argc, char *argv[]) +{ + init(); + + play(); + + endwin(); + exit(0); +} + +static void init (void) +{ + srand ((unsigned)getpid()); + initscr (); + cbreak (); /* immediate char return */ + noecho (); /* no immediate echo */ + boardwin = newwin(BDEPTH * 2 + 1, BWIDTH * 4 + 1, BOARDY, BOARDX); + helpwin = newwin(0, 0, INSTRY, INSTRX); + msgwin = newwin(1, INSTRX-1, NOTIFYY, 0); + keypad(boardwin, TRUE); + + if (has_colors()) + { + start_color(); + + (void) init_pair(TRAIL_COLOR, COLOR_CYAN, COLOR_BLACK); + (void) init_pair(PLUS_COLOR, COLOR_RED, COLOR_BLACK); + (void) init_pair(MINUS_COLOR, COLOR_GREEN, COLOR_BLACK); + + trail |= COLOR_PAIR(TRAIL_COLOR); + plus |= COLOR_PAIR(PLUS_COLOR); + minus |= COLOR_PAIR(MINUS_COLOR); + } + +#ifdef NCURSES_MOUSE_VERSION + (void) mousemask(BUTTON1_CLICKED, (mmask_t *)NULL); +#endif /* NCURSES_MOUSE_VERSION*/ + + oldch = minus; +} + +static void help1(void) +/* game explanation -- initial help screen */ +{ + (void)waddstr(helpwin, "Knight's move is a solitaire puzzle. Your\n"); + (void)waddstr(helpwin, "objective is to visit each square of the \n"); + (void)waddstr(helpwin, "chessboard exactly once by making knight's\n"); + (void)waddstr(helpwin, "moves (one square right or left followed \n"); + (void)waddstr(helpwin, "by two squares up or down, or two squares \n"); + (void)waddstr(helpwin, "right or left followed by one square up or\n"); + (void)waddstr(helpwin, "down). You may start anywhere.\n\n"); + + (void)waddstr(helpwin, "Use arrow keys to move the cursor around.\n"); + (void)waddstr(helpwin, "When you want to move your knight to the \n"); + (void)waddstr(helpwin, "cursor location, press <space> or Enter.\n"); + (void)waddstr(helpwin, "Illegal moves will be rejected with an \n"); + (void)waddstr(helpwin, "audible beep.\n\n"); + (void)waddstr(helpwin, "The program will detect if you solve the\n"); + (void)waddstr(helpwin, "puzzle; also inform you when you run out\n"); + (void)waddstr(helpwin, "of legal moves.\n\n"); + + (void)mvwaddstr(helpwin, NOTIFYY-INSTRY, 0, + "Press `?' to go to keystroke help."); +} + +static void help2(void) +/* keystroke help screen */ +{ + (void)waddstr(helpwin, "Possible moves are shown with `-'.\n\n"); + + (void)waddstr(helpwin, "You can move around with the arrow keys or\n"); + (void)waddstr(helpwin, "with the rogue/hack movement keys. Other\n"); + (void)waddstr(helpwin, "commands allow you to undo moves or redraw.\n"); + (void)waddstr(helpwin, "Your mouse may work; try left-button to\n"); + (void)waddstr(helpwin, "move to the square under the pointer.\n\n"); + + (void)waddstr(helpwin, "x,q -- exit y k u 7 8 9\n"); + (void)waddstr(helpwin, "r -- redraw screen \\|/ \\|/ \n"); + (void)waddstr(helpwin, "u -- undo move h-+-l 4-+-6\n"); + (void)waddstr(helpwin, " /|\\ /|\\ \n"); + (void)waddstr(helpwin, " b j n 1 2 3\n"); + + (void)waddstr(helpwin,"\nYou can place your knight on the selected\n"); + (void)waddstr(helpwin, "square with spacebar, Enter, or the keypad\n"); + (void)waddstr(helpwin, "center key. You can quit with `x' or `q'.\n"); + + (void)mvwaddstr(helpwin, NOTIFYY-INSTRY, 0, + "Press `?' to go to game explanation"); +} + +static void play (void) +/* play the game */ +{ + bool keyhelp; /* TRUE if keystroke help is up */ + int c, ny = 0, nx = 0; + int i, j, count; + + do { + /* clear screen and draw board */ + werase(boardwin); + werase(helpwin); + werase(msgwin); + dosquares(); + help1(); + wnoutrefresh(stdscr); + wnoutrefresh(helpwin); + wnoutrefresh(msgwin); + wnoutrefresh(boardwin); + doupdate(); + + for (i = 0; i < BDEPTH; i++) + for (j = 0; j < BWIDTH; j++) + { + board[i][j] = FALSE; + cellmove(i, j); + waddch(boardwin, minus); + } + memset(history, '\0', sizeof(history)); + history[0].y = history[0].x = -1; + lastrow = lastcol = -2; + movecount = 1; + keyhelp = FALSE; + + for (;;) + { + if (rw != lastrow || col != lastcol) + { + if (lastrow >= 0 && lastcol >= 0) + { + cellmove(lastrow, lastcol); + if (board[lastrow][lastcol]) + waddch(boardwin, trail); + else + waddch(boardwin, oldch); + } + + cellmove(rw, col); + oldch = winch(boardwin); + + lastrow = rw; + lastcol= col; + } + cellmove(rw, col); + waddch(boardwin, plus); + cellmove(rw, col); + + wrefresh(msgwin); + + c = wgetch(boardwin); + + werase(msgwin); + + switch (c) + { + case 'k': case '8': + case KEY_UP: + ny = rw+BDEPTH-1; nx = col; + break; + case 'j': case '2': + case KEY_DOWN: + ny = rw+1; nx = col; + break; + case 'h': case '4': + case KEY_LEFT: + ny = rw; nx = col+BWIDTH-1; + break; + case 'l': case '6': + case KEY_RIGHT: + ny = rw; nx = col+1; + break; + case 'y': case '7': + case KEY_A1: + ny = rw+BDEPTH-1; nx = col+BWIDTH-1; + break; + case 'b': case '1': + case KEY_C1: + ny = rw+1; nx = col+BWIDTH-1; + break; + case 'u': case '9': + case KEY_A3: + ny = rw+BDEPTH-1; nx = col+1; + break; + case 'n': case '3': + case KEY_C3: + ny = rw+1; nx = col+1; + break; + +#ifdef NCURSES_MOUSE_VERSION + case KEY_MOUSE: + { + MEVENT myevent; + + getmouse(&myevent); + if (myevent.y >= CY(0) && myevent.y <= CY(BDEPTH) + && myevent.x >= CX(0) && myevent.x <= CX(BWIDTH)) + { + nx = CXINV(myevent.x); + ny = CYINV(myevent.y); + ungetch('\n'); + break; + } + else + { + beep(); + continue; + } + } +#endif /* NCURSES_MOUSE_VERSION */ + + case KEY_B2: + case '\n': + case ' ': + if (evalmove(rw, col)) + { + drawmove(trail, + history[movecount-1].y, history[movecount-1].x, + rw, col); + history[movecount].y = rw; + history[movecount].x = col; + movecount++; + + if (!chkmoves()) + goto dropout; + } + else + beep(); + break; + + case KEY_REDO: + case '\f': + case 'r': + clearok(curscr, TRUE); + wnoutrefresh(stdscr); + wnoutrefresh(boardwin); + wnoutrefresh(msgwin); + wnoutrefresh(helpwin); + doupdate(); + break; + + case KEY_UNDO: + case KEY_BACKSPACE: + case '\b': + if (movecount == 1) + { + ny = lastrow; + nx = lastcol; + waddstr(msgwin, "\nNo previous move."); + beep(); + } + else + { + int oldy = history[movecount-1].y; + int oldx = history[movecount-1].x; + + board[oldy][oldx] = FALSE; + --movecount; + ny = history[movecount-1].y; + nx = history[movecount-1].x; + drawmove(' ', oldy, oldx, ny, nx); + + /* avoid problems if we just changed the current cell */ + cellmove(lastrow, lastcol); + oldch = winch(boardwin); + } + break; + + case 'q': + case 'x': + goto dropout; + + case '?': + werase(helpwin); + if (keyhelp) + { + help1(); + keyhelp = FALSE; + } + else + { + help2(); + keyhelp = TRUE; + } + wrefresh(helpwin); + break; + + default: + beep(); + break; + } + + col = nx % BWIDTH; + rw = ny % BDEPTH; + } + + dropout: + count = 0; + for (i = 0; i < BDEPTH; i++) + for (j = 0; j < BWIDTH; j++) + if (board[i][j] != 0) + count += 1; + if (count == (BWIDTH * BDEPTH)) + wprintw(msgwin, "\nYou won. Care to try again? "); + else + wprintw(msgwin, "\n%d squares filled. Try again? ", count); + } while + (tolower(wgetch(msgwin)) == 'y'); +} + +static void dosquares (void) +{ + int i, j; + + mvaddstr(0, 20, "KNIGHT'S MOVE -- a logical solitaire"); + + move(BOARDY,BOARDX); + waddch(boardwin, ACS_ULCORNER); + for (j = 0; j < 7; j++) + { + waddch(boardwin, ACS_HLINE); + waddch(boardwin, ACS_HLINE); + waddch(boardwin, ACS_HLINE); + waddch(boardwin, ACS_TTEE); + } + waddch(boardwin, ACS_HLINE); + waddch(boardwin, ACS_HLINE); + waddch(boardwin, ACS_HLINE); + waddch(boardwin, ACS_URCORNER); + + for (i = 1; i < BDEPTH; i++) + { + move(BOARDY + i * 2 - 1, BOARDX); + waddch(boardwin, ACS_VLINE); + for (j = 0; j < BWIDTH; j++) + { + waddch(boardwin, ' '); + waddch(boardwin, ' '); + waddch(boardwin, ' '); + waddch(boardwin, ACS_VLINE); + } + move(BOARDY + i * 2, BOARDX); + waddch(boardwin, ACS_LTEE); + for (j = 0; j < BWIDTH - 1; j++) + { + waddch(boardwin, ACS_HLINE); + waddch(boardwin, ACS_HLINE); + waddch(boardwin, ACS_HLINE); + waddch(boardwin, ACS_PLUS); + } + waddch(boardwin, ACS_HLINE); + waddch(boardwin, ACS_HLINE); + waddch(boardwin, ACS_HLINE); + waddch(boardwin, ACS_RTEE); + } + + move(BOARDY + i * 2 - 1, BOARDX); + waddch(boardwin, ACS_VLINE); + for (j = 0; j < BWIDTH; j++) + { + waddch(boardwin, ' '); + waddch(boardwin, ' '); + waddch(boardwin, ' '); + waddch(boardwin, ACS_VLINE); + } + + move(BOARDY + i * 2, BOARDX); + waddch(boardwin, ACS_LLCORNER); + for (j = 0; j < BWIDTH - 1; j++) + { + waddch(boardwin, ACS_HLINE); + waddch(boardwin, ACS_HLINE); + waddch(boardwin, ACS_HLINE); + waddch(boardwin, ACS_BTEE); + } + waddch(boardwin, ACS_HLINE); + waddch(boardwin, ACS_HLINE); + waddch(boardwin, ACS_HLINE); + waddch(boardwin, ACS_LRCORNER); +} + +static void mark_possibles(int prow, int pcol, chtype mark) +{ + if (chksqr(prow+2,pcol+1)){cellmove(prow+2,pcol+1);waddch(boardwin,mark);}; + if (chksqr(prow+2,pcol-1)){cellmove(prow+2,pcol-1);waddch(boardwin,mark);}; + if (chksqr(prow-2,pcol+1)){cellmove(prow-2,pcol+1);waddch(boardwin,mark);}; + if (chksqr(prow-2,pcol-1)){cellmove(prow-2,pcol-1);waddch(boardwin,mark);}; + if (chksqr(prow+1,pcol+2)){cellmove(prow+1,pcol+2);waddch(boardwin,mark);}; + if (chksqr(prow+1,pcol-2)){cellmove(prow+1,pcol-2);waddch(boardwin,mark);}; + if (chksqr(prow-1,pcol+2)){cellmove(prow-1,pcol+2);waddch(boardwin,mark);}; + if (chksqr(prow-1,pcol-2)){cellmove(prow-1,pcol-2);waddch(boardwin,mark);}; +} + +static void drawmove(char tchar, int oldy, int oldx, int row, int column) +/* place the stars, update board & currents */ +{ + if (movecount <= 1) + { + int i, j; + + for (i = 0; i < BDEPTH; i++) + for (j = 0; j < BWIDTH; j++) + { + cellmove(i, j); + if (winch(boardwin) == minus) + waddch(boardwin, movecount ? ' ' : minus); + } + } + else + { + cellmove(oldy, oldx); + waddch(boardwin, '\b'); + waddch(boardwin, tchar); + waddch(boardwin, tchar); + waddch(boardwin, tchar); + mark_possibles(oldy, oldx, ' '); + } + + if (row != -1 && column != -1) + { + cellmove(row, column); + waddch(boardwin, '\b'); + waddch(boardwin, trail); + waddch(boardwin, trail); + waddch(boardwin, trail); + mark_possibles(row, column, minus); + board[row][column] = TRUE; + } + + wprintw(msgwin, "\nMove %d", movecount); +} + +static bool evalmove(int row, int column) +/* evaluate move */ +{ + if (movecount == 1) + return(TRUE); + else if (board[row][column] == TRUE) + { + waddstr(msgwin, "\nYou've already been there."); + return(FALSE); + } + else + { + int rdif = iabs(row - history[movecount-1].y); + int cdif = iabs(column - history[movecount-1].x); + + if (!((rdif == 1) && (cdif == 2)) && !((rdif == 2) && (cdif == 1))) + { + waddstr(msgwin, "\nThat's not a legal knight's move."); + return(FALSE); + } + } + + return(TRUE); +} + +static bool chkmoves (void) +/* check to see if valid moves are available */ +{ + if (chksqr(rw+2,col+1)) return(TRUE); + if (chksqr(rw+2,col-1)) return(TRUE); + if (chksqr(rw-2,col+1)) return(TRUE); + if (chksqr(rw-2,col-1)) return(TRUE); + if (chksqr(rw+1,col+2)) return(TRUE); + if (chksqr(rw+1,col-2)) return(TRUE); + if (chksqr(rw-1,col+2)) return(TRUE); + if (chksqr(rw-1,col-2)) return(TRUE); + return (FALSE); +} + +static int iabs(int num) +{ + if (num < 0) return (-num); + else return (num); +} + +static bool chksqr (int r1, int c1) +{ + if ((r1 < 0) || (r1 > BDEPTH - 1)) + return(FALSE); + if ((c1 < 0) || (c1 > BWIDTH - 1)) + return(FALSE); + return (!board[r1][c1]); +} + +/* knight.c ends here */ diff --git a/libslang/src/curses/rain.c b/libslang/src/curses/rain.c new file mode 100644 index 0000000..792dab9 --- /dev/null +++ b/libslang/src/curses/rain.c @@ -0,0 +1,97 @@ +#include <curses.h> +#include <signal.h> +#include <stdlib.h> + +/* rain 11/3/1980 EPS/CITHEP */ + +#define cursor(col,row) move(row,col) + +float ranf(void); +void onsig(int sig); + +int +main(int argc, char *argv[]) +{ +int x, y, j; +static int xpos[5], ypos[5]; +float r; +float c; + + for (j=SIGHUP;j<=SIGTERM;j++) + if (signal(j,SIG_IGN)!=SIG_IGN) signal(j,onsig); + + initscr(); + nl(); + noecho(); + r = (float)(LINES - 4); + c = (float)(COLS - 4); + for (j=5;--j>=0;) { + xpos[j]=(int)(c* ranf())+2; + ypos[j]=(int)(r* ranf())+2; + } + for (j=0;;) { + x=(int)(c*ranf())+2; + y=(int)(r*ranf())+2; + + cursor(x,y); addch('.'); + + cursor(xpos[j],ypos[j]); addch('o'); + + if (j==0) j=4; else --j; + cursor(xpos[j],ypos[j]); addch('O'); + + if (j==0) j=4; else --j; + cursor(xpos[j],ypos[j]-1); + addch('-'); + cursor(xpos[j]-1,ypos[j]); + addstr("|.|"); + cursor(xpos[j],ypos[j]+1); + addch('-'); + + if (j==0) j=4; else --j; + cursor(xpos[j],ypos[j]-2); + addch('-'); + cursor(xpos[j]-1,ypos[j]-1); + addstr("/ \\"); + cursor(xpos[j]-2,ypos[j]); + addstr("| O |"); + cursor(xpos[j]-1,ypos[j]+1); + addstr("\\ /"); + cursor(xpos[j],ypos[j]+2); + addch('-'); + + if (j==0) j=4; else --j; + cursor(xpos[j],ypos[j]-2); + addch(' '); + cursor(xpos[j]-1,ypos[j]-1); + addstr(" "); + cursor(xpos[j]-2,ypos[j]); + addstr(" "); + cursor(xpos[j]-1,ypos[j]+1); + addstr(" "); + cursor(xpos[j],ypos[j]+2); + addch(' '); + xpos[j]=x; ypos[j]=y; + refresh(); + napms(50); + } +} + +void +onsig(int n) +{ + endwin(); + exit(n); +} + +float +ranf(void) +{ + float rv; + long r = rand(); + + r &= 077777; + rv =((float)r/32767.); + return rv; +} + diff --git a/libslang/src/curses/tclock.c b/libslang/src/curses/tclock.c new file mode 100644 index 0000000..12c0125 --- /dev/null +++ b/libslang/src/curses/tclock.c @@ -0,0 +1,177 @@ +#include <stdio.h> +#include <float.h> +#include <math.h> +#include <time.h> +#include <stdlib.h> +#include <unistd.h> +#include <curses.h> + +/* + tclock - analog/digital clock for curses. + If it gives you joy, then + (a) I'm glad + (b) you need to get out more :-) + + This program is copyright Howard Jones, September 1994 + (ha.jones@ic.ac.uk). It may be freely distributed as + long as this copyright message remains intact, and any + modifications are clearly marked as such. [In fact, if + you modify it, I wouldn't mind the modifications back, + especially if they add any nice features. A good one + would be a precalc table for the 60 hand positions, so + that the floating point stuff can be ditched. As I said, + it was a 20 hackup minute job.] + + COMING SOON: tfishtank. Be the envy of your mac-owning + colleagues. +*/ + +/* To compile: cc -o tclock tclock.c -lcurses -lm */ + +#ifndef PI +#define PI 3.141592654 +#endif + +#define sign(_x) (_x<0?-1:1) + +/* Plot a point */ +static void +plot(int x,int y,char col) +{ + mvaddch(y,x,(chtype)col); +} + + +/* Draw a diagonal(arbitrary) line using Bresenham's alogrithm. */ +static void +dline(int from_x, int from_y, int x2, int y2, char ch) +{ + int dx,dy; + int ax,ay; + int sx,sy; + int x,y; + int d; + + dx=x2-from_x; + dy=y2-from_y; + + ax=abs(dx*2); + ay=abs(dy*2); + + sx=sign(dx); + sy=sign(dy); + + x=from_x; + y=from_y; + + if(ax>ay) + { + d=ay-(ax/2); + + while(1) + { + plot(x,y,ch); + if(x==x2) return; + + if(d>=0) + { + y+=sy; + d-=ax; + } + x+=sx; + d+=ay; + } + } + else + { + d=ax-(ay/2); + + while(1) + { + plot(x,y,ch); + if(y==y2) return; + + if(d>=0) + { + x+=sx; + d-=ay; + } + y+=sy; + d+=ax; + } + } +} + +int +main(int argc, char **argv) +{ + int i,cx,cy; + double mradius, hradius, mangle, hangle; + double sangle, sradius, hours; + int hdx, hdy; + int mdx, mdy; + int sdx, sdy; + time_t tim; + struct tm *t; + char szChar[10]; + + initscr(); + noecho(); + + cx=39; + cy=12; + mradius=9; + hradius=6; + sradius=8; + + for(i=0;i<12;i++) + { + sangle=(i+1)*(2.0*PI)/12.0; + sradius=10; + sdx=2.0*sradius*sin(sangle); + sdy=sradius*cos(sangle); + sprintf(szChar,"%d",i+1); + + mvaddstr((int)(cy-sdy),(int)(cx+sdx),szChar); + } + + mvaddstr(0,0,"ASCII Clock by Howard Jones (ha.jones@ic.ac.uk),1994"); + + sradius=8; + while(1) + { + sleep(1); + + tim=time(0); + t=localtime(&tim); + + hours=(t->tm_hour + (t->tm_min/60.0)); + if(hours>12.0) hours-=12.0; + + mangle=(t->tm_min)*(2*PI)/60.0; + mdx=2.0*mradius*sin(mangle); + mdy=mradius*cos(mangle); + + hangle=(hours)*(2.0*PI)/12.0; + hdx=2.0*hradius*sin(hangle); + hdy=hradius*cos(hangle); + + sangle=(t->tm_sec%60)*(2.0*PI)/60.0; + sdx=2.0*sradius*sin(sangle); + sdy=sradius*cos(sangle); + + plot(cx+sdx,cy-sdy,'O'); + dline(cx,cy,cx+hdx,cy-hdy,'.'); + dline(cx,cy,cx+mdx,cy-mdy,'#'); + + mvaddstr(23,0,ctime(&tim)); + + refresh(); + plot(cx+sdx,cy-sdy,' '); + dline(cx,cy,cx+hdx,cy-hdy,' '); + dline(cx,cy,cx+mdx,cy-mdy,' '); + + } + + return 0; +} diff --git a/libslang/src/curses/view.c b/libslang/src/curses/view.c new file mode 100644 index 0000000..8286dac --- /dev/null +++ b/libslang/src/curses/view.c @@ -0,0 +1,143 @@ +/* + * view.c -- a silly little viewer program + * + * written by Eric S. Raymond <esr@snark.thyrsus.com> December 1994 + * to test the scrolling code in ncurses. + * + * Takes a filename argument. It's a simple file-viewer with various + * scroll-up and scroll-down commands. + * + * n -- scroll one line forward + * p -- scroll one line back + * + * Either command accepts a numeric prefix interpreted as a repeat count. + * Thus, typing `5n' should scroll forward 5 lines in the file. + * + * The way you can tell this is working OK is that, in the trace file, + * there should be one scroll operation plus a small number of line + * updates, as opposed to a whole-page update. This means the physical + * scroll operation worked, and the refresh() code only had to do a + * partial repaint. + */ +#include <curses.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <signal.h> + +#define MAXLINES 256 /* most lines we can handle */ + +static void finish(int sig); + +static char *lines[MAXLINES]; + +int main(int argc, char *argv[]) +{ +FILE *fp; +char buf[BUFSIZ]; +int i; +char **lptr, **olptr; + +#ifdef TRACE + trace(TRACE_UPDATE); +#endif + + if (argc != 2) { + fprintf(stderr, "usage: view file\n"); + exit(1); + } else if ((fp = fopen(argv[1], "r")) == (FILE *)NULL) { + perror(argv[1]); + exit(1); + } + + (void) signal(SIGINT, finish); /* arrange interrupts to terminate */ + + (void) initscr(); /* initialize the curses library */ + keypad(stdscr, TRUE); /* enable keyboard mapping */ + (void) nonl(); /* tell curses not to do NL->CR/NL on output */ + (void) cbreak(); /* take input chars one at a time, no wait for \n */ + (void) noecho(); /* don't echo input */ + scrollok(stdscr, TRUE); + + /* slurp the file */ + for (lptr = &lines[0]; fgets(buf, BUFSIZ, fp) != (char *)NULL; lptr++) { + if (lptr - lines >= MAXLINES) { + endwin(); + (void) fprintf(stderr, "%s: %s is too large\n", argv[0], argv[1]); + exit(1); + } + + buf[strlen(buf) - 1] = '\0'; + *lptr = (char *)malloc((size_t)(COLS + 1)); + (void) strncpy(*lptr, buf, (size_t)COLS); + (*lptr)[COLS] = '\0'; + } + (void) fclose(fp); + + lptr = lines; + for (;;) { + int n, c; + bool explicit; + + for (i = 0; i < LINES; i++) { + move(i, 0); + clrtoeol(); + if (lptr[i]) + addstr(lptr[i]); + } + + explicit = FALSE; + n = 0; + for (;;) { + c = getch(); + if (isdigit(c)) + n = 10 * n + (c - '0'); + else + break; + } + if (!explicit && n == 0) + n = 1; + + switch(c) { + case KEY_DOWN: + case 'n': + olptr = lptr; + for (i = 0; i < n; i++) + if (lptr + LINES < lines + MAXLINES && lptr[LINES + 1]) + lptr++; + else + break; + wscrl(stdscr, lptr - olptr); + break; + + case KEY_UP: + case 'p': + olptr = lptr; + for (i = 0; i < n; i++) + if (lptr > lines) + lptr--; + else + break; + wscrl(stdscr, lptr - olptr); + break; + + default: + move (0,0); + clrtoeol (); + printw ("Invalid input: %c", c); + refresh (); + sleep (1); + } + } + + finish(0); /* we're done */ +} + +static void finish(int sig) +{ + endwin(); + exit(sig != 0); +} + +/* view.c ends here */ + diff --git a/libslang/src/curses/worm.c b/libslang/src/curses/worm.c new file mode 100644 index 0000000..2c4a390 --- /dev/null +++ b/libslang/src/curses/worm.c @@ -0,0 +1,361 @@ +/* + + @@@ @@@ @@@@@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@ + @@@ @@@ @@@@@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@@@@@ + @@@ @@@ @@@@ @@@@ @@@@ @@@@ @@@ @@@@ + @@@ @@ @@@ @@@ @@@ @@@ @@@ @@@ @@@ + @@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ @@@ + @@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ + @@@@@@@@@@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ + @@@@ @@@@ @@@@@@@@@@@@ @@@ @@@ @@@ @@@ + @@ @@ @@@@@@@@@@ @@@ @@@ @@@ @@@ + + Eric P. Scott + Caltech High Energy Physics + October, 1980 + + Hacks to turn this into a test frame for cursor movement: + Eric S. Raymond <esr@snark.thyrsus.com> + January, 1995 + + July 1995 (esr): worms is now in living color! :-) + +Options: + -f fill screen with copies of 'WORM' at start. + -l <n> set worm length + -n <n> set number of worms + -t make worms leave droppings + -T <start> <end> set trace interval + -S set single-stepping during trace interval + -N suppress cursor-movement optimization + + This program makes a good torture-test for the ncurses cursor-optimization + code. You can use -T to set the worm move interval over which movement + traces will be dumped. The program stops and waits for one character of + input at the beginning and end of the interval. +*/ + +#include <curses.h> +#include <stdlib.h> +#include <signal.h> + +#define cursor(col,row) move(row,col) + +short *ref[128]; +static chtype flavor[]={ + 'O' , '*', '#', '$', '%', '0', '@', +}; +#define MAXWORMS (sizeof(flavor)/sizeof(chtype)) +static short xinc[]={ + 1, 1, 1, 0, -1, -1, -1, 0 +}, yinc[]={ + -1, 0, 1, 1, 1, 0, -1, -1 +}; +static struct worm { + int orientation, head; + short *xpos, *ypos; +} worm[40]; + +static char *field; +static int length=16, number=3; +static chtype trail=' '; + +#ifdef TRACE +int generation, trace_start, trace_end, singlestep; +#endif /* TRACE */ +static struct options { + int nopts; + int opts[3]; +} normal[8]={ + { 3, { 7, 0, 1 } }, + { 3, { 0, 1, 2 } }, + { 3, { 1, 2, 3 } }, + { 3, { 2, 3, 4 } }, + { 3, { 3, 4, 5 } }, + { 3, { 4, 5, 6 } }, + { 3, { 5, 6, 7 } }, + { 3, { 6, 7, 0 } } +}, upper[8]={ + { 1, { 1, 0, 0 } }, + { 2, { 1, 2, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 2, { 4, 5, 0 } }, + { 1, { 5, 0, 0 } }, + { 2, { 1, 5, 0 } } +}, left[8]={ + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 2, { 2, 3, 0 } }, + { 1, { 3, 0, 0 } }, + { 2, { 3, 7, 0 } }, + { 1, { 7, 0, 0 } }, + { 2, { 7, 0, 0 } } +}, right[8]={ + { 1, { 7, 0, 0 } }, + { 2, { 3, 7, 0 } }, + { 1, { 3, 0, 0 } }, + { 2, { 3, 4, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 2, { 6, 7, 0 } } +}, lower[8]={ + { 0, { 0, 0, 0 } }, + { 2, { 0, 1, 0 } }, + { 1, { 1, 0, 0 } }, + { 2, { 1, 5, 0 } }, + { 1, { 5, 0, 0 } }, + { 2, { 5, 6, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } } +}, upleft[8]={ + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 1, { 3, 0, 0 } }, + { 2, { 1, 3, 0 } }, + { 1, { 1, 0, 0 } } +}, upright[8]={ + { 2, { 3, 5, 0 } }, + { 1, { 3, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 1, { 5, 0, 0 } } +}, lowleft[8]={ + { 3, { 7, 0, 1 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 1, { 1, 0, 0 } }, + { 2, { 1, 7, 0 } }, + { 1, { 7, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } } +}, lowright[8]={ + { 0, { 0, 0, 0 } }, + { 1, { 7, 0, 0 } }, + { 2, { 5, 7, 0 } }, + { 1, { 5, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } } +}; + +void onsig(int sig); +float ranf(void); + +int +main(int argc, char *argv[]) +{ +int x, y; +int n; +struct worm *w; +struct options *op; +int h; +short *ip; +int last, bottom; + + for (x=1;x<argc;x++) { + register char *p; + p=argv[x]; + if (*p=='-') p++; + switch (*p) { + case 'f': + field="WORM"; + break; + case 'l': + if (++x==argc) goto usage; + if ((length=atoi(argv[x]))<2||length>1024) { + fprintf(stderr,"%s: Invalid length\n",*argv); + exit(1); + } + break; + case 'n': + if (++x==argc) goto usage; + if ((number=atoi(argv[x]))<1||number>40) { + fprintf(stderr,"%s: Invalid number of worms\n",*argv); + exit(1); + } + break; + case 't': + trail='.'; + break; +#ifdef TRACE + case 'S': + singlestep = TRUE; + break; + case 'T': + trace_start = atoi(argv[++x]); + trace_end = atoi(argv[++x]); + break; + case 'N': + no_optimize = TRUE; /* declared by ncurses */ + break; +#endif /* TRACE */ + default: + usage: + fprintf(stderr, "usage: %s [-field] [-length #] [-number #] [-trail]\n",*argv); + exit(1); + break; + } + } + + signal(SIGINT, onsig); + initscr(); +#ifdef TRACE + noecho(); + cbreak(); +#endif /* TRACE */ + nonl(); + bottom = LINES-1; + last = COLS-1; + +#ifdef A_COLOR + if (has_colors()) + { + start_color(); + + init_pair(COLOR_GREEN, COLOR_GREEN, COLOR_BLACK); + init_pair(COLOR_RED, COLOR_RED, COLOR_BLACK); + init_pair(COLOR_CYAN, COLOR_CYAN, COLOR_BLACK); + init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK); + init_pair(COLOR_MAGENTA, COLOR_MAGENTA, COLOR_BLACK); + init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_BLACK); + init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK); + + flavor[0] |= COLOR_PAIR(COLOR_GREEN) | A_BOLD; + flavor[1] |= COLOR_PAIR(COLOR_RED) | A_BOLD; + flavor[2] |= COLOR_PAIR(COLOR_CYAN) | A_BOLD; + flavor[3] |= COLOR_PAIR(COLOR_WHITE) | A_BOLD; + flavor[4] |= COLOR_PAIR(COLOR_MAGENTA) | A_BOLD; + flavor[5] |= COLOR_PAIR(COLOR_BLUE) | A_BOLD; + flavor[6] |= COLOR_PAIR(COLOR_YELLOW) | A_BOLD; + } +#endif /* A_COLOR */ + + ip=(short *)malloc(LINES*COLS*sizeof (short)); + + for (n=0;n<LINES;) { + ref[n++]=ip; ip+=COLS; + } + for (ip=ref[0],n=LINES*COLS;--n>=0;) *ip++=0; + +#ifdef BADCORNER + /* if addressing the lower right corner doesn't work in your curses */ + ref[bottom][last]=1; +#endif /* BADCORNER */ + + for (n=number, w= &worm[0];--n>=0;w++) { + w->orientation=w->head=0; + if (!(ip=(short *)malloc((length+1)*sizeof (short)))) { + fprintf(stderr,"%s: out of memory\n",*argv); + exit(1); + } + w->xpos=ip; + for (x=length;--x>=0;) *ip++ = -1; + if (!(ip=(short *)malloc((length+1)*sizeof (short)))) { + fprintf(stderr,"%s: out of memory\n",*argv); + exit(1); + } + w->ypos=ip; + for (y=length;--y>=0;) *ip++ = -1; + } + if (field) { + register char *p; + p=field; + for (y=bottom;--y>=0;) { + for (x=COLS;--x>=0;) { + addch((chtype)(*p++)); + if (!*p) p=field; + } + addch('\n'); + } + } + refresh(); + napms(100); + + for (;;) { +#ifdef TRACE + if (trace_start || trace_end) { + if (generation == trace_start) { + trace(TRACE_CALLS); + getch(); + } else if (generation == trace_end) { + trace(0); + getch(); + } + + if (singlestep && generation > trace_start && generation < trace_end) + getch(); + + generation++; + } +#endif /* TRACE */ + + for (n=0,w= &worm[0];n<number;n++,w++) { + if ((x=w->xpos[h=w->head])<0) { + cursor(x=w->xpos[h]=0,y=w->ypos[h]=bottom); + addch(flavor[n % MAXWORMS]); + ref[y][x]++; + } + else y=w->ypos[h]; + if (++h==length) h=0; + if (w->xpos[w->head=h]>=0) { + register int x1, y1; + x1=w->xpos[h]; y1=w->ypos[h]; + if (--ref[y1][x1]==0) { + cursor(x1,y1); addch(trail); + } + } + op= &(x==0 ? (y==0 ? upleft : (y==bottom ? lowleft : left)) : + (x==last ? (y==0 ? upright : (y==bottom ? lowright : right)) : + (y==0 ? upper : (y==bottom ? lower : normal))))[w->orientation]; + switch (op->nopts) { + case 0: + refresh(); + endwin(); + exit(0); + case 1: + w->orientation=op->opts[0]; + break; + default: + w->orientation=op->opts[(int)(ranf()*(float)op->nopts)]; + } + cursor(x+=xinc[w->orientation], y+=yinc[w->orientation]); + + if (y < 0 ) y = 0; + addch(flavor[n % MAXWORMS]); + ref[w->ypos[h]=y][w->xpos[h]=x]++; + } + napms(100); + refresh(); + } +} + +void +onsig(int sig) +{ + standend(); + refresh(); + endwin(); + exit(sig); +} + +float +ranf(void) +{ +float rv; +long r = rand(); + + r &= 077777; + rv =((float)r/32767.); + return rv; +} |