xref: /dragonfly/games/snake/snake/snake.c (revision 6e285212)
1 /*
2  * Copyright (c) 1980, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#) Copyright (c) 1980, 1993 The Regents of the University of California.  All rights reserved.
34  * @(#)snake.c	8.2 (Berkeley) 1/7/94
35  * $FreeBSD: src/games/snake/snake/snake.c,v 1.11.2.1 2000/08/17 06:21:44 jhb Exp $
36  * $DragonFly: src/games/snake/snake/snake.c,v 1.2 2003/06/17 04:25:25 dillon Exp $
37  */
38 
39 /*
40  * snake - crt hack game.
41  *
42  * You move around the screen with arrow keys trying to pick up money
43  * without getting eaten by the snake.  hjkl work as in vi in place of
44  * arrow keys.  You can leave at the exit any time.
45  *
46  * compile as follows:
47  *	cc -O snake.c move.c -o snake -lm -ltermlib
48  */
49 
50 #include <sys/param.h>
51 
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <pwd.h>
55 #include <time.h>
56 #include <stdlib.h>
57 #include <unistd.h>
58 
59 #include "snake.h"
60 #include "pathnames.h"
61 
62 #define PENALTY  10	/* % penalty for invoking spacewarp	*/
63 
64 #define EOT	'\004'
65 #define LF	'\n'
66 #define DEL	'\177'
67 
68 #define ME		'I'
69 #define SNAKEHEAD	'S'
70 #define SNAKETAIL	's'
71 #define TREASURE	'$'
72 #define GOAL		'#'
73 
74 #define BSIZE	80
75 
76 struct point you;
77 struct point money;
78 struct point finish;
79 struct point snake[6];
80 
81 int loot, penalty;
82 int long tl, tm=0L;
83 int moves;
84 char stri[BSIZE];
85 char *p;
86 char ch, savec;
87 char *kl, *kr, *ku, *kd;
88 int fast=1;
89 int repeat=1;
90 long tv;
91 char *tn;
92 
93 int rawscores;
94 FILE *logfile;
95 
96 main(argc,argv)
97 int argc;
98 char **argv;
99 {
100 	extern char *optarg;
101 	extern int optind;
102 	int ch, i;
103 	void stop();
104 
105 	rawscores = open(_PATH_RAWSCORES, O_RDWR|O_CREAT, 0664);
106 	logfile = fopen(_PATH_LOGFILE, "a");
107 
108 	/* revoke privs */
109 	setgid(getgid());
110 
111 	srandomdev();
112 
113 	while ((ch = getopt(argc, argv, "l:w:")) != -1)
114 		switch((char)ch) {
115 #ifdef notdef
116 		case 'd':
117 			tv = atol(optarg);
118 			break;
119 #endif
120 		case 'w':	/* width */
121 			ccnt = atoi(optarg);
122 			break;
123 		case 'l':	/* length */
124 			lcnt = atoi(optarg);
125 			break;
126 		case '?':
127 		default:
128 			fputs("usage: snake [-d seed] [-w width] [-l length]\n", stderr);
129 			exit(1);
130 		}
131 
132 	penalty = loot = 0;
133 	getcap();
134 
135 	i = MIN(lcnt, ccnt);
136 	if (i < 4) {
137 		cook();
138 		pr("snake: screen too small for a fair game.\n");
139 		exit(1);
140 	}
141 
142 	/*
143 	 * chunk is the amount of money the user gets for each $.
144 	 * The formula below tries to be fair for various screen sizes.
145 	 * We only pay attention to the smaller of the 2 edges, since
146 	 * that seems to be the bottleneck.
147 	 * This formula is a hyperbola which includes the following points:
148 	 *	(24, $25)	(original scoring algorithm)
149 	 *	(12, $40)	(experimentally derived by the "feel")
150 	 *	(48, $15)	(a guess)
151 	 * This will give a 4x4 screen $99/shot.  We don't allow anything
152 	 * smaller than 4x4 because there is a 3x3 game where you can win
153 	 * an infinite amount of money.
154 	 */
155 	if (i < 12) i = 12;	/* otherwise it isn't fair */
156 	/*
157 	 * Compensate for border.  This really changes the game since
158 	 * the screen is two squares smaller but we want the default
159 	 * to be $25, and the high scores on small screens were a bit
160 	 * much anyway.
161 	 */
162 	i += 2;
163 	chunk = (675.0 / (i+6)) + 2.5;	/* min screen edge */
164 
165 	signal (SIGINT, stop);
166 	putpad(TI); /*	String to begin programs that use cm */
167 	putpad(KS); /*	Put terminal in keypad transmit mode */
168 	putpad(VI); /*  Hide cursor */
169 
170 	snrand(&finish);
171 	snrand(&you);
172 	snrand(&money);
173 	snrand(&snake[0]);
174 
175 	if ((orig.sg_ospeed < B9600) ||
176 	    ((! CM) && (! TA))) fast=0;
177 	for(i=1;i<6;i++)
178 		chase (&snake[i], &snake[i-1]);
179 	setup();
180 	mainloop();
181 }
182 
183 /* Main command loop */
184 mainloop()
185 {
186 	int j, k;
187 
188 	for (;;) {
189 		int c,lastc,match;
190 
191 		move(&you);
192 		fflush(stdout);
193 		if (((c = getchar() & 0177) <= '9') && (c >= '0')) {
194 			ungetc(c,stdin);
195 			j = scanf("%d",&repeat);
196 			c = getchar() & 0177;
197 		} else {
198 			if (c != '.') repeat = 1;
199 		}
200 		if (c == '.') {
201 			c = lastc;
202 		}
203 		if ((Klength > 0) &&
204 		    (c == *KL || c == *KR || c == *KU || c == *KD)) {
205 			savec = c;
206 			match = 0;
207 			kl = KL;
208 			kr = KR;
209 			ku = KU;
210 			kd = KD;
211 			for (j=Klength;j>0;j--){
212 				if (match != 1) {
213 				match = 0;
214 					if (*kl++ == c) {
215 						ch = 'h';
216 						match++;
217 					}
218 					if (*kr++ == c) {
219 						ch = 'l';
220 						match++;
221 					}
222 					if (*ku++ == c) {
223 						ch = 'k';
224 						match++;
225 					}
226 					if (*kd++ == c) {
227 						ch = 'j';
228 						match++;
229 					}
230 					if (match == 0) {
231 						ungetc(c,stdin);
232 						ch = savec;
233 		/* Oops!
234 		 * This works if we figure it out on second character.
235 		 */
236 						break;
237 					}
238 				}
239 				savec = c;
240 				if(j != 1) c = getchar() & 0177;
241 			}
242 			c = ch;
243 		}
244 		if (!fast) flushi();
245 		lastc = c;
246 		switch (c){
247 		case CTRL('z'):
248 			suspend();
249 			continue;
250 		case EOT:
251 		case 'x':
252 		case 0177:	/* del or end of file */
253 			ll();
254 			length(moves);
255 			logit("quit");
256 			done();
257 		case CTRL('l'):
258 			setup();
259 			winnings(cashvalue);
260 			continue;
261 		case 'p':
262 		case 'd':
263 			snap();
264 			continue;
265 		case 'w':
266 			spacewarp(0);
267 			continue;
268 		case 'A':
269 			repeat = you.col;
270 			c = 'h';
271 			break;
272 		case 'H':
273 		case 'S':
274 			repeat = you.col - money.col;
275 			c = 'h';
276 			break;
277 		case 'T':
278 			repeat = you.line;
279 			c = 'k';
280 			break;
281 		case 'K':
282 		case 'E':
283 			repeat = you.line - money.line;
284 			c = 'k';
285 			break;
286 		case 'P':
287 			repeat = ccnt - 1 - you.col;
288 			c = 'l';
289 			break;
290 		case 'L':
291 		case 'F':
292 			repeat = money.col - you.col;
293 			c = 'l';
294 			break;
295 		case 'B':
296 			repeat = lcnt - 1 - you.line;
297 			c = 'j';
298 			break;
299 		case 'J':
300 		case 'C':
301 			repeat = money.line - you.line;
302 			c = 'j';
303 			break;
304 		}
305 		for(k=1;k<=repeat;k++){
306 			moves++;
307 			switch(c) {
308 			case 's':
309 			case 'h':
310 			case '\b':
311 				if (you.col >0) {
312 					if((fast)||(k == 1))
313 						pchar(&you,' ');
314 					you.col--;
315 					if((fast) || (k == repeat) ||
316 					   (you.col == 0))
317 						pchar(&you,ME);
318 				}
319 				break;
320 			case 'f':
321 			case 'l':
322 			case ' ':
323 				if (you.col < ccnt-1) {
324 					if((fast)||(k == 1))
325 						pchar(&you,' ');
326 					you.col++;
327 					if((fast) || (k == repeat) ||
328 					   (you.col == ccnt-1))
329 						pchar(&you,ME);
330 				}
331 				break;
332 			case CTRL('p'):
333 			case 'e':
334 			case 'k':
335 			case 'i':
336 				if (you.line > 0) {
337 					if((fast)||(k == 1))
338 						pchar(&you,' ');
339 					you.line--;
340 					if((fast) || (k == repeat) ||
341 					  (you.line == 0))
342 						pchar(&you,ME);
343 				}
344 				break;
345 			case CTRL('n'):
346 			case 'c':
347 			case 'j':
348 			case LF:
349 			case 'm':
350 				if (you.line+1 < lcnt) {
351 					if((fast)||(k == 1))
352 						pchar(&you,' ');
353 					you.line++;
354 					if((fast) || (k == repeat) ||
355 					  (you.line == lcnt-1))
356 						pchar(&you,ME);
357 				}
358 				break;
359 			}
360 
361 			if (same(&you,&money))
362 			{
363 				loot += 25;
364 				if(k < repeat)
365 					pchar(&you,' ');
366 				do {
367 					snrand(&money);
368 				} while (money.col == finish.col && money.line == finish.line ||
369 					 money.col < 5 && money.line == 0 ||
370 					 money.col == you.col && money.line == you.line);
371 				pchar(&money,TREASURE);
372 				winnings(cashvalue);
373 				continue;
374 			}
375 			if (same(&you,&finish))
376 			{
377 				win(&finish);
378 				ll();
379 				cook();
380 				pr("You have won with $%d.\n",cashvalue);
381 				fflush(stdout);
382 				logit("won");
383 				post(cashvalue,1);
384 				length(moves);
385 				done();
386 			}
387 			if (pushsnake())break;
388 		}
389 		fflush(stdout);
390 	}
391 }
392 
393 setup(){	/*
394 		 * setup the board
395 		 */
396 	int i;
397 
398 	clear();
399 	pchar(&you,ME);
400 	pchar(&finish,GOAL);
401 	pchar(&money,TREASURE);
402 	for(i=1; i<6; i++) {
403 		pchar(&snake[i],SNAKETAIL);
404 	}
405 	pchar(&snake[0], SNAKEHEAD);
406 	drawbox();
407 	fflush(stdout);
408 }
409 
410 drawbox()
411 {
412 	int i;
413 	struct point p;
414 
415 	p.line = -1;
416 	for (i= 0; i<ccnt; i++) {
417 		p.col = i;
418 		pchar(&p, '-');
419 	}
420 	p.col = ccnt;
421 	for (i= -1; i<=lcnt; i++) {
422 		p.line = i;
423 		pchar(&p, '|');
424 	}
425 	p.col = -1;
426 	for (i= -1; i<=lcnt; i++) {
427 		p.line = i;
428 		pchar(&p, '|');
429 	}
430 	p.line = lcnt;
431 	for (i= 0; i<ccnt; i++) {
432 		p.col = i;
433 		pchar(&p, '-');
434 	}
435 }
436 
437 snrand(sp)
438 struct point *sp;
439 {
440 	struct point p;
441 	int i;
442 
443 	for (;;) {
444 		p.col = random() % ccnt;
445 		p.line = random() % lcnt;
446 
447 		/* make sure it's not on top of something else */
448 		if (p.line == 0 && p.col < 5)
449 			continue;
450 		if (same(&p, &you))
451 			continue;
452 		if (same(&p, &money))
453 			continue;
454 		if (same(&p, &finish))
455 			continue;
456 		for (i = 0; i < 5; i++)
457 			if (same(&p, &snake[i]))
458 				break;
459 		if (i < 5)
460 			continue;
461 		break;
462 	}
463 	*sp = p;
464 }
465 
466 post(iscore, flag)
467 int	iscore, flag;
468 {
469 	short	score = iscore;
470 	short	uid;
471 	short	oldbest=0;
472 	short	allbwho=0, allbscore=0;
473 	struct	passwd *p;
474 
475 	/*
476 	 * Neg uid, 0, and 1 cannot have scores recorded.
477 	 */
478 	if ((uid = getuid()) <= 1) {
479 		pr("No saved scores for uid %d.\n", uid);
480 		return(1);
481 	}
482 	if (rawscores == -1) {
483 		pr("No score file %s: %s.\n", _PATH_RAWSCORES,
484 		    strerror(errno));
485 		return(1);
486 	}
487 	/* Figure out what happened in the past */
488 	read(rawscores, &allbscore, sizeof(short));
489 	read(rawscores, &allbwho, sizeof(short));
490 	lseek(rawscores, ((off_t)uid)*sizeof(short), 0);
491 	read(rawscores, &oldbest, sizeof(short));
492 	if (!flag)
493 		return (score > oldbest ? 1 : 0);
494 
495 	/* Update this jokers best */
496 	if (score > oldbest) {
497 		lseek(rawscores, ((off_t)uid)*sizeof(short), 0);
498 		write(rawscores, &score, sizeof(short));
499 		pr("You bettered your previous best of $%d\n", oldbest);
500 	} else
501 		pr("Your best to date is $%d\n", oldbest);
502 
503 	/* See if we have a new champ */
504 	p = getpwuid(allbwho);
505 	if (p == NULL || score > allbscore) {
506 		lseek(rawscores, (off_t)0, 0);
507 		write(rawscores, &score, sizeof(short));
508 		write(rawscores, &uid, sizeof(short));
509 		if (allbwho)
510 			pr("You beat %s's old record of $%d!\n",
511 			    p->pw_name, allbscore);
512 		else
513 			pr("You set a new record!\n");
514 	} else
515 		pr("The highest is %s with $%d\n", p->pw_name, allbscore);
516 	close(rawscores);
517 	return (1);
518 }
519 
520 /*
521  * Flush typeahead to keep from buffering a bunch of chars and then
522  * overshooting.  This loses horribly at 9600 baud, but works nicely
523  * if the terminal gets behind.
524  */
525 flushi()
526 {
527 	stty(0, &new);
528 }
529 int mx [8] = {
530 	0, 1, 1, 1, 0,-1,-1,-1};
531 int my [8] = {
532 	-1,-1, 0, 1, 1, 1, 0,-1};
533 float absv[8]= {
534 	1, 1.4, 1, 1.4, 1, 1.4, 1, 1.4
535 };
536 int oldw=0;
537 chase (np, sp)
538 struct point *sp, *np;
539 {
540 	/* this algorithm has bugs; otherwise the
541 	   snake would get too good */
542 	struct point d;
543 	int w, i, wt[8];
544 	double v1, v2, vp, max;
545 	point(&d,you.col-sp->col,you.line-sp->line);
546 	v1 = sqrt( (double) (d.col*d.col + d.line*d.line) );
547 	w=0;
548 	max=0;
549 	for(i=0; i<8; i++)
550 	{
551 		vp = d.col*mx[i] + d.line*my[i];
552 		v2 = absv[i];
553 		if (v1>0)
554 			vp = ((double)vp)/(v1*v2);
555 		else vp=1.0;
556 		if (vp>max)
557 		{
558 			max=vp;
559 			w=i;
560 		}
561 	}
562 	for(i=0; i<8; i++)
563 	{
564 		point(&d,sp->col+mx[i],sp->line+my[i]);
565 		wt[i]=0;
566 		if (d.col<0 || d.col>=ccnt || d.line<0 || d.line>=lcnt)
567 			continue;
568 		/*
569 		 * Change to allow snake to eat you if you're on the money,
570 		 * otherwise, you can just crouch there until the snake goes
571 		 * away.  Not positive it's right.
572 		 *
573 		 * if (d.line == 0 && d.col < 5) continue;
574 		 */
575 		if (same(&d,&money)) continue;
576 		if (same(&d,&finish)) continue;
577 		wt[i]= i==w ? loot/10 : 1;
578 		if (i==oldw) wt [i] += loot/20;
579 	}
580 	for(w=i=0; i<8; i++)
581 		w+= wt[i];
582 	vp = random() % w;
583 	for(i=0; i<8; i++)
584 		if (vp <wt[i])
585 			break;
586 		else
587 			vp -= wt[i];
588 	if (i==8) {
589 		pr("failure\n");
590 		i=0;
591 		while (wt[i]==0) i++;
592 	}
593 	oldw=w=i;
594 	point(np,sp->col+mx[w],sp->line+my[w]);
595 }
596 
597 spacewarp(w)
598 int w;{
599 	struct point p;
600 	int j;
601 	char *str;
602 
603 	snrand(&you);
604 	point(&p,COLUMNS/2 - 8,LINES/2 - 1);
605 	if (p.col < 0)
606 		p.col = 0;
607 	if (p.line < 0)
608 		p.line = 0;
609 	if (w) {
610 		str = "BONUS!!!";
611 		loot = loot - penalty;
612 		penalty = 0;
613 	} else {
614 		str = "SPACE WARP!!!";
615 		penalty += loot/PENALTY;
616 	}
617 	for(j=0;j<3;j++){
618 		clear();
619 		delay(5);
620 		apr(&p,str);
621 		delay(10);
622 	}
623 	setup();
624 	winnings(cashvalue);
625 }
626 
627 snap()
628 {
629 	struct point p;
630 
631 	if(you.line < 3){
632 		pchar(point(&p,you.col,0),'-');
633 	}
634 	if(you.line > lcnt-4){
635 		pchar(point(&p,you.col,lcnt-1),'_');
636 	}
637 	if(you.col < 10){
638 		pchar(point(&p,0,you.line),'(');
639 	}
640 	if(you.col > ccnt-10){
641 		pchar(point(&p,ccnt-1,you.line),')');
642 	}
643 	if (! stretch(&money)) if (! stretch(&finish)) delay(10);
644 	if(you.line < 3){
645 		point(&p,you.col,0);
646 		chk(&p);
647 	}
648 	if(you.line > lcnt-4){
649 		point(&p,you.col,lcnt-1);
650 		chk(&p);
651 	}
652 	if(you.col < 10){
653 		point(&p,0,you.line);
654 		chk(&p);
655 	}
656 	if(you.col > ccnt-10){
657 		point(&p,ccnt-1,you.line);
658 		chk(&p);
659 	}
660 	fflush(stdout);
661 }
662 
663 stretch(ps)
664 struct point *ps;{
665 	struct point p;
666 
667 	point(&p,you.col,you.line);
668 	if(abs(ps->col-you.col) < 6){
669 		if(you.line < ps->line){
670 			for (p.line = you.line+1;p.line <= ps->line;p.line++)
671 				pchar(&p,'v');
672 			delay(10);
673 			for (;p.line > you.line;p.line--)
674 				chk(&p);
675 		} else {
676 			for (p.line = you.line-1;p.line >= ps->line;p.line--)
677 				pchar(&p,'^');
678 			delay(10);
679 			for (;p.line < you.line;p.line++)
680 				chk(&p);
681 		}
682 		return(1);
683 	} else if(abs(ps->line-you.line) < 3){
684 		p.line = you.line;
685 		if(you.col < ps->col){
686 			for (p.col = you.col+1;p.col <= ps->col;p.col++)
687 				pchar(&p,'>');
688 			delay(10);
689 			for (;p.col > you.col;p.col--)
690 				chk(&p);
691 		} else {
692 			for (p.col = you.col-1;p.col >= ps->col;p.col--)
693 				pchar(&p,'<');
694 			delay(10);
695 			for (;p.col < you.col;p.col++)
696 				chk(&p);
697 		}
698 		return(1);
699 	}
700 	return(0);
701 }
702 
703 surround(ps)
704 struct point *ps;{
705 	struct point x;
706 	int j;
707 
708 	if(ps->col == 0)ps->col++;
709 	if(ps->line == 0)ps->line++;
710 	if(ps->line == LINES -1)ps->line--;
711 	if(ps->col == COLUMNS -1)ps->col--;
712 	apr(point(&x,ps->col-1,ps->line-1),"/*\\\r* *\r\\*/");
713 	for (j=0;j<20;j++){
714 		pchar(ps,'@');
715 		delay(1);
716 		pchar(ps,' ');
717 		delay(1);
718 	}
719 	if (post(cashvalue,0)) {
720 		apr(point(&x,ps->col-1,ps->line-1),"   \ro.o\r\\_/");
721 		delay(6);
722 		apr(point(&x,ps->col-1,ps->line-1),"   \ro.-\r\\_/");
723 		delay(6);
724 	}
725 	apr(point(&x,ps->col-1,ps->line-1),"   \ro.o\r\\_/");
726 }
727 
728 win(ps)
729 struct point *ps;
730 {
731 	struct point x;
732 	int j,k;
733 	int boxsize;	/* actually diameter of box, not radius */
734 
735 	boxsize = fast ? 10 : 4;
736 	point(&x,ps->col,ps->line);
737 	for(j=1;j<boxsize;j++){
738 		for(k=0;k<j;k++){
739 			pchar(&x,'#');
740 			x.line--;
741 		}
742 		for(k=0;k<j;k++){
743 			pchar(&x,'#');
744 			x.col++;
745 		}
746 		j++;
747 		for(k=0;k<j;k++){
748 			pchar(&x,'#');
749 			x.line++;
750 		}
751 		for(k=0;k<j;k++){
752 			pchar(&x,'#');
753 			x.col--;
754 		}
755 	}
756 	fflush(stdout);
757 }
758 
759 pushsnake()
760 {
761 	int i, bonus;
762 	int issame = 0;
763 
764 	/*
765 	 * My manual says times doesn't return a value.  Furthermore, the
766 	 * snake should get his turn every time no matter if the user is
767 	 * on a fast terminal with typematic keys or not.
768 	 * So I have taken the call to times out.
769 	 */
770 	for(i=4; i>=0; i--)
771 		if (same(&snake[i], &snake[5]))
772 			issame++;
773 	if (!issame)
774 		pchar(&snake[5],' ');
775 	for(i=4; i>=0; i--)
776 		snake[i+1]= snake[i];
777 	chase(&snake[0], &snake[1]);
778 	pchar(&snake[1],SNAKETAIL);
779 	pchar(&snake[0],SNAKEHEAD);
780 	for(i=0; i<6; i++)
781 	{
782 		if (same(&snake[i],&you))
783 		{
784 			surround(&you);
785 			i = (cashvalue) % 10;
786 			bonus = random() % 10;
787 			ll();
788 			pr("%d\n", bonus);
789 			delay(30);
790 			if (bonus == i) {
791 				spacewarp(1);
792 				logit("bonus");
793 				flushi();
794 				return(1);
795 			}
796 			if ( loot >= penalty ){
797 				pr("You and your $%d have been eaten\n",
798 				    cashvalue);
799 			} else {
800 				pr("The snake ate you.  You owe $%d.\n",
801 				    -cashvalue);
802 			}
803 			logit("eaten");
804 			length(moves);
805 			done();
806 		}
807 	}
808 	return(0);
809 }
810 
811 chk(sp)
812 struct point *sp;
813 {
814 	int j;
815 
816 	if (same(sp,&money)) {
817 		pchar(sp,TREASURE);
818 		return(2);
819 	}
820 	if (same(sp,&finish)) {
821 		pchar(sp,GOAL);
822 		return(3);
823 	}
824 	if (same(sp,&snake[0])) {
825 		pchar(sp,SNAKEHEAD);
826 		return(4);
827 	}
828 	for(j=1;j<6;j++){
829 		if(same(sp,&snake[j])){
830 			pchar(sp,SNAKETAIL);
831 			return(4);
832 		}
833 	}
834 	if ((sp->col < 4) && (sp->line == 0)){
835 		winnings(cashvalue);
836 		if((you.line == 0) && (you.col < 4)) pchar(&you,ME);
837 		return(5);
838 	}
839 	if (same(sp,&you)) {
840 		pchar(sp,ME);
841 		return(1);
842 	}
843 	pchar(sp,' ');
844 	return(0);
845 }
846 winnings(won)
847 int won;
848 {
849 	struct point p;
850 
851 	p.line = p.col = 1;
852 	if(won>0){
853 		move(&p);
854 		pr("$%d",won);
855 	}
856 }
857 
858 void
859 stop(){
860 	signal(SIGINT,SIG_IGN);
861 	ll();
862 	length(moves);
863 	done();
864 }
865 
866 suspend()
867 {
868 	ll();
869 	cook();
870 	kill(getpid(), SIGTSTP);
871 	raw();
872 	setup();
873 	winnings(cashvalue);
874 }
875 
876 length(num)
877 int num;
878 {
879 	pr("You made %d moves.\n",num);
880 }
881 
882 logit(msg)
883 char *msg;
884 {
885 	time_t t;
886 
887 	if (logfile != NULL) {
888 		time(&t);
889 		fprintf(logfile, "%s $%d %dx%d %s %s",
890 		    getlogin(), cashvalue, lcnt, ccnt, msg, ctime(&t));
891 		fclose(logfile);
892 	}
893 }
894