]>
git.cameronkatri.com Git - bsdgames-darwin.git/blob - snake/snake/snake.c
1 /* $NetBSD: snake.c,v 1.6 1995/04/22 10:18:17 cgd 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
37 static char copyright
[] =
38 "@(#) 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 static char rcsid
[] = "$NetBSD: snake.c,v 1.6 1995/04/22 10:18:17 cgd 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>
70 #include "pathnames.h"
72 #define PENALTY 10 /* % penalty for invoking spacewarp */
89 struct point snake
[6];
97 char *kl
, *kr
, *ku
, *kd
;
115 while ((ch
= getopt(argc
, argv
, "l:w:")) != EOF
)
122 case 'w': /* width */
125 case 'l': /* length */
130 fputs("usage: snake [-d seed] [-w width] [-l length]\n", stderr
);
140 pr("snake: screen too small for a fair game.\n");
145 * chunk is the amount of money the user gets for each $.
146 * The formula below tries to be fair for various screen sizes.
147 * We only pay attention to the smaller of the 2 edges, since
148 * that seems to be the bottleneck.
149 * This formula is a hyperbola which includes the following points:
150 * (24, $25) (original scoring algorithm)
151 * (12, $40) (experimentally derived by the "feel")
152 * (48, $15) (a guess)
153 * This will give a 4x4 screen $99/shot. We don't allow anything
154 * smaller than 4x4 because there is a 3x3 game where you can win
155 * an infinite amount of money.
157 if (i
< 12) i
= 12; /* otherwise it isn't fair */
159 * Compensate for border. This really changes the game since
160 * the screen is two squares smaller but we want the default
161 * to be $25, and the high scores on small screens were a bit
165 chunk
= (675.0 / (i
+6)) + 2.5; /* min screen edge */
167 signal (SIGINT
, stop
);
168 putpad(TI
); /* String to begin programs that use cm */
169 putpad(KS
); /* Put terminal in keypad transmit mode */
176 if ((orig
.sg_ospeed
< B9600
) ||
177 ((! CM
) && (! TA
))) fast
=0;
179 chase (&snake
[i
], &snake
[i
-1]);
184 /* Main command loop */
194 if (((c
= getchar() & 0177) <= '9') && (c
>= '0')) {
196 j
= scanf("%d",&repeat
);
197 c
= getchar() & 0177;
199 if (c
!= '.') repeat
= 1;
205 (c
== *KL
|| c
== *KR
|| c
== *KU
|| c
== *KD
)) {
212 for (j
=Klength
;j
>0;j
--){
235 * This works if we figure it out on second character.
241 if(j
!= 1) c
= getchar() & 0177;
253 case 0177: /* del or end of file */
275 repeat
= you
.col
- money
.col
;
284 repeat
= you
.line
- money
.line
;
288 repeat
= ccnt
- 1 - you
.col
;
293 repeat
= money
.col
- you
.col
;
297 repeat
= lcnt
- 1 - you
.line
;
302 repeat
= money
.line
- you
.line
;
306 for(k
=1;k
<=repeat
;k
++){
316 if((fast
) || (k
== repeat
) ||
324 if (you
.col
< ccnt
-1) {
328 if((fast
) || (k
== repeat
) ||
341 if((fast
) || (k
== repeat
) ||
351 if (you
.line
+1 < lcnt
) {
355 if((fast
) || (k
== repeat
) ||
356 (you
.line
== lcnt
-1))
362 if (same(&you
,&money
))
371 } while (money
.col
== finish
.col
&& money
.line
== finish
.line
||
372 money
.col
< 5 && money
.line
== 0 ||
373 money
.col
== you
.col
&& money
.line
== you
.line
);
374 pchar(&money
,TREASURE
);
378 if (same(&you
,&finish
))
383 pr("You have won with $%d.\n",cashvalue
);
390 if (pushsnake())break;
404 pchar(&money
,TREASURE
);
406 pchar(&snake
[i
],SNAKETAIL
);
408 pchar(&snake
[0], SNAKEHEAD
);
419 for (i
= 0; i
<ccnt
; i
++) {
424 for (i
= -1; i
<=lcnt
; i
++) {
429 for (i
= -1; i
<=lcnt
; i
++) {
434 for (i
= 0; i
<ccnt
; i
++) {
447 p
.col
= random() % ccnt
;
448 p
.line
= random() % lcnt
;
450 /* make sure it's not on top of something else */
451 if (p
.line
== 0 && p
.col
< 5)
455 if (same(&p
, &money
))
457 if (same(&p
, &finish
))
459 for (i
= 0; i
< 5; i
++)
460 if (same(&p
, &snake
[i
]))
472 short score
= iscore
;
476 short allbwho
=0, allbscore
=0;
480 * Neg uid, 0, and 1 cannot have scores recorded.
482 if ((uid
= getuid()) <= 1) {
483 pr("No saved scores for uid %d.\n", uid
);
486 if ((rawscores
= open(_PATH_RAWSCORES
, O_RDWR
|O_CREAT
, 0644)) < 0) {
487 pr("No score file %s: %s.\n", _PATH_RAWSCORES
,
491 /* Figure out what happened in the past */
492 read(rawscores
, &allbscore
, sizeof(short));
493 read(rawscores
, &allbwho
, sizeof(short));
494 lseek(rawscores
, uid
*sizeof(short), 0);
495 read(rawscores
, &oldbest
, sizeof(short));
497 return (score
> oldbest
? 1 : 0);
499 /* Update this jokers best */
500 if (score
> oldbest
) {
501 lseek(rawscores
, uid
*sizeof(short), 0);
502 write(rawscores
, &score
, sizeof(short));
503 pr("You bettered your previous best of $%d\n", oldbest
);
505 pr("Your best to date is $%d\n", oldbest
);
507 /* See if we have a new champ */
508 p
= getpwuid(allbwho
);
509 if (p
== NULL
|| score
> allbscore
) {
510 lseek(rawscores
, 0, 0);
511 write(rawscores
, &score
, sizeof(short));
512 write(rawscores
, &uid
, sizeof(short));
514 pr("You beat %s's old record of $%d!\n",
515 p
->pw_name
, allbscore
);
517 pr("You set a new record!\n");
519 pr("The highest is %s with $%d\n", p
->pw_name
, allbscore
);
525 * Flush typeahead to keep from buffering a bunch of chars and then
526 * overshooting. This loses horribly at 9600 baud, but works nicely
527 * if the terminal gets behind.
534 0, 1, 1, 1, 0,-1,-1,-1};
536 -1,-1, 0, 1, 1, 1, 0,-1};
538 1, 1.4, 1, 1.4, 1, 1.4, 1, 1.4
542 struct point
*sp
, *np
;
544 /* this algorithm has bugs; otherwise the
545 snake would get too good */
548 double v1
, v2
, vp
, max
;
549 point(&d
,you
.col
-sp
->col
,you
.line
-sp
->line
);
550 v1
= sqrt( (double) (d
.col
*d
.col
+ d
.line
*d
.line
) );
555 vp
= d
.col
*mx
[i
] + d
.line
*my
[i
];
558 vp
= ((double)vp
)/(v1
*v2
);
568 point(&d
,sp
->col
+mx
[i
],sp
->line
+my
[i
]);
570 if (d
.col
<0 || d
.col
>=ccnt
|| d
.line
<0 || d
.line
>=lcnt
)
573 * Change to allow snake to eat you if you're on the money,
574 * otherwise, you can just crouch there until the snake goes
575 * away. Not positive it's right.
577 * if (d.line == 0 && d.col < 5) continue;
579 if (same(&d
,&money
)) continue;
580 if (same(&d
,&finish
)) continue;
581 wt
[i
]= i
==w
? loot
/10 : 1;
582 if (i
==oldw
) wt
[i
] += loot
/20;
586 vp
= (( rand() >> 6 ) & 01777) %w
;
595 while (wt
[i
]==0) i
++;
598 point(np
,sp
->col
+mx
[w
],sp
->line
+my
[w
]);
608 point(&p
,COLUMNS
/2 - 8,LINES
/2 - 1);
615 loot
= loot
- penalty
;
618 str
= "SPACE WARP!!!";
619 penalty
+= loot
/PENALTY
;
636 pchar(point(&p
,you
.col
,0),'-');
638 if(you
.line
> lcnt
-4){
639 pchar(point(&p
,you
.col
,lcnt
-1),'_');
642 pchar(point(&p
,0,you
.line
),'(');
644 if(you
.col
> ccnt
-10){
645 pchar(point(&p
,ccnt
-1,you
.line
),')');
647 if (! stretch(&money
)) if (! stretch(&finish
)) delay(10);
652 if(you
.line
> lcnt
-4){
653 point(&p
,you
.col
,lcnt
-1);
657 point(&p
,0,you
.line
);
660 if(you
.col
> ccnt
-10){
661 point(&p
,ccnt
-1,you
.line
);
670 point(&p
,you
.col
,you
.line
);
671 if(abs(ps
->col
-you
.col
) < 6){
672 if(you
.line
< ps
->line
){
673 for (p
.line
= you
.line
+1;p
.line
<= ps
->line
;p
.line
++)
676 for (;p
.line
> you
.line
;p
.line
--)
679 for (p
.line
= you
.line
-1;p
.line
>= ps
->line
;p
.line
--)
682 for (;p
.line
< you
.line
;p
.line
++)
686 } else if(abs(ps
->line
-you
.line
) < 3){
688 if(you
.col
< ps
->col
){
689 for (p
.col
= you
.col
+1;p
.col
<= ps
->col
;p
.col
++)
692 for (;p
.col
> you
.col
;p
.col
--)
695 for (p
.col
= you
.col
-1;p
.col
>= ps
->col
;p
.col
--)
698 for (;p
.col
< you
.col
;p
.col
++)
711 if(ps
->col
== 0)ps
->col
++;
712 if(ps
->line
== 0)ps
->line
++;
713 if(ps
->line
== LINES
-1)ps
->line
--;
714 if(ps
->col
== COLUMNS
-1)ps
->col
--;
715 apr(point(&x
,ps
->col
-1,ps
->line
-1),"/*\\\r* *\r\\*/");
722 if (post(cashvalue
,0)) {
723 apr(point(&x
,ps
->col
-1,ps
->line
-1)," \ro.o\r\\_/");
725 apr(point(&x
,ps
->col
-1,ps
->line
-1)," \ro.-\r\\_/");
728 apr(point(&x
,ps
->col
-1,ps
->line
-1)," \ro.o\r\\_/");
735 int boxsize
; /* actually diameter of box, not radius */
737 boxsize
= fast
? 10 : 4;
738 point(&x
,ps
->col
,ps
->line
);
739 for(j
=1;j
<boxsize
;j
++){
767 * My manual says times doesn't return a value. Furthermore, the
768 * snake should get his turn every time no matter if the user is
769 * on a fast terminal with typematic keys or not.
770 * So I have taken the call to times out.
773 if (same(&snake
[i
], &snake
[5]))
776 pchar(&snake
[5],' ');
778 snake
[i
+1]= snake
[i
];
779 chase(&snake
[0], &snake
[1]);
780 pchar(&snake
[1],SNAKETAIL
);
781 pchar(&snake
[0],SNAKEHEAD
);
784 if (same(&snake
[i
],&you
))
787 i
= (cashvalue
) % 10;
788 bonus
= ((rand()>>8) & 0377)% 10;
798 if ( loot
>= penalty
){
799 pr("You and your $%d have been eaten\n",
802 pr("The snake ate you. You owe $%d.\n",
818 if (same(sp
,&money
)) {
822 if (same(sp
,&finish
)) {
826 if (same(sp
,&snake
[0])) {
831 if(same(sp
,&snake
[j
])){
836 if ((sp
->col
< 4) && (sp
->line
== 0)){
838 if((you
.line
== 0) && (you
.col
< 4)) pchar(&you
,ME
);
862 signal(SIGINT
,SIG_IGN
);
874 kill(getpid(), SIGTSTP
);
883 pr("You made %d moves.\n",num
);
892 if ((logfile
=fopen(_PATH_LOGFILE
, "a")) != NULL
) {
894 fprintf(logfile
, "%s $%d %dx%d %s %s",
895 getlogin(), cashvalue
, lcnt
, ccnt
, msg
, ctime(&t
));