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