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