]>
git.cameronkatri.com Git - bsdgames-darwin.git/blob - snake/snake/snake.c
49507b594643386cd763e5ef3a73bda5b87ede3d
1 /* $NetBSD: snake.c,v 1.10 1999/09/08 21:17:59 jsm Exp $ */
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <sys/cdefs.h>
38 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\n\
39 The Regents of the University of California. All rights reserved.\n");
44 static char sccsid
[] = "@(#)snake.c 8.2 (Berkeley) 1/7/94";
46 __RCSID("$NetBSD: snake.c,v 1.10 1999/09/08 21:17:59 jsm Exp $");
51 * snake - crt hack game.
53 * You move around the screen with arrow keys trying to pick up money
54 * without getting eaten by the snake. hjkl work as in vi in place of
55 * arrow keys. You can leave at the exit any time.
58 * cc -O snake.c move.c -o snake -lm -ltermlib
61 #include <sys/param.h>
71 #include "pathnames.h"
73 #define PENALTY 10 /* % penalty for invoking spacewarp */
90 struct point snake
[6];
98 char *kl
, *kr
, *ku
, *kd
;
104 int main
__P((int, char **));
118 while ((ch
= getopt(argc
, argv
, "l:w:")) != -1)
125 case 'w': /* width */
128 case 'l': /* length */
133 fputs("usage: snake [-d seed] [-w width] [-l length]\n", stderr
);
143 pr("snake: screen too small for a fair game.\n");
147 * chunk is the amount of money the user gets for each $.
148 * The formula below tries to be fair for various screen sizes.
149 * We only pay attention to the smaller of the 2 edges, since
150 * that seems to be the bottleneck.
151 * This formula is a hyperbola which includes the following points:
152 * (24, $25) (original scoring algorithm)
153 * (12, $40) (experimentally derived by the "feel")
154 * (48, $15) (a guess)
155 * This will give a 4x4 screen $99/shot. We don't allow anything
156 * smaller than 4x4 because there is a 3x3 game where you can win
157 * an infinite amount of money.
160 i
= 12; /* otherwise it isn't fair */
162 * Compensate for border. This really changes the game since
163 * the screen is two squares smaller but we want the default
164 * to be $25, and the high scores on small screens were a bit
168 chunk
= (675.0 / (i
+ 6)) + 2.5; /* min screen edge */
170 signal(SIGINT
, stop
);
171 putpad(TI
); /* String to begin programs that use cm */
172 putpad(KS
); /* Put terminal in keypad transmit mode */
179 if (ospeed
< 9600 || ((!CM
) && (!TA
)))
181 for (i
= 1; i
< 6; i
++)
182 chase(&snake
[i
], &snake
[i
- 1]);
189 /* Main command loop */
201 if (((c
= getchar() & 0177) <= '9') && (c
>= '0')) {
203 j
= scanf("%d", &repeat
);
204 c
= getchar() & 0177;
213 (c
== *KL
|| c
== *KR
|| c
== *KU
|| c
== *KD
)) {
220 for (j
= Klength
; j
> 0; j
--) {
242 /* Oops! This works if we
243 * figure it out on second
250 c
= getchar() & 0177;
263 case 0177: /* del or end of file */
285 repeat
= you
.col
- money
.col
;
294 repeat
= you
.line
- money
.line
;
298 repeat
= ccnt
- 1 - you
.col
;
303 repeat
= money
.col
- you
.col
;
307 repeat
= lcnt
- 1 - you
.line
;
312 repeat
= money
.line
- you
.line
;
316 for (k
= 1; k
<= repeat
; k
++) {
323 if ((fast
) || (k
== 1))
326 if ((fast
) || (k
== repeat
) ||
334 if (you
.col
< ccnt
- 1) {
335 if ((fast
) || (k
== 1))
338 if ((fast
) || (k
== repeat
) ||
339 (you
.col
== ccnt
- 1))
348 if ((fast
) || (k
== 1))
351 if ((fast
) || (k
== repeat
) ||
361 if (you
.line
+ 1 < lcnt
) {
362 if ((fast
) || (k
== 1))
365 if ((fast
) || (k
== repeat
) ||
366 (you
.line
== lcnt
- 1))
372 if (same(&you
, &money
)) {
378 } while ((money
.col
== finish
.col
&&
379 money
.line
== finish
.line
) ||
380 (money
.col
< 5 && money
.line
== 0) ||
381 (money
.col
== you
.col
&&
382 money
.line
== you
.line
));
383 pchar(&money
, TREASURE
);
387 if (same(&you
, &finish
)) {
391 pr("You have won with $%d.\n", cashvalue
);
415 pchar(&finish
, GOAL
);
416 pchar(&money
, TREASURE
);
417 for (i
= 1; i
< 6; i
++) {
418 pchar(&snake
[i
], SNAKETAIL
);
420 pchar(&snake
[0], SNAKEHEAD
);
432 for (i
= 0; i
< ccnt
; i
++) {
437 for (i
= -1; i
<= lcnt
; i
++) {
442 for (i
= -1; i
<= lcnt
; i
++) {
447 for (i
= 0; i
< ccnt
; i
++) {
461 p
.col
= random() % ccnt
;
462 p
.line
= random() % lcnt
;
464 /* make sure it's not on top of something else */
465 if (p
.line
== 0 && p
.col
< 5)
469 if (same(&p
, &money
))
471 if (same(&p
, &finish
))
473 for (i
= 0; i
< 5; i
++)
474 if (same(&p
, &snake
[i
]))
487 short score
= iscore
;
491 short allbwho
= 0, allbscore
= 0;
495 * Neg uid, 0, and 1 cannot have scores recorded.
497 if ((uid
= getuid()) <= 1) {
498 pr("No saved scores for uid %d.\n", uid
);
501 if ((rawscores
= open(_PATH_RAWSCORES
, O_RDWR
| O_CREAT
, 0644)) < 0) {
502 pr("No score file %s: %s.\n", _PATH_RAWSCORES
,
506 /* Figure out what happened in the past */
507 read(rawscores
, &allbscore
, sizeof(short));
508 read(rawscores
, &allbwho
, sizeof(short));
509 lseek(rawscores
, uid
* sizeof(short), 0);
510 read(rawscores
, &oldbest
, sizeof(short));
512 return (score
> oldbest
? 1 : 0);
514 /* Update this jokers best */
515 if (score
> oldbest
) {
516 lseek(rawscores
, uid
* sizeof(short), 0);
517 write(rawscores
, &score
, sizeof(short));
518 pr("You bettered your previous best of $%d\n", oldbest
);
520 pr("Your best to date is $%d\n", oldbest
);
522 /* See if we have a new champ */
523 p
= getpwuid(allbwho
);
524 if (p
== NULL
|| score
> allbscore
) {
525 lseek(rawscores
, 0, 0);
526 write(rawscores
, &score
, sizeof(short));
527 write(rawscores
, &uid
, sizeof(short));
529 pr("You beat %s's old record of $%d!\n",
530 p
->pw_name
, allbscore
);
532 pr("You set a new record!\n");
534 pr("The highest is %s with $%d\n", p
->pw_name
, allbscore
);
540 * Flush typeahead to keep from buffering a bunch of chars and then
541 * overshooting. This loses horribly at 9600 baud, but works nicely
542 * if the terminal gets behind.
547 tcflush(0, TCIFLUSH
);
551 0, 1, 1, 1, 0, -1, -1, -1
554 -1, -1, 0, 1, 1, 1, 0, -1
556 const float absv
[8] = {
557 1, 1.4, 1, 1.4, 1, 1.4, 1, 1.4
563 struct point
*sp
, *np
;
565 /* this algorithm has bugs; otherwise the snake would get too good */
568 double v1
, v2
, vp
, max
;
569 point(&d
, you
.col
- sp
->col
, you
.line
- sp
->line
);
570 v1
= sqrt((double) (d
.col
* d
.col
+ d
.line
* d
.line
));
573 for (i
= 0; i
< 8; i
++) {
574 vp
= d
.col
* mx
[i
] + d
.line
* my
[i
];
577 vp
= ((double) vp
) / (v1
* v2
);
585 for (i
= 0; i
< 8; i
++) {
586 point(&d
, sp
->col
+ mx
[i
], sp
->line
+ my
[i
]);
588 if (d
.col
< 0 || d
.col
>= ccnt
|| d
.line
< 0 || d
.line
>= lcnt
)
591 * Change to allow snake to eat you if you're on the money,
592 * otherwise, you can just crouch there until the snake goes
593 * away. Not positive it's right.
595 * if (d.line == 0 && d.col < 5) continue;
597 if (same(&d
, &money
))
599 if (same(&d
, &finish
))
601 wt
[i
] = i
== w
? loot
/ 10 : 1;
605 for (w
= i
= 0; i
< 8; i
++)
607 vp
= ((rand() >> 6) & 01777) % w
;
608 for (i
= 0; i
< 8; i
++)
620 point(np
, sp
->col
+ mx
[w
], sp
->line
+ my
[w
]);
632 point(&p
, COLUMNS
/ 2 - 8, LINES
/ 2 - 1);
639 loot
= loot
- penalty
;
642 str
= "SPACE WARP!!!";
643 penalty
+= loot
/ PENALTY
;
645 for (j
= 0; j
< 3; j
++) {
661 pchar(point(&p
, you
.col
, 0), '-');
663 if (you
.line
> lcnt
- 4) {
664 pchar(point(&p
, you
.col
, lcnt
- 1), '_');
667 pchar(point(&p
, 0, you
.line
), '(');
669 if (you
.col
> ccnt
- 10) {
670 pchar(point(&p
, ccnt
- 1, you
.line
), ')');
672 if (!stretch(&money
))
673 if (!stretch(&finish
))
676 point(&p
, you
.col
, 0);
679 if (you
.line
> lcnt
- 4) {
680 point(&p
, you
.col
, lcnt
- 1);
684 point(&p
, 0, you
.line
);
687 if (you
.col
> ccnt
- 10) {
688 point(&p
, ccnt
- 1, you
.line
);
696 const struct point
*ps
;
700 point(&p
, you
.col
, you
.line
);
701 if (abs(ps
->col
- you
.col
) < 6) {
702 if (you
.line
< ps
->line
) {
703 for (p
.line
= you
.line
+ 1; p
.line
<= ps
->line
;
707 for (; p
.line
> you
.line
; p
.line
--)
710 for (p
.line
= you
.line
- 1; p
.line
>= ps
->line
;
714 for (; p
.line
< you
.line
; p
.line
++)
719 if (abs(ps
->line
- you
.line
) < 3) {
721 if (you
.col
< ps
->col
) {
722 for (p
.col
= you
.col
+ 1; p
.col
<= ps
->col
;
726 for (; p
.col
> you
.col
; p
.col
--)
729 for (p
.col
= you
.col
- 1; p
.col
>= ps
->col
;
733 for (; p
.col
< you
.col
; p
.col
++)
752 if (ps
->line
== LINES
- 1)
754 if (ps
->col
== COLUMNS
- 1)
756 apr(point(&x
, ps
->col
- 1, ps
->line
- 1), "/*\\\r* *\r\\*/");
757 for (j
= 0; j
< 20; j
++) {
763 if (post(cashvalue
, 0)) {
764 apr(point(&x
, ps
->col
- 1, ps
->line
- 1), " \ro.o\r\\_/");
766 apr(point(&x
, ps
->col
- 1, ps
->line
- 1), " \ro.-\r\\_/");
769 apr(point(&x
, ps
->col
- 1, ps
->line
- 1), " \ro.o\r\\_/");
774 const struct point
*ps
;
778 int boxsize
; /* actually diameter of box, not radius */
780 boxsize
= fast
? 10 : 4;
781 point(&x
, ps
->col
, ps
->line
);
782 for (j
= 1; j
< boxsize
; j
++) {
783 for (k
= 0; k
< j
; k
++) {
787 for (k
= 0; k
< j
; k
++) {
792 for (k
= 0; k
< j
; k
++) {
796 for (k
= 0; k
< j
; k
++) {
811 * My manual says times doesn't return a value. Furthermore, the
812 * snake should get his turn every time no matter if the user is
813 * on a fast terminal with typematic keys or not.
814 * So I have taken the call to times out.
816 for (i
= 4; i
>= 0; i
--)
817 if (same(&snake
[i
], &snake
[5]))
820 pchar(&snake
[5], ' ');
821 for (i
= 4; i
>= 0; i
--)
822 snake
[i
+ 1] = snake
[i
];
823 chase(&snake
[0], &snake
[1]);
824 pchar(&snake
[1], SNAKETAIL
);
825 pchar(&snake
[0], SNAKEHEAD
);
826 for (i
= 0; i
< 6; i
++) {
827 if (same(&snake
[i
], &you
)) {
829 i
= (cashvalue
) % 10;
830 bonus
= ((rand() >> 8) & 0377) % 10;
840 if (loot
>= penalty
) {
841 pr("You and your $%d have been eaten\n",
844 pr("The snake ate you. You owe $%d.\n",
857 const struct point
*sp
;
861 if (same(sp
, &money
)) {
865 if (same(sp
, &finish
)) {
869 if (same(sp
, &snake
[0])) {
870 pchar(sp
, SNAKEHEAD
);
873 for (j
= 1; j
< 6; j
++) {
874 if (same(sp
, &snake
[j
])) {
875 pchar(sp
, SNAKETAIL
);
879 if ((sp
->col
< 4) && (sp
->line
== 0)) {
881 if ((you
.line
== 0) && (you
.col
< 4))
885 if (same(sp
, &you
)) {
910 signal(SIGINT
, SIG_IGN
);
921 kill(getpid(), SIGTSTP
);
931 pr("You made %d moves.\n", num
);
941 if ((logfile
= fopen(_PATH_LOGFILE
, "a")) != NULL
) {
943 fprintf(logfile
, "%s $%d %dx%d %s %s",
944 getlogin(), cashvalue
, lcnt
, ccnt
, msg
, ctime(&t
));