games@tekred.CNA.TEK.COM (03/22/89)
Submitted-by: gwyn%smoke.brl.mil@CUNYVM.CUNY.EDU (Doug Gwyn)
Posting-number: Volume 6, Issue 30
Archive-name: crabs
[This program is display device specific. I don't have either
of these guys so I couldn't try it out - you're on your own. -br]
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of shell archive."
# Contents: crabs.c
# Wrapped by billr@saab on Tue Mar 21 10:44:38 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'crabs.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'crabs.c'\"
else
echo shar: Extracting \"'crabs.c'\" \(12000 characters\)
sed "s/^X//" >'crabs.c' <<'END_OF_FILE'
X/*
X crabs -- see September 1985 Scientific American pages 18..23
X
X last edit: 89/02/25 D A Gwyn
X
X SCCS ID: @(#)crabs.c 1.3 for 5620 DMD and 630 MTG
X
XTo compile:
X $ dmdcc -o crabs.m crabs.c # -g -O also recommended
X
XTo run:
X $ dmdld crabs.m # runs only in mpx mode
Xor
X $ dmdld crabs.m - # for invisible crabs
X*/
X
X#ifndef lint
Xstatic char SCCS_ID[] = "@(#)crabs.c 1.3 89/02/25"; /* for "what"
X utility */
X#endif
X
X
X#include <dmd.h>
X
X#ifdef DMD630
X
X#define texture16 texture
X
X#else /* 5620 */
X
Xstatic Texture16 T_background = /* background texture */
X {
X 0x1111, 0x4444, 0x1111, 0x4444,
X 0x1111, 0x4444, 0x1111, 0x4444,
X 0x1111, 0x4444, 0x1111, 0x4444,
X 0x1111, 0x4444, 0x1111, 0x4444
X };
X
Xstatic Bitmap physical = /* full screen definition */
X {
X (Word *)0x700000L, /* DMD screen image base address */
X (XMAX + 31) / 32, /* bitmap width in 32-bit Words */
X 0, 0, XMAX, YMAX /* screen rectangle within bitmap */
X };
X
X#endif
X
X
X#define NCRABS 32 /* total number of crabs (1..32) */
X
X#define MAXVEL 8 /* abs. bound on velocity component */
X
X#define PERIOD 2 /* sleep time (ticks) per cycle */
X
X
Xtypedef int bool; /* Boolean data type */
X#define false 0
X#define true 1
X
X
Xstatic bool visible; /* true if crabs are to be shown */
X
Xstatic struct
X {
X Point ulc; /* upper left corner screen coords */
X Point vel; /* velocity (pixels/cycle) */
X } crab[NCRABS]; /* keeps track of crabs' state */
X/* We rely on this forcing the following arrays to be Word-aligned! */
X
X/* There are 4 possible crab orientations, each of which
X has 4 possible relationships with the grey background.
X (Scientific American article says 8, but it's wrong.) */
X
X/* Crab images XORed with grey background texture at various offsets: */
X
Xstatic short upcrab[] = /* facing up */
X {
X 0x6E4C, 0x2A66,
X 0xB377, 0xE6D5,
X 0x8081, 0x8101,
X 0xB935, 0xAC9D,
X 0x6E5C, 0x3A76,
X 0x3A76, 0x6E5C,
X 0xAC9D, 0xB935,
X 0x0242, 0x4240
X };
X
Xstatic short downcrab[] = /* facing down */
X {
X 0x4240, 0x0242,
X 0xB935, 0xAC9D,
X 0x6E5C, 0x3A76,
X 0x3A76, 0x6E5C,
X 0xAC9D, 0xB935,
X 0x8101, 0x8081,
X 0xEECD, 0xAB67,
X 0x3276, 0x6654
X };
X
Xstatic short rightcrab[] = /* facing right */
X {
X 0x4E4C, 0x0A46,
X 0xB333, 0xA291,
X 0x6A59, 0x3B73,
X 0x3A72, 0x6A58,
X 0x6859, 0x3971,
X 0x3B73, 0x6A59,
X 0xA291, 0xB333,
X 0x0A46, 0x4E4C
X };
X
Xstatic short leftcrab[] = /* facing left */
X {
X 0x6250, 0x3272,
X 0x8945, 0xCCCD,
X 0xCEDC, 0x9A56,
X 0x9A16, 0x8E9C,
X 0x4E5C, 0x1A56,
X 0x9A56, 0xCEDC,
X 0xCCCD, 0x8945,
X 0x3272, 0x6250
X };
X
X/* The bitmaps for the four orientations: */
X
Xstatic Bitmap upmap = { (Word *)upcrab, 32/WORDSIZE, 0, 0, 32, 8 };
Xstatic Bitmap downmap = { (Word *)downcrab, 32/WORDSIZE, 0, 0, 32, 8 };
Xstatic Bitmap rightmap = { (Word *)rightcrab, 32/WORDSIZE, 0, 0, 32, 8 };
Xstatic Bitmap leftmap = { (Word *)leftcrab, 32/WORDSIZE, 0, 0, 32, 8 };
X
X/* Crab "vicinities" are recorded in the following
X global map; see Collide() and Draw() for details: */
X
Xstatic long vicinity[(XMAX + 31) / 32 + 2][(YMAX + 31) / 32 + 2];
X /* includes margins all around */
X
Xstatic void Cycle(), DrawCrab(), HideCrabs(), Init(), ModVel(), NewVel();
Xstatic int RandInt();
Xstatic long Collide();
X
Xmain( argc, argv )
X int argc;
X char *argv[];
X {
X Init( argc, argv ); /* set up initial grey crab layer */
X
X for ( ; ; ) /* no way out! */
X {
X sleep( PERIOD ); /* relinquish the processor */
X
X Cycle(); /* move the crabs */
X }
X /*NOTREACHED*/
X }
X
X
Xstatic void
XInit( argc, argv ) /* set up initial crab layer */
X int argc;
X char *argv[];
X {
X int i; /* crab # */
X
X visible = argc <= 1; /* default is to show crabs */
X
X texture16( &display, display.rect, &T_background, F_STORE );
X /* crab layer */
X
X /* Create initial set of crabs: */
X
X for ( i = 0; i < NCRABS; ++i )
X {
X /* Assign random position within "crabs" layer: */
X
X crab[i].ulc.x = RandInt( display.rect.origin.x,
X display.rect.corner.x - 8
X );
X crab[i].ulc.y = RandInt( display.rect.origin.y,
X display.rect.corner.y - 8
X );
X
X /* Assign random velocity: */
X
X NewVel( i );
X
X /* Draw crab at initial position (within "crabs" layer): */
X
X if ( visible )
X DrawCrab( i );
X }
X
X/* DEBUG
X display.rect.corner = display.rect.origin; /* make unpickable */
X }
X
X
Xstatic void
XCycle() /* one motion cycle for all crabs */
X {
X static long old[8]; /* old contents of new crab position */
X static Bitmap oldmap = { (Word *)old, 32/WORDSIZE, 0, 0, 8, 8 };
X Point p; /* new crab upper left corner */
X Rectangle r; /* new crab area */
X long syndrome; /* crab collision mask */
X int i; /* crab # */
X int w; /* index for old[.] */
X
X for ( i = 0; i < NCRABS; ++i )
X {
X DrawCrab( i ); /* erase crab from previous position */
X
X for ( ; ; ) /* determine a new position */
X {
X p.x = crab[i].ulc.x + crab[i].vel.x; /* motion */
X p.y = crab[i].ulc.y + crab[i].vel.y;
X
X if ( p.x >= 0 && p.x < XMAX - 8
X && p.y >= 0 && p.y < YMAX - 8
X )
X break; /* on-screen, proceed */
X
X /* Bounce off edge of screen: */
X
X NewVel( i ); /* assign new velocity */
X }
X
X r.origin = p;
X r.corner.x = p.x + 8;
X r.corner.y = p.y + 8;
X
X /* Check for collision with other crabs;
X if you don't worry about this, you get
X crud left behind from crab collisions
X (visible in Scientific American article).
X (Note that crab # i has been removed.) */
X
X /* The strategy is: only undraw possibly colliding crabs.
X The obvious alternative, not showing any crabs until
X all locations have been painted, would probably cause
X the set of crabs to flicker or to appear too faint. */
X
X if ( (syndrome = Collide( p )) != 0L )
X HideCrabs( syndrome ); /* save from following code */
X
X /* Save old contents of new crab location: */
X
X bitblt( &physical, r, &oldmap, Pt( 0, 0 ), F_STORE );
X
X /* Paint the new location grey: */
X
X texture16( &physical, r, &T_background, F_STORE );
X
X /* Determine if new location used to be grey: */
X
X bitblt( &physical, r, &oldmap, Pt( 0, 0 ), F_XOR );
X
X for ( w = 0; w < 8; ++w )
X if ( old[w] != 0L )
X { /* this location has been nibbled */
X p = crab[i].ulc; /* reset position */
X
X NewVel( i ); /* bounce away from bite */
X
X break;
X }
X
X if ( syndrome != 0L )
X HideCrabs( syndrome ); /* bring them back */
X
X /* Draw the crab in its new position: */
X
X crab[i].ulc = p;
X
X ModVel( i ); /* randomly alter crab velocity */
X
X DrawCrab( i );
X }
X }
X
X
Xstatic long
XCollide( p ) /* return syndrome for crab collision */
X Point p; /* crab upper left corner */
X {
X long syndrome; /* accumulate syndrome here */
X bool right = p.x % 32 > 32 - 8,
X down = p.y % 32 > 32 - 8; /* more than one vicinity? */
X int x32 = p.x / 32,
X y32 = p.y / 32; /* vicinity array indices */
X
X /* "Or" in crabs from overlapping vicinities: */
X
X syndrome = vicinity[x32 + 1][y32 + 1];
X if ( right )
X syndrome |= vicinity[x32 + 1 + 1][y32 + 1];
X if ( down )
X syndrome |= vicinity[x32 + 1][y32 + 1 + 1];
X if ( right && down )
X syndrome |= vicinity[x32 + 1 + 1][y32 + 1 + 1];
X
X return syndrome;
X }
X
X
Xstatic void
XHideCrabs( syndrome ) /* draw crabs contained in syndrome */
X long syndrome; /* syndrome (crab bit flags) */
X {
X int i; /* indexes crab[.] */
X long m; /* bit mask for crab # i */
X
X for ( m = 1L, i = 0; i < NCRABS; m <<= 1, ++i )
X if ( (m & syndrome) != 0L ) /* crab contained in syndrome */
X DrawCrab( i ); /* toggle crab */
X }
X
X
Xstatic void
XDrawCrab( i ) /* draw specified crab */
X int i; /* crab # (0..NCRABS-1) */
X {
X Point p; /* upper left corner for crab image */
X Point v; /* crab velocity */
X Bitmap *whichmap; /* -> 1 of 4 possible orientations */
X int index; /* selects 1 of 4 offsets wrt grey */
X int x32, y32; /* vicinity array indices */
X bool right, down; /* more than one vicinity? */
X long syn_bit; /* crab possible-occupancy bit */
X
X if ( visible )
X {
X p = crab[i].ulc;
X v = crab[i].vel;
X
X if ( abs( v.x ) >= abs( v.y ) )
X if ( v.x > 0 )
X whichmap = &upmap;
X else
X whichmap = &downmap;
X else
X if ( v.y > 0 )
X whichmap = &rightmap;
X else
X whichmap = &leftmap;
X
X index = (p.x + p.y * 2) % 4 * 8;
X bitblt( whichmap,
X Rect( index, 0, index + 8, 8 ),
X &physical,
X p,
X F_XOR
X );
X
X /* A crab's vicinities are the disjoint 32x32 regions
X that contain any piece of the crab's 8x8 square.
X On the average, 9 out of 16 crabs occupy just 1
X vicinity; 6 out of 16 crabs occupy 2 vicinities,
X and 1 out of every 16 crabs occupies 4 vicinities. */
X
X x32 = p.x / 32;
X y32 = p.y / 32; /* coords for upper left vicinity */
X
X right = p.x % 32 > 32 - 8; /* also next vicinity right? */
X down = p.y % 32 > 32 - 8; /* also next vicinty down? */
X
X /* Toggle crab's occupancy bit in all occupied vicinities: */
X
X syn_bit = i == 0 ? 1L : 1L << i;
X
X vicinity[x32 + 1][y32 + 1] ^= syn_bit;
X if ( right )
X vicinity[x32 + 1 + 1][y32 + 1] ^= syn_bit;
X if ( down )
X vicinity[x32 + 1][y32 + 1 + 1] ^= syn_bit;
X if ( right && down )
X vicinity[x32 + 1 + 1][y32 + 1 + 1] ^= syn_bit;
X }
X /* else nibble away but don't show crabs */
X }
X
X
Xstatic void
XNewVel( i ) /* assign new velocity to crab */
X int i; /* crab # */
X {
X crab[i].vel.x = RandInt( 1 - MAXVEL, MAXVEL );
X crab[i].vel.y = RandInt( 1 - MAXVEL, MAXVEL );
X
X /* Velocity (0,0) is okay since we repeatedly modify all velocities. */
X }
X
X
Xstatic void
XModVel( i ) /* randomly modify crab velocity */
X int i; /* crab # */
X {
X int d; /* increment */
X
X if ( crab[i].vel.x >= MAXVEL - 1 )
X d = RandInt( -1, 1 );
X else if ( crab[i].vel.x <= 1 - MAXVEL )
X d = RandInt( 0, 2 );
X else
X d = RandInt( -1, 2 );
X
X crab[i].vel.x += d;
X
X if ( crab[i].vel.y >= MAXVEL - 1 )
X d = RandInt( -1, 1 );
X else if ( crab[i].vel.y <= 1 - MAXVEL )
X d = RandInt( 0, 2 );
X else
X d = RandInt( -1, 2 );
X
X crab[i].vel.y += d;
X }
X
X
Xstatic int
XRandInt( lo, hi ) /* generate random integer in range */
X int lo, hi; /* range lo..hi-1 */
X {
X return lo + (int)((long)(hi - lo) * (long)(rand() & 0x7FFF) / 32768L);
X }
X
X
X
END_OF_FILE
if test 12000 -ne `wc -c <'crabs.c'`; then
echo shar: \"'crabs.c'\" unpacked with wrong size!
fi
# end of 'crabs.c'
fi
echo shar: End of shell archive.
exit 0