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