xref: /original-bsd/games/worm/worm.c (revision 3708840b)
1 static char	*sccsid = "@(#)worm.c	4.3 (Berkeley) 05/19/83";
2 
3 /*
4  * Worm.  Written by Michael Toy
5  * UCSC
6  */
7 
8 #include <ctype.h>
9 #include <curses.h>
10 #include <signal.h>
11 
12 #define newlink() (struct body *) malloc(sizeof (struct body));
13 #define HEAD '@'
14 #define BODY 'o'
15 #define LENGTH 7
16 #define RUNLEN 8
17 #define when break;case
18 #define otherwise break;default
19 #define CNTRL(p) ('p'-'A'+1)
20 #ifndef attron
21 # define	baudrate()	_tty.sg_ospeed
22 #endif
23 
24 WINDOW *tv;
25 WINDOW *stw;
26 struct body {
27 	int x;
28 	int y;
29 	struct body *prev;
30 	struct body *next;
31 } *head, *tail, goody;
32 int growing = 0;
33 int running = 0;
34 int slow = 0;
35 int score = 0;
36 int start_len = LENGTH;
37 char lastch;
38 char outbuf[BUFSIZ];
39 
40 main(argc, argv)
41 char **argv;
42 {
43 	int leave(), wake(), suspend();
44 	char ch;
45 
46 	if (argc == 2)
47 		start_len = atoi(argv[1]);
48 	if ((start_len <= 0) || (start_len > 500))
49 		start_len = LENGTH;
50 	setbuf(stdout, outbuf);
51 	srand(getpid());
52 	signal(SIGALRM, wake);
53 	signal(SIGINT, leave);
54 	signal(SIGQUIT, leave);
55 #ifdef SIGTSTP
56 	signal(SIGTSTP, suspend);	/* process control signal */
57 #endif
58 	initscr();
59 	crmode();
60 	noecho();
61 	slow = (baudrate() <= B1200);
62 	clear();
63 	stw = newwin(1, COLS-1, 0, 0);
64 	tv = newwin(LINES-1, COLS-1, 1, 0);
65 	box(tv, '*', '*');
66 	scrollok(tv, FALSE);
67 	scrollok(stw, FALSE);
68 	wmove(stw, 0, 0);
69 	wprintw(stw, " Worm");
70 	refresh();
71 	wrefresh(stw);
72 	wrefresh(tv);
73 	life();			/* Create the worm */
74 	prize();		/* Put up a goal */
75 	while(1)
76 	{
77 		if (running)
78 		{
79 			running--;
80 			process(lastch);
81 		}
82 		else
83 		{
84 		    fflush(stdout);
85 		    if (read(0, &ch, 1) >= 0)
86 			process(ch);
87 		}
88 	}
89 }
90 
91 life()
92 {
93 	register struct body *bp, *np;
94 	register int i;
95 
96 	head = newlink();
97 	head->x = start_len+2;
98 	head->y = 12;
99 	head->next = NULL;
100 	display(head, HEAD);
101 	for (i = 0, bp = head; i < start_len; i++, bp = np) {
102 		np = newlink();
103 		np->next = bp;
104 		bp->prev = np;
105 		np->x = bp->x - 1;
106 		np->y = bp->y;
107 		display(np, BODY);
108 	}
109 	tail = np;
110 	tail->prev = NULL;
111 }
112 
113 display(pos, chr)
114 struct body *pos;
115 char chr;
116 {
117 	wmove(tv, pos->y, pos->x);
118 	waddch(tv, chr);
119 }
120 
121 leave()
122 {
123 	endwin();
124 	exit(0);
125 }
126 
127 wake()
128 {
129 	signal(SIGALRM, wake);
130 	fflush(stdout);
131 	process(lastch);
132 }
133 
134 rnd(range)
135 {
136 	return abs((rand()>>5)+(rand()>>5)) % range;
137 }
138 
139 newpos(bp)
140 struct body * bp;
141 {
142 	do {
143 		bp->y = rnd(LINES-3)+ 2;
144 		bp->x = rnd(COLS-3) + 1;
145 		wmove(tv, bp->y, bp->x);
146 	} while(winch(tv) != ' ');
147 }
148 
149 prize()
150 {
151 	int value;
152 
153 	value = rnd(9) + 1;
154 	newpos(&goody);
155 	waddch(tv, value+'0');
156 	wrefresh(tv);
157 }
158 
159 process(ch)
160 char ch;
161 {
162 	register int x,y;
163 	struct body *nh;
164 
165 	alarm(0);
166 	x = head->x;
167 	y = head->y;
168 	switch(ch)
169 	{
170 		when 'h': x--;
171 		when 'j': y++;
172 		when 'k': y--;
173 		when 'l': x++;
174 		when 'H': x--; running = RUNLEN; ch = tolower(ch);
175 		when 'J': y++; running = RUNLEN/2; ch = tolower(ch);
176 		when 'K': y--; running = RUNLEN/2; ch = tolower(ch);
177 		when 'L': x++; running = RUNLEN; ch = tolower(ch);
178 		when '\f': setup(); return;
179 		when CNTRL(Z): suspend(); return;
180 		when CNTRL(C): crash(); return;
181 		when CNTRL(D): crash(); return;
182 		otherwise: if (! running) alarm(1);
183 			   return;
184 	}
185 	lastch = ch;
186 	if (growing == 0)
187 	{
188 		display(tail, ' ');
189 		tail->next->prev = NULL;
190 		nh = tail->next;
191 		free(tail);
192 		tail = nh;
193 	}
194 	else growing--;
195 	display(head, BODY);
196 	wmove(tv, y, x);
197 	if (isdigit(ch = winch(tv)))
198 	{
199 		growing += ch-'0';
200 		prize();
201 		score += growing;
202 		running = 0;
203 		wmove(stw, 0, 68);
204 		wprintw(stw, "Score: %3d", score);
205 		wrefresh(stw);
206 	}
207 	else if(ch != ' ') crash();
208 	nh = newlink();
209 	nh->next = NULL;
210 	nh->prev = head;
211 	head->next = nh;
212 	nh->y = y;
213 	nh->x = x;
214 	display(nh, HEAD);
215 	head = nh;
216 	if (!(slow && running))
217 		wrefresh(tv);
218 	if (!running)
219 		alarm(1);
220 }
221 
222 crash()
223 {
224 	sleep(2);
225 	clear();
226 	move(23, 0);
227 	refresh();
228 	printf("Well you ran into something and the game is over.\n");
229 	printf("Your final score was %d\n", score);
230 	leave();
231 }
232 
233 suspend()
234 {
235 	char *sh;
236 
237 	move(LINES-1, 0);
238 	refresh();
239 	endwin();
240 	fflush(stdout);
241 #ifdef SIGTSTP
242 	kill(getpid(), SIGTSTP);
243 	signal(SIGTSTP, suspend);
244 #else
245 	sh = getenv("SHELL");
246 	if (sh == NULL)
247 		sh = "/bin/sh";
248 	system(sh);
249 #endif
250 	crmode();
251 	noecho();
252 	setup();
253 }
254 
255 setup()
256 {
257 	clear();
258 	refresh();
259 	touchwin(stw);
260 	wrefresh(stw);
261 	touchwin(tv);
262 	wrefresh(tv);
263 	alarm(1);
264 }
265