xref: /openbsd-src/games/snake/snake.c (revision df69c215c7c66baf660f3f65414fd34796c96152)
1*df69c215Sderaadt /*	$OpenBSD: snake.c,v 1.34 2019/06/28 13:32:52 deraadt Exp $	*/
2f43998fdSpjanzen /*	$NetBSD: snake.c,v 1.8 1995/04/29 00:06:41 mycroft Exp $	*/
3f43998fdSpjanzen 
4f43998fdSpjanzen /*
5f43998fdSpjanzen  * Copyright (c) 1980, 1993
6f43998fdSpjanzen  *	The Regents of the University of California.  All rights reserved.
7f43998fdSpjanzen  *
8f43998fdSpjanzen  * Redistribution and use in source and binary forms, with or without
9f43998fdSpjanzen  * modification, are permitted provided that the following conditions
10f43998fdSpjanzen  * are met:
11f43998fdSpjanzen  * 1. Redistributions of source code must retain the above copyright
12f43998fdSpjanzen  *    notice, this list of conditions and the following disclaimer.
13f43998fdSpjanzen  * 2. Redistributions in binary form must reproduce the above copyright
14f43998fdSpjanzen  *    notice, this list of conditions and the following disclaimer in the
15f43998fdSpjanzen  *    documentation and/or other materials provided with the distribution.
167a09557bSmillert  * 3. Neither the name of the University nor the names of its contributors
17f43998fdSpjanzen  *    may be used to endorse or promote products derived from this software
18f43998fdSpjanzen  *    without specific prior written permission.
19f43998fdSpjanzen  *
20f43998fdSpjanzen  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21f43998fdSpjanzen  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22f43998fdSpjanzen  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23f43998fdSpjanzen  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24f43998fdSpjanzen  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25f43998fdSpjanzen  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26f43998fdSpjanzen  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27f43998fdSpjanzen  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28f43998fdSpjanzen  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29f43998fdSpjanzen  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30f43998fdSpjanzen  * SUCH DAMAGE.
31f43998fdSpjanzen  */
32f43998fdSpjanzen 
33f43998fdSpjanzen /*
34f43998fdSpjanzen  * snake - crt hack game.
35f43998fdSpjanzen  *
36f43998fdSpjanzen  * You move around the screen with arrow keys trying to pick up money
37f43998fdSpjanzen  * without getting eaten by the snake.  hjkl work as in vi in place of
38f43998fdSpjanzen  * arrow keys.  You can leave at the exit any time.
39f43998fdSpjanzen  */
40f43998fdSpjanzen 
41fa24ff78Spjanzen #include <curses.h>
42fa24ff78Spjanzen #include <err.h>
43f527bb56Stb #include <errno.h>
44f43998fdSpjanzen #include <fcntl.h>
45f527bb56Stb #include <limits.h>
46fa24ff78Spjanzen #include <math.h>
47fa24ff78Spjanzen #include <signal.h>
48fa24ff78Spjanzen #include <stdlib.h>
49fa24ff78Spjanzen #include <string.h>
50fa24ff78Spjanzen #include <termios.h>
51ee7acb09Stb #include <time.h>
52f43998fdSpjanzen #include <unistd.h>
53f43998fdSpjanzen 
54fa24ff78Spjanzen #ifdef	DEBUG
55fa24ff78Spjanzen #define	cashvalue	(loot-penalty)/25
56fa24ff78Spjanzen #else
57fa24ff78Spjanzen #define	cashvalue	chunk*(loot-penalty)/25
58fa24ff78Spjanzen #endif
59fa24ff78Spjanzen 
60fa24ff78Spjanzen struct point {
61fa24ff78Spjanzen 	int col, line;
62fa24ff78Spjanzen };
63fa24ff78Spjanzen 
64fa24ff78Spjanzen #define	same(s1, s2)	((s1)->line == (s2)->line && (s1)->col == (s2)->col)
65fa24ff78Spjanzen 
66fa24ff78Spjanzen #define PENALTY	10	/* % penalty for invoking spacewarp     */
67fa24ff78Spjanzen 
68fa24ff78Spjanzen #define ME		'I'
69fa24ff78Spjanzen #define SNAKEHEAD	'S'
70fa24ff78Spjanzen #define SNAKETAIL	's'
71fa24ff78Spjanzen #define TREASURE	'$'
72fa24ff78Spjanzen #define GOAL		'#'
73fa24ff78Spjanzen 
74f527bb56Stb #define TOPN	10	/* top scores to print if you lose */
75f527bb56Stb #define SCORES_ENTRIES (TOPN + 1)
76fa24ff78Spjanzen 
77fa24ff78Spjanzen #define pchar(point, c)	mvaddch((point)->line + 1, (point)->col + 1, (c))
78fa24ff78Spjanzen /* Can't use terminal timing to do delay, in light of X */
79fa24ff78Spjanzen #define delay(t)	usleep((t) * 50000)
80fa24ff78Spjanzen /* Delay units are 1/20 s */
81fa24ff78Spjanzen 
82f43998fdSpjanzen struct point you;
83f43998fdSpjanzen struct point money;
84f43998fdSpjanzen struct point finish;
85f43998fdSpjanzen struct point snake[6];
86f43998fdSpjanzen 
87f527bb56Stb int	 lcnt, ccnt;	/* user's idea of screen size */
88f527bb56Stb int	 chunk;		/* amount of money given at a time */
89f43998fdSpjanzen int	 loot, penalty;
90f43998fdSpjanzen int	 moves;
91f43998fdSpjanzen int	 fast = 1;
92f43998fdSpjanzen 
93f527bb56Stb struct highscore {
94f527bb56Stb 	char	name[LOGIN_NAME_MAX];
95f527bb56Stb 	short	score;
96f527bb56Stb } scores[SCORES_ENTRIES];
97f527bb56Stb int	 nscores;
98f527bb56Stb 
99f527bb56Stb char	 scorepath[PATH_MAX];
100f527bb56Stb FILE	*sf;
101f43998fdSpjanzen int	 rawscores;
102f527bb56Stb 
103f43998fdSpjanzen #ifdef LOGGING
104f43998fdSpjanzen FILE	*logfile;
105f527bb56Stb char	 logpath[PATH_MAX];
106f43998fdSpjanzen #endif
107f43998fdSpjanzen 
108c72b5b24Smillert void	chase(struct point *, struct point *);
109c72b5b24Smillert int	chk(struct point *);
110c72b5b24Smillert void	drawbox(void);
111c72b5b24Smillert void	length(int);
112c72b5b24Smillert void	mainloop(void);
113c72b5b24Smillert int	post(int, int);
114c72b5b24Smillert int	pushsnake(void);
115f527bb56Stb int	readscores(int);
116c72b5b24Smillert void	setup(void);
117c72b5b24Smillert void	snap(void);
118f527bb56Stb void	snrand(struct point *);
119565945afSmestre void	snscore(int);
120c72b5b24Smillert void	spacewarp(int);
121c72b5b24Smillert void	stop(int);
122c72b5b24Smillert int	stretch(struct point *);
123c72b5b24Smillert void	surround(struct point *);
124c72b5b24Smillert void	suspend(void);
125c72b5b24Smillert void	win(struct point *);
126c72b5b24Smillert void	winnings(int);
127fa24ff78Spjanzen 
128fa24ff78Spjanzen #ifdef LOGGING
129c72b5b24Smillert void	logit(char *);
130fa24ff78Spjanzen #endif
131fa24ff78Spjanzen 
1325029f74fSderaadt int	wantstop;
133fa24ff78Spjanzen 
134f43998fdSpjanzen int
main(int argc,char * argv[])135ff8320a7Sderaadt main(int argc, char *argv[])
136f43998fdSpjanzen {
1375029f74fSderaadt 	struct	sigaction sa;
138f527bb56Stb 	int	ch, i;
139f43998fdSpjanzen 
140f43998fdSpjanzen #ifdef LOGGING
1414a0e2eedStb 	const char	*home;
1424a0e2eedStb 
1434a0e2eedStb 	home = getenv("HOME");
1444a0e2eedStb 	if (home == NULL || *home == '\0')
1454a0e2eedStb 		err(1, "getenv");
1464a0e2eedStb 
147fd639cceStb 	snprintf(logpath, sizeof(logpath), "%s/%s", home, ".snake.log");
148f527bb56Stb 	logfile = fopen(logpath, "a");
149f43998fdSpjanzen #endif
150f43998fdSpjanzen 
151fa24ff78Spjanzen 	while ((ch = getopt(argc, argv, "hl:stw:")) != -1)
152f43998fdSpjanzen 		switch ((char)ch) {
153f43998fdSpjanzen 		case 'w':	/* width */
154e42da8bdSmestre 			ccnt = strtonum(optarg, 1, INT_MAX, NULL);
155f43998fdSpjanzen 			break;
156f43998fdSpjanzen 		case 'l':	/* length */
157e42da8bdSmestre 			lcnt = strtonum(optarg, 1, INT_MAX, NULL);
158f43998fdSpjanzen 			break;
159f43998fdSpjanzen 		case 's': /* score */
160f527bb56Stb 			if (readscores(0))
161565945afSmestre 				snscore(0);
162f527bb56Stb 			else
163f527bb56Stb 				printf("no scores so far\n");
16417641e31Stb 			return 0;
165f43998fdSpjanzen 			break;
166fa24ff78Spjanzen 		case 't': /* slow terminal */
167fa24ff78Spjanzen 			fast = 0;
168fa24ff78Spjanzen 			break;
169f43998fdSpjanzen 		case 'h':
170f43998fdSpjanzen 		default:
171e42da8bdSmestre 			fprintf(stderr, "usage: %s [-st] [-l length] "
172e42da8bdSmestre 			    "[-w width]\n", getprogname());
17317641e31Stb 			return 1;
174f43998fdSpjanzen 		}
175f43998fdSpjanzen 
176f527bb56Stb 	readscores(1);
177f43998fdSpjanzen 	penalty = loot = 0;
178fa24ff78Spjanzen 	initscr();
179b9f12921Smestre 
180b9f12921Smestre 	if (pledge("stdio tty", NULL) == -1)
181b9f12921Smestre 		err(1, "pledge");
182b9f12921Smestre 
183fa24ff78Spjanzen #ifdef KEY_LEFT
184fa24ff78Spjanzen 	keypad(stdscr, TRUE);
185fa24ff78Spjanzen #endif
186fa24ff78Spjanzen 	nonl();
187fa24ff78Spjanzen 	cbreak();
188fa24ff78Spjanzen 	noecho();
189fa24ff78Spjanzen 
190fa24ff78Spjanzen 	if (!lcnt || lcnt > LINES - 2)
191fa24ff78Spjanzen 		lcnt = LINES - 2;
192fa24ff78Spjanzen 	if (!ccnt || ccnt > COLS - 3)
193fa24ff78Spjanzen 		ccnt = COLS - 3;
194f43998fdSpjanzen 
19534278d36Sguenther 	i = lcnt < ccnt ? lcnt : ccnt;
196f43998fdSpjanzen 	if (i < 4) {
197fa24ff78Spjanzen 		endwin();
198f43998fdSpjanzen 		errx(1, "screen too small for a fair game.");
199f43998fdSpjanzen 	}
200f43998fdSpjanzen 	/*
201f43998fdSpjanzen 	 * chunk is the amount of money the user gets for each $.
202f43998fdSpjanzen 	 * The formula below tries to be fair for various screen sizes.
203f43998fdSpjanzen 	 * We only pay attention to the smaller of the 2 edges, since
204f43998fdSpjanzen 	 * that seems to be the bottleneck.
205f43998fdSpjanzen 	 * This formula is a hyperbola which includes the following points:
206f43998fdSpjanzen 	 *	(24, $25)	(original scoring algorithm)
207f43998fdSpjanzen 	 *	(12, $40)	(experimentally derived by the "feel")
208f43998fdSpjanzen 	 *	(48, $15)	(a guess)
209f43998fdSpjanzen 	 * This will give a 4x4 screen $99/shot.  We don't allow anything
210f43998fdSpjanzen 	 * smaller than 4x4 because there is a 3x3 game where you can win
211f43998fdSpjanzen 	 * an infinite amount of money.
212f43998fdSpjanzen 	 */
213f43998fdSpjanzen 	if (i < 12)
214f43998fdSpjanzen 		i = 12;	/* otherwise it isn't fair */
215f43998fdSpjanzen 	/*
216f43998fdSpjanzen 	 * Compensate for border.  This really changes the game since
217f43998fdSpjanzen 	 * the screen is two squares smaller but we want the default
218f43998fdSpjanzen 	 * to be $25, and the high scores on small screens were a bit
219f43998fdSpjanzen 	 * much anyway.
220f43998fdSpjanzen 	 */
221f43998fdSpjanzen 	i += 2;
222f43998fdSpjanzen 	chunk = (675.0 / (i + 6)) + 2.5;	/* min screen edge */
223f43998fdSpjanzen 
2245029f74fSderaadt 	memset(&sa, 0, sizeof sa);
2255029f74fSderaadt 	sigemptyset(&sa.sa_mask);
2265029f74fSderaadt 	sa.sa_handler = stop;
2275029f74fSderaadt 	sigaction(SIGINT, &sa, NULL);
228f43998fdSpjanzen 
229f43998fdSpjanzen 	snrand(&finish);
230f43998fdSpjanzen 	snrand(&you);
231f43998fdSpjanzen 	snrand(&money);
232f43998fdSpjanzen 	snrand(&snake[0]);
233f43998fdSpjanzen 
234f43998fdSpjanzen 	for (i = 1; i < 6; i++)
235f43998fdSpjanzen 		chase(&snake[i], &snake[i - 1]);
236f43998fdSpjanzen 	setup();
237f43998fdSpjanzen 	mainloop();
23817641e31Stb 	return 0;
239f43998fdSpjanzen }
240f43998fdSpjanzen 
241f43998fdSpjanzen /* Main command loop */
242f43998fdSpjanzen void
mainloop(void)243ff8320a7Sderaadt mainloop(void)
244f43998fdSpjanzen {
245fa24ff78Spjanzen 	int	k;
246fa24ff78Spjanzen 	int	c, lastc = 0;
247fa24ff78Spjanzen 	int repeat = 1;
248f43998fdSpjanzen 
249f43998fdSpjanzen 	for (;;) {
2505029f74fSderaadt 		if (wantstop) {
2515029f74fSderaadt 			endwin();
2525029f74fSderaadt 			length(moves);
2535029f74fSderaadt 			exit(0);
2545029f74fSderaadt 		}
2555029f74fSderaadt 
256fa24ff78Spjanzen 		/* Highlight you, not left & above */
257fa24ff78Spjanzen 		move(you.line + 1, you.col + 1);
258fa24ff78Spjanzen 		refresh();
259fa24ff78Spjanzen 		if (((c = getch()) <= '9') && (c >= '0')) {
260fa24ff78Spjanzen 			repeat = c - '0';
261fa24ff78Spjanzen 			while (((c = getch()) <= '9') && (c >= '0'))
262fa24ff78Spjanzen 				repeat = 10 * repeat + (c - '0');
263f43998fdSpjanzen 		} else {
264f43998fdSpjanzen 			if (c != '.')
265f43998fdSpjanzen 				repeat = 1;
266f43998fdSpjanzen 		}
267f43998fdSpjanzen 		if (c == '.')
268f43998fdSpjanzen 			c = lastc;
269f43998fdSpjanzen 		if (!fast)
270fa24ff78Spjanzen 			flushinp();
271f43998fdSpjanzen 		lastc = c;
272fa24ff78Spjanzen 
273f43998fdSpjanzen 		switch (c) {
274f43998fdSpjanzen 		case CTRL('z'):
275f43998fdSpjanzen 			suspend();
276f43998fdSpjanzen 			continue;
277fa24ff78Spjanzen 		case '\044':
278f43998fdSpjanzen 		case 'x':
279f43998fdSpjanzen 		case 0177:	/* del or end of file */
280fa24ff78Spjanzen 		case ERR:
281fa24ff78Spjanzen 			endwin();
282f43998fdSpjanzen 			length(moves);
283f43998fdSpjanzen #ifdef LOGGING
284f43998fdSpjanzen 			logit("quit");
285f43998fdSpjanzen #endif
286f43998fdSpjanzen 			exit(0);
287f43998fdSpjanzen 		case CTRL('l'):
288f43998fdSpjanzen 			setup();
289f43998fdSpjanzen 			winnings(cashvalue);
290f43998fdSpjanzen 			continue;
291f43998fdSpjanzen 		case 'p':
292f43998fdSpjanzen 		case 'd':
293f43998fdSpjanzen 			snap();
294f43998fdSpjanzen 			continue;
295f43998fdSpjanzen 		case 'w':
296f43998fdSpjanzen 			spacewarp(0);
297f43998fdSpjanzen 			continue;
298f43998fdSpjanzen 		case 'A':
299f43998fdSpjanzen 			repeat = you.col;
300f43998fdSpjanzen 			c = 'h';
301f43998fdSpjanzen 			break;
302f43998fdSpjanzen 		case 'H':
303f43998fdSpjanzen 		case 'S':
304f43998fdSpjanzen 			repeat = you.col - money.col;
305f43998fdSpjanzen 			c = 'h';
306f43998fdSpjanzen 			break;
307f43998fdSpjanzen 		case 'T':
308f43998fdSpjanzen 			repeat = you.line;
309f43998fdSpjanzen 			c = 'k';
310f43998fdSpjanzen 			break;
311f43998fdSpjanzen 		case 'K':
312f43998fdSpjanzen 		case 'E':
313f43998fdSpjanzen 			repeat = you.line - money.line;
314f43998fdSpjanzen 			c = 'k';
315f43998fdSpjanzen 			break;
316f43998fdSpjanzen 		case 'P':
317f43998fdSpjanzen 			repeat = ccnt - 1 - you.col;
318f43998fdSpjanzen 			c = 'l';
319f43998fdSpjanzen 			break;
320f43998fdSpjanzen 		case 'L':
321f43998fdSpjanzen 		case 'F':
322f43998fdSpjanzen 			repeat = money.col - you.col;
323f43998fdSpjanzen 			c = 'l';
324f43998fdSpjanzen 			break;
325f43998fdSpjanzen 		case 'B':
326f43998fdSpjanzen 			repeat = lcnt - 1 - you.line;
327f43998fdSpjanzen 			c = 'j';
328f43998fdSpjanzen 			break;
329f43998fdSpjanzen 		case 'J':
330f43998fdSpjanzen 		case 'C':
331f43998fdSpjanzen 			repeat = money.line - you.line;
332f43998fdSpjanzen 			c = 'j';
333f43998fdSpjanzen 			break;
334f43998fdSpjanzen 		}
335f43998fdSpjanzen 		for (k = 1; k <= repeat; k++) {
336f43998fdSpjanzen 			moves++;
337f43998fdSpjanzen 			switch (c) {
338f43998fdSpjanzen 			case 's':
339f43998fdSpjanzen 			case 'h':
340fa24ff78Spjanzen #ifdef KEY_LEFT
341fa24ff78Spjanzen 			case KEY_LEFT:
342fa24ff78Spjanzen #endif
343f43998fdSpjanzen 			case '\b':
344f43998fdSpjanzen 				if (you.col > 0) {
345f43998fdSpjanzen 					if ((fast) || (k == 1))
346f43998fdSpjanzen 						pchar(&you, ' ');
347f43998fdSpjanzen 					you.col--;
348fa24ff78Spjanzen 					if ((fast) || (k == repeat) ||
349fa24ff78Spjanzen 					    (you.col == 0))
350f43998fdSpjanzen 						pchar(&you, ME);
351f43998fdSpjanzen 				}
352f43998fdSpjanzen 				break;
353f43998fdSpjanzen 			case 'f':
354f43998fdSpjanzen 			case 'l':
355fa24ff78Spjanzen #ifdef KEY_RIGHT
356fa24ff78Spjanzen 			case KEY_RIGHT:
357fa24ff78Spjanzen #endif
358f43998fdSpjanzen 			case ' ':
359f43998fdSpjanzen 				if (you.col < ccnt - 1) {
360f43998fdSpjanzen 					if ((fast) || (k == 1))
361f43998fdSpjanzen 						pchar(&you, ' ');
362f43998fdSpjanzen 					you.col++;
363fa24ff78Spjanzen 					if ((fast) || (k == repeat) ||
364fa24ff78Spjanzen 					    (you.col == ccnt - 1))
365f43998fdSpjanzen 						pchar(&you, ME);
366f43998fdSpjanzen 				}
367f43998fdSpjanzen 				break;
368f43998fdSpjanzen 			case CTRL('p'):
369f43998fdSpjanzen 			case 'e':
370f43998fdSpjanzen 			case 'k':
371fa24ff78Spjanzen #ifdef KEY_UP
372fa24ff78Spjanzen 			case KEY_UP:
373fa24ff78Spjanzen #endif
374f43998fdSpjanzen 			case 'i':
375f43998fdSpjanzen 				if (you.line > 0) {
376f43998fdSpjanzen 					if ((fast) || (k == 1))
377f43998fdSpjanzen 						pchar(&you, ' ');
378f43998fdSpjanzen 					you.line--;
379fa24ff78Spjanzen 					if ((fast) || (k == repeat) ||
380fa24ff78Spjanzen 					    (you.line == 0))
381f43998fdSpjanzen 						pchar(&you, ME);
382f43998fdSpjanzen 				}
383f43998fdSpjanzen 				break;
384f43998fdSpjanzen 			case CTRL('n'):
385f43998fdSpjanzen 			case 'c':
386f43998fdSpjanzen 			case 'j':
387fa24ff78Spjanzen #ifdef KEY_DOWN
388fa24ff78Spjanzen 			case KEY_DOWN:
389fa24ff78Spjanzen #endif
390fa24ff78Spjanzen 			case '\n':
391fa24ff78Spjanzen 			case '\r':
392f43998fdSpjanzen 			case 'm':
393f43998fdSpjanzen 				if (you.line + 1 < lcnt) {
394f43998fdSpjanzen 					if ((fast) || (k == 1))
395f43998fdSpjanzen 						pchar(&you, ' ');
396f43998fdSpjanzen 					you.line++;
397fa24ff78Spjanzen 					if ((fast) || (k == repeat) ||
398fa24ff78Spjanzen 					    (you.line == lcnt - 1))
399f43998fdSpjanzen 						pchar(&you, ME);
400f43998fdSpjanzen 				}
401f43998fdSpjanzen 				break;
402f43998fdSpjanzen 			}
403f43998fdSpjanzen 
404f43998fdSpjanzen 			if (same(&you, &money)) {
405f43998fdSpjanzen 				loot += 25;
406f43998fdSpjanzen 				if (k < repeat)
407f43998fdSpjanzen 					pchar(&you, ' ');
408f43998fdSpjanzen 				do {
409f43998fdSpjanzen 					snrand(&money);
410fa24ff78Spjanzen 				} while ((money.col == finish.col &&
411fa24ff78Spjanzen 				    money.line == finish.line) ||
412f43998fdSpjanzen 				    (money.col < 5 && money.line == 0) ||
413fa24ff78Spjanzen 				    (money.col == you.col &&
414fa24ff78Spjanzen 				    money.line == you.line));
415f43998fdSpjanzen 				pchar(&money, TREASURE);
416f43998fdSpjanzen 				winnings(cashvalue);
417f43998fdSpjanzen /*				continue;		 Previously, snake missed a turn! */
418f43998fdSpjanzen 			}
419f43998fdSpjanzen 			if (same(&you, &finish)) {
420f43998fdSpjanzen 				win(&finish);
421fa24ff78Spjanzen 				flushinp();
422fa24ff78Spjanzen 				endwin();
423f43998fdSpjanzen 				printf("You have won with $%d.\n", cashvalue);
424fa24ff78Spjanzen 				fflush(stdout);
425f43998fdSpjanzen #ifdef LOGGING
426f43998fdSpjanzen 				logit("won");
427f43998fdSpjanzen #endif
428f43998fdSpjanzen 				length(moves);
429f43998fdSpjanzen 				post(cashvalue, 1);
430f43998fdSpjanzen 				close(rawscores);
431f43998fdSpjanzen 				exit(0);
432f43998fdSpjanzen 			}
433f43998fdSpjanzen 			if (pushsnake())
434f43998fdSpjanzen 				break;
435f43998fdSpjanzen 		}
436f43998fdSpjanzen 	}
437f43998fdSpjanzen }
438f43998fdSpjanzen 
439f43998fdSpjanzen /* set up the board */
440f43998fdSpjanzen void
setup(void)441ff8320a7Sderaadt setup(void)
442f43998fdSpjanzen {
443f43998fdSpjanzen 	int	i;
444f43998fdSpjanzen 
445fa24ff78Spjanzen 	erase();
446f43998fdSpjanzen 	pchar(&you, ME);
447f43998fdSpjanzen 	pchar(&finish, GOAL);
448f43998fdSpjanzen 	pchar(&money, TREASURE);
449f43998fdSpjanzen 	for (i = 1; i < 6; i++) {
450f43998fdSpjanzen 		pchar(&snake[i], SNAKETAIL);
451f43998fdSpjanzen 	}
452f43998fdSpjanzen 	pchar(&snake[0], SNAKEHEAD);
453f43998fdSpjanzen 	drawbox();
454fa24ff78Spjanzen 	refresh();
455f43998fdSpjanzen }
456f43998fdSpjanzen 
457f43998fdSpjanzen void
drawbox(void)458ff8320a7Sderaadt drawbox(void)
459f43998fdSpjanzen {
460f43998fdSpjanzen 	int i;
461f43998fdSpjanzen 
462fa24ff78Spjanzen 	for (i = 1; i <= ccnt; i++) {
463fa24ff78Spjanzen 		mvaddch(0, i, '-');
464fa24ff78Spjanzen 		mvaddch(lcnt + 1, i, '-');
465f43998fdSpjanzen 	}
466fa24ff78Spjanzen 	for (i = 0; i <= lcnt + 1; i++) {
467fa24ff78Spjanzen 		mvaddch(i, 0, '|');
468fa24ff78Spjanzen 		mvaddch(i, ccnt + 1, '|');
469f43998fdSpjanzen 	}
470f43998fdSpjanzen }
471f43998fdSpjanzen 
472f43998fdSpjanzen void
snrand(struct point * sp)473ff8320a7Sderaadt snrand(struct point *sp)
474f43998fdSpjanzen {
475f43998fdSpjanzen 	struct point p;
476f43998fdSpjanzen 	int i;
477f43998fdSpjanzen 
478f43998fdSpjanzen 	for (;;) {
47966e49541Snaddy 		p.col = arc4random_uniform(ccnt);
48066e49541Snaddy 		p.line = arc4random_uniform(lcnt);
481f43998fdSpjanzen 
482f43998fdSpjanzen 		/* make sure it's not on top of something else */
483f43998fdSpjanzen 		if (p.line == 0 && p.col < 5)
484f43998fdSpjanzen 			continue;
485f43998fdSpjanzen 		if (same(&p, &you))
486f43998fdSpjanzen 			continue;
487f43998fdSpjanzen 		if (same(&p, &money))
488f43998fdSpjanzen 			continue;
489f43998fdSpjanzen 		if (same(&p, &finish))
490f43998fdSpjanzen 			continue;
491f43998fdSpjanzen 		for (i = 0; i < 6; i++)
492f43998fdSpjanzen 			if (same(&p, &snake[i]))
493f43998fdSpjanzen 				break;
494f43998fdSpjanzen 		if (i < 6)
495f43998fdSpjanzen 			continue;
496f43998fdSpjanzen 		break;
497f43998fdSpjanzen 	}
498f43998fdSpjanzen 	*sp = p;
499f43998fdSpjanzen }
500f43998fdSpjanzen 
501f43998fdSpjanzen int
post(int iscore,int flag)502ff8320a7Sderaadt post(int iscore, int flag)
503f43998fdSpjanzen {
504f527bb56Stb 	struct  highscore tmp;
505f527bb56Stb 	int	rank = nscores;
506f43998fdSpjanzen 	short	oldbest = 0;
507f43998fdSpjanzen 
508fa24ff78Spjanzen 	/* I want to printf() the scores for terms that clear on endwin(),
509f43998fdSpjanzen 	 * but this routine also gets called with flag == 0 to see if
510f43998fdSpjanzen 	 * the snake should wink.  If (flag) then we're at game end and
511f43998fdSpjanzen 	 * can printf.
512f43998fdSpjanzen 	 */
513f527bb56Stb 	if (flag == 0) {
514f527bb56Stb 		if (nscores > 0)
515f527bb56Stb 			return (iscore > scores[nscores - 1].score);
516f527bb56Stb 		else
517f527bb56Stb 			return (iscore > 0);
518f43998fdSpjanzen 	}
519f43998fdSpjanzen 
520f527bb56Stb 	if (nscores > 0) {
521f527bb56Stb 		oldbest = scores[0].score;
522f527bb56Stb 		scores[nscores].score = iscore;
523f527bb56Stb 		if (nscores < TOPN)
524f527bb56Stb 			nscores++;
525f527bb56Stb 	} else {
526f527bb56Stb 		nscores = 1;
527f527bb56Stb 		scores[0].score = iscore;
528f527bb56Stb 		oldbest = 0;
529f527bb56Stb 	}
530f527bb56Stb 
531f527bb56Stb 	/* Insert this joker's current score */
532f527bb56Stb 	while (rank-- > 0 && iscore > scores[rank].score) {
533f527bb56Stb 		memcpy(&tmp, &scores[rank], sizeof(struct highscore));
534f527bb56Stb 		memcpy(&scores[rank], &scores[rank + 1],
535f527bb56Stb 		    sizeof(struct highscore));
536f527bb56Stb 		memcpy(&scores[rank + 1], &tmp, sizeof(struct highscore));
537f527bb56Stb 	}
538f527bb56Stb 
539f527bb56Stb 	if (rank++ < 0)
540f43998fdSpjanzen 		printf("\nYou bettered your previous best of $%d\n", oldbest);
541f527bb56Stb 	else if (rank < nscores)
542f527bb56Stb 		printf("\nYour score of $%d is ranked %d of all times!\n",
543f527bb56Stb 		    iscore, rank + 1);
544f43998fdSpjanzen 
54545555366Smestre 	if (fseek(sf, 0L, SEEK_SET) == -1)
54645555366Smestre 		err(1, "fseek");
547565945afSmestre 	if (fwrite(scores, sizeof(scores[0]), nscores, sf) < (u_int)nscores)
548f527bb56Stb 		err(1, "fwrite");
549f527bb56Stb 	if (fclose(sf))
550f527bb56Stb 		err(1, "fclose");
551f527bb56Stb 
552f43998fdSpjanzen 	/* See if we have a new champ */
553565945afSmestre 	snscore(TOPN);
554f43998fdSpjanzen 	return(1);
555f43998fdSpjanzen }
556f43998fdSpjanzen 
557fa24ff78Spjanzen const int	mx[8] = { 0, 1, 1, 1, 0,-1,-1,-1};
558fa24ff78Spjanzen const int	my[8] = {-1,-1, 0, 1, 1, 1, 0,-1};
559fa24ff78Spjanzen const float	absv[8] = {1, 1.4, 1, 1.4, 1, 1.4, 1, 1.4};
560f43998fdSpjanzen int	oldw = 0;
561f43998fdSpjanzen 
562f43998fdSpjanzen void
chase(struct point * np,struct point * sp)563ff8320a7Sderaadt chase(struct point *np, struct point *sp)
564f43998fdSpjanzen {
565f43998fdSpjanzen 	/* this algorithm has bugs; otherwise the snake would get too good */
566f43998fdSpjanzen 	struct point d;
567f43998fdSpjanzen 	int	w, i, wt[8];
568f43998fdSpjanzen 	double	v1, v2, vp, max;
569f43998fdSpjanzen 
570fa24ff78Spjanzen 	d.col = you.col-sp->col;
571fa24ff78Spjanzen 	d.line = you.line-sp->line;
572f43998fdSpjanzen 	v1 = sqrt((double)(d.col * d.col + d.line * d.line) );
573f43998fdSpjanzen 	w  = 0;
574f43998fdSpjanzen 	max = 0;
575fa24ff78Spjanzen 	for (i = 0; i < 8; i++) {
576f43998fdSpjanzen 		vp = d.col * mx[i] + d.line * my[i];
577f43998fdSpjanzen 		v2 = absv[i];
578f43998fdSpjanzen 		if (v1 > 0)
579f43998fdSpjanzen 			vp = ((double)vp) / (v1 * v2);
580f43998fdSpjanzen 		else
581f43998fdSpjanzen 			vp = 1.0;
582f43998fdSpjanzen 		if (vp > max) {
583f43998fdSpjanzen 			max = vp;
584f43998fdSpjanzen 			w = i;
585f43998fdSpjanzen 		}
586f43998fdSpjanzen 	}
587f43998fdSpjanzen 	for (i = 0; i < 8; i++) {
588fa24ff78Spjanzen 		d.col = sp->col + mx[i];
589fa24ff78Spjanzen 		d.line = sp->line + my[i];
590f43998fdSpjanzen 		wt[i] = 0;
591f43998fdSpjanzen 		if (d.col < 0 || d.col >= ccnt || d.line < 0 || d.line >= lcnt)
592f43998fdSpjanzen 			continue;
593f43998fdSpjanzen 		/*
594f43998fdSpjanzen 		 * Change to allow snake to eat you if you're on the money;
595f43998fdSpjanzen 		 * otherwise, you can just crouch there until the snake goes
596f43998fdSpjanzen 		 * away.  Not positive it's right.
597f43998fdSpjanzen 		 *
598f43998fdSpjanzen 		 * if (d.line == 0 && d.col < 5) continue;
599f43998fdSpjanzen 		 */
600f43998fdSpjanzen 		if (same(&d, &money) || same(&d,&finish))
601f43998fdSpjanzen 			continue;
602f43998fdSpjanzen 		wt[i] = (i == w ? loot/10 : 1);
603f43998fdSpjanzen 		if (i == oldw)
604f43998fdSpjanzen 			wt[i] += loot/20;
605f43998fdSpjanzen 	}
606f43998fdSpjanzen 	for (w = i = 0; i < 8; i++)
607f43998fdSpjanzen 		w += wt[i];
60866e49541Snaddy 	vp = arc4random_uniform(w);
609f43998fdSpjanzen 	for (i = 0; i < 8; i++)
610f43998fdSpjanzen 		if (vp < wt[i])
611f43998fdSpjanzen 			break;
612f43998fdSpjanzen 		else
613f43998fdSpjanzen 			vp -= wt[i];
614f43998fdSpjanzen 	if (i == 8) {
615fa24ff78Spjanzen 		printw("failure\n");
616f43998fdSpjanzen 		i = 0;
617f43998fdSpjanzen 		while (wt[i] == 0)
618f43998fdSpjanzen 			i++;
619f43998fdSpjanzen 	}
620f43998fdSpjanzen 	oldw = w = i;
621fa24ff78Spjanzen 	np->col = sp->col + mx[w];
622fa24ff78Spjanzen 	np->line = sp->line + my[w];
623f43998fdSpjanzen }
624f43998fdSpjanzen 
625f43998fdSpjanzen void
spacewarp(int w)626ff8320a7Sderaadt spacewarp(int w)
627f43998fdSpjanzen {
628f43998fdSpjanzen 	struct point p;
629f43998fdSpjanzen 	int	j;
6300c07ef3dSdhill 	const char  *str;
631f43998fdSpjanzen 
632f43998fdSpjanzen 	snrand(&you);
633fa24ff78Spjanzen 	p.col = COLS / 2 - 8;
634fa24ff78Spjanzen 	p.line = LINES / 2 - 1;
635f43998fdSpjanzen 	if (p.col < 0)
636f43998fdSpjanzen 		p.col = 0;
637f43998fdSpjanzen 	if (p.line < 0)
638f43998fdSpjanzen 		p.line = 0;
639f43998fdSpjanzen 	if (w) {
640f43998fdSpjanzen 		str = "BONUS!!!";
641f43998fdSpjanzen 		loot = loot - penalty;
642f43998fdSpjanzen 		penalty = 0;
643f43998fdSpjanzen 	} else {
644f43998fdSpjanzen 		str = "SPACE WARP!!!";
645f43998fdSpjanzen 		penalty += loot / PENALTY;
646f43998fdSpjanzen 	}
647f43998fdSpjanzen 	for (j = 0; j < 3; j++) {
648fa24ff78Spjanzen 		erase();
649fa24ff78Spjanzen 		refresh();
650f43998fdSpjanzen 		delay(5);
651fa24ff78Spjanzen 		mvaddstr(p.line + 1, p.col + 1, str);
652ae3bacb5Stedu 		mvaddstr(0, 0, "");
653fa24ff78Spjanzen 		refresh();
654f43998fdSpjanzen 		delay(10);
655f43998fdSpjanzen 	}
656f43998fdSpjanzen 	setup();
657f43998fdSpjanzen 	winnings(cashvalue);
658f43998fdSpjanzen }
659f43998fdSpjanzen 
660f43998fdSpjanzen void
snap(void)661ff8320a7Sderaadt snap(void)
662f43998fdSpjanzen {
663f43998fdSpjanzen 
664f43998fdSpjanzen 	if (!stretch(&money))
665f43998fdSpjanzen 		if (!stretch(&finish)) {
666fa24ff78Spjanzen 			pchar(&you, '?');
667fa24ff78Spjanzen 			refresh();
668f43998fdSpjanzen 			delay(10);
669fa24ff78Spjanzen 			pchar(&you, ME);
670f43998fdSpjanzen 		}
671fa24ff78Spjanzen 	refresh();
672f43998fdSpjanzen }
673f43998fdSpjanzen 
674f43998fdSpjanzen int
stretch(struct point * ps)675ff8320a7Sderaadt stretch(struct point *ps)
676f43998fdSpjanzen {
677f43998fdSpjanzen 	struct point p;
678f43998fdSpjanzen 
679fa24ff78Spjanzen 	p.col = you.col;
680fa24ff78Spjanzen 	p.line = you.line;
681f43998fdSpjanzen 	if ((abs(ps->col - you.col) < (ccnt / 12)) && (you.line != ps->line)) {
682f43998fdSpjanzen 		if (you.line < ps->line) {
683f43998fdSpjanzen 			for (p.line = you.line + 1; p.line <= ps->line; p.line++)
684f43998fdSpjanzen 				pchar(&p, 'v');
685fa24ff78Spjanzen 			refresh();
686f43998fdSpjanzen 			delay(10);
687f43998fdSpjanzen 			for (; p.line > you.line; p.line--)
688f43998fdSpjanzen 				chk(&p);
689f43998fdSpjanzen 		} else {
690f43998fdSpjanzen 			for (p.line = you.line - 1; p.line >= ps->line; p.line--)
691f43998fdSpjanzen 				pchar(&p, '^');
692fa24ff78Spjanzen 			refresh();
693f43998fdSpjanzen 			delay(10);
694f43998fdSpjanzen 			for (; p.line < you.line; p.line++)
695f43998fdSpjanzen 				chk(&p);
696f43998fdSpjanzen 		}
697f43998fdSpjanzen 		return(1);
698f43998fdSpjanzen 	} else if ((abs(ps->line - you.line) < (lcnt / 7)) && (you.col != ps->col)) {
699f43998fdSpjanzen 		p.line = you.line;
700f43998fdSpjanzen 		if (you.col < ps->col) {
701f43998fdSpjanzen 			for (p.col = you.col + 1; p.col <= ps->col; p.col++)
702f43998fdSpjanzen 				pchar(&p, '>');
703fa24ff78Spjanzen 			refresh();
704f43998fdSpjanzen 			delay(10);
705f43998fdSpjanzen 			for (; p.col > you.col; p.col--)
706f43998fdSpjanzen 				chk(&p);
707f43998fdSpjanzen 		} else {
708f43998fdSpjanzen 			for (p.col = you.col - 1; p.col >= ps->col; p.col--)
709f43998fdSpjanzen 				pchar(&p, '<');
710fa24ff78Spjanzen 			refresh();
711f43998fdSpjanzen 			delay(10);
712f43998fdSpjanzen 			for (; p.col < you.col; p.col++)
713f43998fdSpjanzen 				chk(&p);
714f43998fdSpjanzen 		}
715f43998fdSpjanzen 		return(1);
716f43998fdSpjanzen 	}
717f43998fdSpjanzen 	return(0);
718f43998fdSpjanzen }
719f43998fdSpjanzen 
720f43998fdSpjanzen void
surround(struct point * ps)721ff8320a7Sderaadt surround(struct point *ps)
722f43998fdSpjanzen {
723f43998fdSpjanzen 	int	j;
724f43998fdSpjanzen 
725f43998fdSpjanzen 	if (ps->col == 0)
726f43998fdSpjanzen 		ps->col++;
727f43998fdSpjanzen 	if (ps->line == 0)
728f43998fdSpjanzen 		ps->line++;
729f43998fdSpjanzen 	if (ps->line == LINES - 1)
730f43998fdSpjanzen 		ps->line--;
731fa24ff78Spjanzen 	if (ps->col == COLS - 1)
732f43998fdSpjanzen 		ps->col--;
733fa24ff78Spjanzen 	mvaddstr(ps->line, ps->col, "/*\\");
734fa24ff78Spjanzen 	mvaddstr(ps->line + 1, ps->col, "* *");
735fa24ff78Spjanzen 	mvaddstr(ps->line + 2, ps->col, "\\*/");
736f43998fdSpjanzen 	for (j = 0; j < 20; j++) {
737f43998fdSpjanzen 		pchar(ps, '@');
738fa24ff78Spjanzen 		refresh();
739f43998fdSpjanzen 		delay(1);
740f43998fdSpjanzen 		pchar(ps, ' ');
741fa24ff78Spjanzen 		refresh();
742f43998fdSpjanzen 		delay(1);
743f43998fdSpjanzen 	}
744f43998fdSpjanzen 	if (post(cashvalue, 0)) {
745fa24ff78Spjanzen 		mvaddstr(ps->line, ps->col, "   ");
746fa24ff78Spjanzen 		mvaddstr(ps->line + 1, ps->col, "o.o");
747fa24ff78Spjanzen 		mvaddstr(ps->line + 2, ps->col, "\\_/");
748fa24ff78Spjanzen 		refresh();
749f43998fdSpjanzen 		delay(6);
750fa24ff78Spjanzen 		mvaddstr(ps->line, ps->col, "   ");
751fa24ff78Spjanzen 		mvaddstr(ps->line + 1, ps->col, "o.-");
752fa24ff78Spjanzen 		mvaddstr(ps->line + 2, ps->col, "\\_/");
753fa24ff78Spjanzen 		refresh();
754f43998fdSpjanzen 		delay(6);
755f43998fdSpjanzen 	}
756fa24ff78Spjanzen 	mvaddstr(ps->line, ps->col, "   ");
757fa24ff78Spjanzen 	mvaddstr(ps->line + 1, ps->col, "o.o");
758fa24ff78Spjanzen 	mvaddstr(ps->line + 2, ps->col, "\\_/");
759fa24ff78Spjanzen 	refresh();
760fa24ff78Spjanzen 	delay(6);
761f43998fdSpjanzen }
762f43998fdSpjanzen 
763f43998fdSpjanzen void
win(struct point * ps)764ff8320a7Sderaadt win(struct point *ps)
765f43998fdSpjanzen {
766f43998fdSpjanzen 	struct point x;
767f43998fdSpjanzen 	int	j, k;
768f43998fdSpjanzen 	int	boxsize;	/* actually diameter of box, not radius */
769f43998fdSpjanzen 
770f43998fdSpjanzen 	boxsize = (fast ? 10 : 4);
771fa24ff78Spjanzen 	x.col = ps->col;
772fa24ff78Spjanzen 	x.line = ps->line;
773f43998fdSpjanzen 	for (j = 1; j < boxsize; j++) {
774f43998fdSpjanzen 		for (k = 0; k < j; k++) {
775f43998fdSpjanzen 			pchar(&x, '#');
776f43998fdSpjanzen 			x.line--;
777f43998fdSpjanzen 		}
778f43998fdSpjanzen 		for (k = 0; k < j; k++) {
779f43998fdSpjanzen 			pchar(&x, '#');
780f43998fdSpjanzen 			x.col++;
781f43998fdSpjanzen 		}
782f43998fdSpjanzen 		j++;
783f43998fdSpjanzen 		for (k = 0; k < j; k++) {
784f43998fdSpjanzen 			pchar(&x, '#');
785f43998fdSpjanzen 			x.line++;
786f43998fdSpjanzen 		}
787f43998fdSpjanzen 		for (k = 0; k < j; k++) {
788f43998fdSpjanzen 			pchar(&x, '#');
789f43998fdSpjanzen 			x.col--;
790f43998fdSpjanzen 		}
791fa24ff78Spjanzen 		refresh();
792f43998fdSpjanzen 		delay(1);
793f43998fdSpjanzen 	}
794f43998fdSpjanzen }
795f43998fdSpjanzen 
796f43998fdSpjanzen int
pushsnake(void)797ff8320a7Sderaadt pushsnake(void)
798f43998fdSpjanzen {
799f43998fdSpjanzen 	int	i, bonus;
800f43998fdSpjanzen 	int	issame = 0;
801f43998fdSpjanzen 	struct point tmp;
802f43998fdSpjanzen 
803f43998fdSpjanzen 	for (i = 4; i >= 0; i--)
804f43998fdSpjanzen 		if (same(&snake[i], &snake[5]))
805f43998fdSpjanzen 			issame++;
806e87918d7Stedu 	if (!issame) {
807e87918d7Stedu 		char sp = ' ';
808e87918d7Stedu 		if (same(&money, &snake[5]))
809e87918d7Stedu 			sp = TREASURE;
810e87918d7Stedu 		pchar(&snake[5], sp);
811e87918d7Stedu 	}
812f43998fdSpjanzen 	/* Need the following to catch you if you step on the snake's tail */
813fa24ff78Spjanzen 	tmp.col = snake[5].col;
814fa24ff78Spjanzen 	tmp.line = snake[5].line;
815f43998fdSpjanzen 	for (i = 4; i >= 0; i--)
816f43998fdSpjanzen 		snake[i + 1] = snake[i];
817f43998fdSpjanzen 	chase(&snake[0], &snake[1]);
818f43998fdSpjanzen 	pchar(&snake[1], SNAKETAIL);
819f43998fdSpjanzen 	pchar(&snake[0], SNAKEHEAD);
820f43998fdSpjanzen 	for (i = 0; i < 6; i++) {
821f43998fdSpjanzen 		if ((same(&snake[i], &you)) || (same(&tmp, &you))) {
822f43998fdSpjanzen 			surround(&you);
823f43998fdSpjanzen 			i = (cashvalue) % 10;
82466e49541Snaddy 			bonus = arc4random_uniform(10);
825fa24ff78Spjanzen 			refresh();
826f43998fdSpjanzen 			delay(30);
827f43998fdSpjanzen 			if (bonus == i) {
828f43998fdSpjanzen 				spacewarp(1);
829f43998fdSpjanzen #ifdef LOGGING
830f43998fdSpjanzen 				logit("bonus");
831f43998fdSpjanzen #endif
832fa24ff78Spjanzen 				flushinp();
833f43998fdSpjanzen 				return(1);
834f43998fdSpjanzen 			}
835fa24ff78Spjanzen 			flushinp();
836fa24ff78Spjanzen 			endwin();
837f43998fdSpjanzen 			if (loot >= penalty) {
838f43998fdSpjanzen 				printf("\nYou and your $%d have been eaten\n", cashvalue);
839f43998fdSpjanzen 			} else {
840f43998fdSpjanzen 				printf("\nThe snake ate you.  You owe $%d.\n", -cashvalue);
841f43998fdSpjanzen 			}
842f43998fdSpjanzen #ifdef LOGGING
843f43998fdSpjanzen 			logit("eaten");
844f43998fdSpjanzen #endif
845f43998fdSpjanzen 			length(moves);
846565945afSmestre 			snscore(TOPN);
847f43998fdSpjanzen 			close(rawscores);
848f43998fdSpjanzen 			exit(0);
849f43998fdSpjanzen 		}
850f43998fdSpjanzen 	}
851f43998fdSpjanzen 	return(0);
852f43998fdSpjanzen }
853f43998fdSpjanzen 
854f43998fdSpjanzen int
chk(struct point * sp)855ff8320a7Sderaadt chk(struct point *sp)
856f43998fdSpjanzen {
857f43998fdSpjanzen 	int	j;
858f43998fdSpjanzen 
859f43998fdSpjanzen 	if (same(sp, &money)) {
860f43998fdSpjanzen 		pchar(sp, TREASURE);
861f43998fdSpjanzen 		return(2);
862f43998fdSpjanzen 	}
863f43998fdSpjanzen 	if (same(sp, &finish)) {
864f43998fdSpjanzen 		pchar(sp, GOAL);
865f43998fdSpjanzen 		return(3);
866f43998fdSpjanzen 	}
867f43998fdSpjanzen 	if (same(sp, &snake[0])) {
868f43998fdSpjanzen 		pchar(sp, SNAKEHEAD);
869f43998fdSpjanzen 		return(4);
870f43998fdSpjanzen 	}
871f43998fdSpjanzen 	for (j = 1; j < 6; j++) {
872f43998fdSpjanzen 		if (same(sp, &snake[j])) {
873f43998fdSpjanzen 			pchar(sp, SNAKETAIL);
874f43998fdSpjanzen 			return(4);
875f43998fdSpjanzen 		}
876f43998fdSpjanzen 	}
877f43998fdSpjanzen 	if ((sp->col < 4) && (sp->line == 0)) {
878f43998fdSpjanzen 		winnings(cashvalue);
879f43998fdSpjanzen 		if ((you.line == 0) && (you.col < 4))
880f43998fdSpjanzen 			pchar(&you, ME);
881f43998fdSpjanzen 		return(5);
882f43998fdSpjanzen 	}
883f43998fdSpjanzen 	if (same(sp, &you)) {
884f43998fdSpjanzen 		pchar(sp, ME);
885f43998fdSpjanzen 		return(1);
886f43998fdSpjanzen 	}
887f43998fdSpjanzen 	pchar(sp, ' ');
888f43998fdSpjanzen 	return(0);
889f43998fdSpjanzen }
890f43998fdSpjanzen 
891f43998fdSpjanzen void
winnings(int won)892ff8320a7Sderaadt winnings(int won)
893f43998fdSpjanzen {
894fa24ff78Spjanzen 	if (won > 0)
895fa24ff78Spjanzen 		mvprintw(1, 1, "$%d  ", won);
896f43998fdSpjanzen }
897f43998fdSpjanzen 
898f43998fdSpjanzen void
stop(int dummy)899ff8320a7Sderaadt stop(int dummy)
900f43998fdSpjanzen {
9015029f74fSderaadt 	wantstop = 1;
902f43998fdSpjanzen }
903f43998fdSpjanzen 
904f43998fdSpjanzen void
suspend(void)905ff8320a7Sderaadt suspend(void)
906f43998fdSpjanzen {
907fa24ff78Spjanzen 	endwin();
908f43998fdSpjanzen 	kill(getpid(), SIGTSTP);
909fa24ff78Spjanzen 	refresh();
910f43998fdSpjanzen 	winnings(cashvalue);
911f43998fdSpjanzen }
912f43998fdSpjanzen 
913f43998fdSpjanzen void
length(int num)914ff8320a7Sderaadt length(int num)
915f43998fdSpjanzen {
916f43998fdSpjanzen 	printf("You made %d moves.\n", num);
917f43998fdSpjanzen }
918f43998fdSpjanzen 
919f527bb56Stb void
snscore(int topn)920565945afSmestre snscore(int topn)
921f527bb56Stb {
922f527bb56Stb 	int i;
923f527bb56Stb 
924f527bb56Stb 	if (nscores == 0)
925f527bb56Stb 		return;
926f527bb56Stb 
927f527bb56Stb 	printf("%sSnake scores to date:\n", topn > 0 ? "Top " : "");
928f527bb56Stb 	for (i = 0; i < nscores; i++)
929f527bb56Stb 		printf("%2d.\t$%d\t%s\n", i+1, scores[i].score, scores[i].name);
930f527bb56Stb }
931f527bb56Stb 
932f43998fdSpjanzen #ifdef LOGGING
933f43998fdSpjanzen void
logit(char * msg)934ff8320a7Sderaadt logit(char *msg)
935f43998fdSpjanzen {
936f43998fdSpjanzen 	time_t t;
937f43998fdSpjanzen 
938f43998fdSpjanzen 	if (logfile != NULL) {
939f43998fdSpjanzen 		time(&t);
940f43998fdSpjanzen 		fprintf(logfile, "%s $%d %dx%d %s %s",
941f43998fdSpjanzen 		    getlogin(), cashvalue, lcnt, ccnt, msg, ctime(&t));
942fa24ff78Spjanzen 		fflush(logfile);
943f43998fdSpjanzen 	}
944f43998fdSpjanzen }
945f43998fdSpjanzen #endif
946f527bb56Stb 
947f527bb56Stb int
readscores(int create)948f527bb56Stb readscores(int create)
949f527bb56Stb {
950f527bb56Stb 	const char	*home;
951fa83b613Stb 	const char	*name;
952f527bb56Stb 	const char	*modstr;
953f527bb56Stb 	int		 modint;
954f527bb56Stb 	int		 ret;
955f527bb56Stb 
956f527bb56Stb 	if (create == 0) {
957f527bb56Stb 		modint = O_RDONLY;
958f527bb56Stb 		modstr = "r";
959f527bb56Stb 	} else {
960f527bb56Stb 		modint = O_RDWR | O_CREAT;
961f527bb56Stb 		modstr = "r+";
962f527bb56Stb 	}
963f527bb56Stb 
964f527bb56Stb 	home = getenv("HOME");
965f527bb56Stb 	if (home == NULL || *home == '\0')
966f527bb56Stb 		err(1, "getenv");
967f527bb56Stb 
968f527bb56Stb 	ret = snprintf(scorepath, sizeof(scorepath), "%s/%s", home,
969f527bb56Stb 	    ".snake.scores");
970f527bb56Stb 	if (ret < 0 || ret >= PATH_MAX)
971f527bb56Stb 		errc(1, ENAMETOOLONG, "%s/%s", home, ".snake.scores");
972f527bb56Stb 
973f527bb56Stb 	rawscores = open(scorepath, modint, 0666);
974*df69c215Sderaadt 	if (rawscores == -1) {
975f527bb56Stb 		if (create == 0)
976f527bb56Stb 			return 0;
977f527bb56Stb 		err(1, "cannot open %s", scorepath);
978f527bb56Stb 	}
979f527bb56Stb 	if ((sf = fdopen(rawscores, modstr)) == NULL)
980f527bb56Stb 		err(1, "cannot fdopen %s", scorepath);
981f527bb56Stb 	nscores = fread(scores, sizeof(scores[0]), TOPN, sf);
982f527bb56Stb 	if (ferror(sf))
983f527bb56Stb 		err(1, "error reading %s", scorepath);
984f527bb56Stb 
985fa83b613Stb 	name = getenv("LOGNAME");
986fa83b613Stb 	if (name == NULL || *name == '\0')
987fa83b613Stb 		name = getenv("USER");
988fa83b613Stb 	if (name == NULL || *name == '\0')
989fa83b613Stb 		name = getlogin();
990fa83b613Stb 	if (name == NULL || *name == '\0')
991fa83b613Stb 		name = "  ???";
992f527bb56Stb 
993f527bb56Stb 	if (nscores > TOPN)
994f527bb56Stb 		nscores = TOPN;
995fa83b613Stb 	strlcpy(scores[nscores].name, name, sizeof(scores[nscores].name));
996f527bb56Stb 	scores[nscores].score = 0;
997f527bb56Stb 
998f527bb56Stb 	return 1;
999f527bb56Stb }
1000