ncursesw-morphos/test/worm.c

428 lines
9.3 KiB
C
Raw Normal View History

1997-05-15 12:00:00 +08:00
/*
@@@ @@@ @@@@@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@
@@@ @@@ @@@@@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@@@@@
@@@ @@@ @@@@ @@@@ @@@@ @@@@ @@@ @@@@
@@@ @@ @@@ @@@ @@@ @@@ @@@ @@@ @@@
@@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ @@@
@@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@
@@@@@@@@@@@@ @@@@ @@@@ @@@ @@@ @@@ @@@
@@@@ @@@@ @@@@@@@@@@@@ @@@ @@@ @@@ @@@
@@ @@ @@@@@@@@@@ @@@ @@@ @@@ @@@
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.
2002-10-13 11:35:53 +08:00
$Id: worm.c,v 1.37 2002/06/29 23:32:18 tom Exp $
1997-05-15 12:00:00 +08:00
*/
#include <test.priv.h>
1999-10-24 12:32:42 +08:00
static chtype flavor[] =
{
'O', '*', '#', '$', '%', '0', '@',
1997-05-15 12:00:00 +08:00
};
1999-10-24 12:32:42 +08:00
static const short xinc[] =
{
1, 1, 1, 0, -1, -1, -1, 0
}, yinc[] =
{
-1, 0, 1, 1, 1, 0, -1, -1
1997-05-15 12:00:00 +08:00
};
static struct worm {
int orientation, head;
short *xpos, *ypos;
} worm[40];
static const char *field;
1999-10-24 12:32:42 +08:00
static int length = 16, number = 3;
static chtype trail = ' ';
1997-05-15 12:00:00 +08:00
#ifdef TRACE
int generation, trace_start, trace_end, singlestep;
#endif /* TRACE */
1999-10-24 12:32:42 +08:00
/* *INDENT-OFF* */
1997-05-15 12:00:00 +08:00
static const 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 } }
};
1999-10-24 12:32:42 +08:00
/* *INDENT-ON* */
static void
cleanup(void)
{
standend();
refresh();
curs_set(1);
endwin();
}
static RETSIGTYPE
onsig(int sig GCC_UNUSED)
{
cleanup();
2002-10-13 11:35:53 +08:00
ExitProgram(EXIT_FAILURE);
1999-10-24 12:32:42 +08:00
}
1997-05-15 12:00:00 +08:00
1999-10-24 12:32:42 +08:00
static float
ranf(void)
{
long r = (rand() & 077777);
return ((float) r / 32768.);
}
1997-05-15 12:00:00 +08:00
int
main(int argc, char *argv[])
{
1999-10-24 12:32:42 +08:00
short **ref;
int x, y;
int n;
struct worm *w;
const struct options *op;
int h;
short *ip;
int last, bottom;
2002-10-13 11:35:53 +08:00
setlocale(LC_ALL, "");
1999-10-24 12:32:42 +08:00
for (x = 1; x < argc; x++) {
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);
2002-10-13 11:35:53 +08:00
ExitProgram(EXIT_FAILURE);
1999-10-24 12:32:42 +08:00
}
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);
2002-10-13 11:35:53 +08:00
ExitProgram(EXIT_FAILURE);
1999-10-24 12:32:42 +08:00
}
break;
case 't':
trail = '.';
break;
1997-05-15 12:00:00 +08:00
#ifdef TRACE
1999-10-24 12:32:42 +08:00
case 'S':
singlestep = TRUE;
break;
case 'T':
trace_start = atoi(argv[++x]);
trace_end = atoi(argv[++x]);
break;
case 'N':
_nc_optimize_enable ^= OPTIMIZE_ALL; /* declared by ncurses */
break;
1997-05-15 12:00:00 +08:00
#endif /* TRACE */
1999-10-24 12:32:42 +08:00
default:
usage:
fprintf(stderr,
2002-10-13 11:35:53 +08:00
"usage: %s [-field] [-length #] [-number #] [-trail]\n", *argv);
ExitProgram(EXIT_FAILURE);
1999-10-24 12:32:42 +08:00
}
1997-05-15 12:00:00 +08:00
}
signal(SIGINT, onsig);
initscr();
noecho();
cbreak();
nonl();
curs_set(0);
1999-10-24 12:32:42 +08:00
bottom = LINES - 1;
last = COLS - 1;
1997-05-15 12:00:00 +08:00
#ifdef A_COLOR
1999-10-24 12:32:42 +08:00
if (has_colors()) {
1997-05-15 12:00:00 +08:00
int bg = COLOR_BLACK;
start_color();
2000-10-21 12:42:11 +08:00
#if HAVE_USE_DEFAULT_COLORS
1997-05-15 12:00:00 +08:00
if (use_default_colors() == OK)
bg = -1;
#endif
1999-10-24 12:32:42 +08:00
#define SET_COLOR(num, fg) \
init_pair(num+1, fg, bg); \
flavor[num] |= COLOR_PAIR(num+1) | A_BOLD
SET_COLOR(0, COLOR_GREEN);
SET_COLOR(1, COLOR_RED);
SET_COLOR(2, COLOR_CYAN);
SET_COLOR(3, COLOR_WHITE);
SET_COLOR(4, COLOR_MAGENTA);
SET_COLOR(5, COLOR_BLUE);
SET_COLOR(6, COLOR_YELLOW);
1997-05-15 12:00:00 +08:00
}
#endif /* A_COLOR */
2000-07-09 10:46:08 +08:00
ref = typeMalloc(short *, LINES);
1999-10-24 12:32:42 +08:00
for (y = 0; y < LINES; y++) {
2000-07-09 10:46:08 +08:00
ref[y] = typeMalloc(short, COLS);
1999-10-24 12:32:42 +08:00
for (x = 0; x < COLS; x++) {
ref[y][x] = 0;
}
1997-05-15 12:00:00 +08:00
}
#ifdef BADCORNER
/* if addressing the lower right corner doesn't work in your curses */
1999-10-24 12:32:42 +08:00
ref[bottom][last] = 1;
1997-05-15 12:00:00 +08:00
#endif /* BADCORNER */
1999-10-24 12:32:42 +08:00
for (n = number, w = &worm[0]; --n >= 0; w++) {
w->orientation = w->head = 0;
2000-07-09 10:46:08 +08:00
if (!(ip = typeMalloc(short, (length + 1)))) {
1999-10-24 12:32:42 +08:00
fprintf(stderr, "%s: out of memory\n", *argv);
2002-10-13 11:35:53 +08:00
ExitProgram(EXIT_FAILURE);
1999-10-24 12:32:42 +08:00
}
w->xpos = ip;
for (x = length; --x >= 0;)
*ip++ = -1;
2000-07-09 10:46:08 +08:00
if (!(ip = typeMalloc(short, (length + 1)))) {
1999-10-24 12:32:42 +08:00
fprintf(stderr, "%s: out of memory\n", *argv);
2002-10-13 11:35:53 +08:00
ExitProgram(EXIT_FAILURE);
1999-10-24 12:32:42 +08:00
}
w->ypos = ip;
for (y = length; --y >= 0;)
*ip++ = -1;
1997-05-15 12:00:00 +08:00
}
if (field) {
1999-10-24 12:32:42 +08:00
const char *p;
p = field;
for (y = bottom; --y >= 0;) {
for (x = COLS; --x >= 0;) {
addch((chtype) (*p++));
if (!*p)
p = field;
}
}
1997-05-15 12:00:00 +08:00
}
1999-10-24 12:32:42 +08:00
napms(10);
1997-05-15 12:00:00 +08:00
refresh();
1999-10-24 12:32:42 +08:00
#ifndef TRACE
nodelay(stdscr, TRUE);
#endif
1997-05-15 12:00:00 +08:00
for (;;) {
#ifdef TRACE
1999-10-24 12:32:42 +08:00
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++;
}
#else
2000-07-09 10:46:08 +08:00
int ch;
1999-10-24 12:32:42 +08:00
if ((ch = getch()) > 0) {
#ifdef KEY_RESIZE
if (ch == KEY_RESIZE) {
if (last != COLS - 1) {
for (y = 0; y <= bottom; y++) {
ref[y] = typeRealloc(short, COLS, ref[y]);
for (x = last + 1; x < COLS; x++)
ref[y][x] = 0;
1997-05-15 12:00:00 +08:00
}
1999-10-24 12:32:42 +08:00
last = COLS - 1;
1997-05-15 12:00:00 +08:00
}
1999-10-24 12:32:42 +08:00
if (bottom != LINES - 1) {
2000-07-09 10:46:08 +08:00
for (y = LINES; y <= bottom; y++)
1999-10-24 12:32:42 +08:00
free(ref[y]);
2000-07-09 10:46:08 +08:00
ref = typeRealloc(short *, LINES, ref);
1999-10-24 12:32:42 +08:00
for (y = bottom + 1; y < LINES; y++) {
2000-07-09 10:46:08 +08:00
ref[y] = typeMalloc(short, COLS);
1999-10-24 12:32:42 +08:00
for (x = 0; x < COLS; x++)
ref[y][x] = 0;
1997-05-15 12:00:00 +08:00
}
1999-10-24 12:32:42 +08:00
bottom = LINES - 1;
1997-05-15 12:00:00 +08:00
}
1999-10-24 12:32:42 +08:00
}
#endif
/*
* Make it simple to put this into single-step mode, or resume
* normal operation -TD
*/
if (ch == 'q') {
cleanup();
2002-10-13 11:35:53 +08:00
ExitProgram(EXIT_SUCCESS);
1999-10-24 12:32:42 +08:00
} else if (ch == 's') {
nodelay(stdscr, FALSE);
} else if (ch == ' ') {
nodelay(stdscr, TRUE);
}
}
#endif /* TRACE */
1997-05-15 12:00:00 +08:00
1999-10-24 12:32:42 +08:00
for (n = 0, w = &worm[0]; n < number; n++, w++) {
if ((x = w->xpos[h = w->head]) < 0) {
move(y = w->ypos[h] = bottom, x = w->xpos[h] = 0);
2002-10-13 11:35:53 +08:00
addch(flavor[n % SIZEOF(flavor)]);
1999-10-24 12:32:42 +08:00
ref[y][x]++;
} else {
y = w->ypos[h];
}
if (x > last)
x = last;
if (y > bottom)
y = bottom;
if (++h == length)
h = 0;
if (w->xpos[w->head = h] >= 0) {
int x1, y1;
x1 = w->xpos[h];
y1 = w->ypos[h];
if (y1 < LINES
&& x1 < COLS
&& --ref[y1][x1] == 0) {
move(y1, x1);
addch(trail);
}
}
op = &(x == 0 ? (y == 0 ? upleft : (y == bottom ? lowleft :
2002-10-13 11:35:53 +08:00
left)) :
(x == last ? (y == 0 ? upright : (y == bottom ? lowright :
right)) :
1999-10-24 12:32:42 +08:00
(y == 0 ? upper : (y == bottom ? lower : normal))))[w->orientation];
switch (op->nopts) {
case 0:
cleanup();
2002-10-13 11:35:53 +08:00
ExitProgram(EXIT_SUCCESS);
1999-10-24 12:32:42 +08:00
case 1:
w->orientation = op->opts[0];
break;
default:
w->orientation = op->opts[(int) (ranf() * (float) op->nopts)];
}
move(y += yinc[w->orientation], x += xinc[w->orientation]);
if (y < 0)
y = 0;
2002-10-13 11:35:53 +08:00
addch(flavor[n % SIZEOF(flavor)]);
1999-10-24 12:32:42 +08:00
ref[w->ypos[h] = y][w->xpos[h] = x]++;
}
napms(10);
1997-05-15 12:00:00 +08:00
refresh();
1999-10-24 12:32:42 +08:00
}
1997-05-15 12:00:00 +08:00
}