/*************************************************************************** * * bmapper.c - a simple bitmap game to test "C" and VDI * * Description: * copies a metafile into a bitmap using VDI. * then creates an n x m grid of windows * on the bitmap. * the lower right corner of the grid of windows is * not created. * the remaining windows are then translated using * movewindow into the null spot. * random selection of nearest window to move is used. * */ #pragma extend /* * The standard iC 286 V3.2 include files are first */ #include #include #include #include #include #include #include #include static char ucginame[256]; static TOKEN cgiconn, metconn; static char cgibuff[1024], metbuff[2048]; static EXCEPTIONSTRUCT noexcept = {0,0,0}; static BitmapId bmap_t; static WindowId wind_t[256]; static WindowId save_t[256]; static int randir; static int olddir; static int report_it; static int same_pri; static DC rel_move; static int wspace; static DC winsize; static int numxwin, numywin; static int rseed; static int move_accepted = 0; static int in_init = 1; static int all_init; static int flush_buffs; static int num_moves; static DC current_move = 0, bs; static CGIDevice cgidev; static char defcginame[] = ":VDI:"; static char defmetname[] = "ROSE4.MET"; static char *cginame; static char *metname; usage() { fprintf(stderr,"usage: bmapper -d -f -b -v cgi_dev -m metafile\n"); fprintf(stderr," -w window_size -g window_gap\n"); fprintf(stderr," -i move_increment -s rand_seed\n"); fprintf(stderr," -p window_priority\n"); fprintf(stderr," -n num_moves_to_exit\n"); exit(1); } void far bmapper_error () { WORD except; Word rgi_except; /* Clean up any bitmaps/windows */ gqdeleteallbitmaps (cgidev); cgi_terminate (cgidev, &rgi_except); if (rgi_except != EOK) dqexit((WORD)1); dqclose(cgiconn, &except); if (except != EOK) dqexit((WORD)1); dqdetach(cgiconn, &except); if (except != EOK) dqexit((WORD)1); dqexit((WORD)1); } seemove( DC rx, DC ry, DC rx2, DC ry2, int wid) { if (report_it == 1) printf("Moving window %d from %d,%d to %d,%d\n", wid, rx, ry, rx2, ry2); } /* this routine is responsible for updating wind_t to reflect the actual window in each 'sector' and for the visual effect of moving the window in sector 'a' into the hole at sector 'b'... */ slowmove( int a, int b) { WORD except; Word rgi_except; WindowId t; DC zx, zy, zx1, zy1; if (wind_t[b] != 255) { fprintf(stderr, "Error in slowmove %d to %d, Not a hole\n",a,b); } /* set state to indicate that a move was valid */ move_accepted = 1; t = wind_t[a]; /* calculate origin of sector a */ zx = (a % 4) * bs; zy = (a / 4) * bs; /* slide a to b - assume it is legal */ switch (randir) { case 0: seemove( zx, zy, zx, (DC)(zy+bs), a); if (in_init == 0) for (zx1 = zx, zy1 = zy; zy1 < (zy + bs); zy1 += rel_move) { gqmovewindow(cgidev, t, (DC)0, rel_move); if (flush_buffs == 0) cgi_flush(cgidev, &rgi_except); } else gqmovewindow(cgidev, t, (DC)0, bs); if (flush_buffs == 0) cgi_flush(cgidev, &rgi_except); break; case 1: seemove( zx, zy, (DC)(zx+bs), zy, a); if (in_init == 0) for (zx1 = zx, zy1 = zy; zx1 < (zx + bs); zx1 += rel_move) { gqmovewindow(cgidev,t, rel_move, (DC)0); if (flush_buffs == 0) cgi_flush(cgidev, &rgi_except); } else gqmovewindow(cgidev, t, bs, (DC)0); if (flush_buffs == 0) cgi_flush(cgidev, &rgi_except); break; case 2: seemove(zx, zy, (DC)(zx-bs), zy, a); if (in_init == 0) for (zx1 = zx, zy1 = zy; zx1 > (zx - bs); zx1 -= rel_move) { gqmovewindow(cgidev, t, (DC)(-rel_move), (DC)0); if (flush_buffs == 0) cgi_flush(cgidev, &rgi_except); } else gqmovewindow(cgidev, t, (DC)(-bs), (DC)0); if (flush_buffs == 0) cgi_flush(cgidev, &rgi_except); break; case 3: seemove(zx, zy, zx, (DC)(zy-bs), a); if (in_init == 0) for (zx1 = zx, zy1 = zy; zy1 > (zy - bs); zy1 -= rel_move) { gqmovewindow(cgidev, t, (DC)0, (DC)(-rel_move)); if (flush_buffs == 0) cgi_flush(cgidev, &rgi_except); } else gqmovewindow(cgidev, t, (DC)0, (DC)(-bs)); if (flush_buffs == 0) cgi_flush(cgidev, &rgi_except); break; default: fprintf(stderr, "Oops - randir is out of bounds at %d\n",randir); break; } if (flush_buffs == 0) cgi_flush(cgidev, &rgi_except); /* swap the entries for next time */ wind_t[a] = wind_t[b]; wind_t[b] = t; /* see if initialization is done */ if (in_init != 0) in_init++; if (in_init >= 100) in_init = 0; /* init done */ if (all_init == 1) in_init = 1; /* reset it again */ } main( int argc, char *argv[]) { WORD except = 0, actual = 1; Word rgi_except; DC x,y; RGI_Index pr; int i,j,k; rqsetexceptionhandler(&noexcept, &except); if (except != EOK) exit(1); dqtrapcc( (HANDLERPTRSTRUCT *) &bmapper_error, &except); if (except != EOK) exit(1); /* initializations for command line options */ rseed = 0; rel_move = 4; /* move increment */ wspace = 0; /* inter-window gap */ winsize = 160; report_it = 0; /* less verbose if 0 more if 1 (-d) */ same_pri = 255; /* 0 = different priority, n = same priority */ cginame = defcginame; metname = defmetname; all_init = 0; /* if 1 then all fast moves */ flush_buffs = 0; /* flush each move */ num_moves = 1000; /* exit after 1000 moves */ while ((argc > 1) && (argv[1][0] == '-')) { switch (argv[1][1]) { case 'd': report_it = 1; break; case 'b': flush_buffs = 1; /* don't flush each move */ break; case 'f': all_init = 1; break; case 'p': argv++; argc--; if ((argc > 1) && (argv[1][0] != '-')) same_pri = atoi( (const char *)&argv[1][0]); else usage(); break; case 's': argv++; argc--; if ((argc > 1) && (argv[1][0] != '-')) rseed = atoi( (const char *)&argv[1][0]); else usage(); break; case 'i': argv++; argc--; if ((argc > 1) && (argv[1][0] != '-')) rel_move = atoi( (const char *)&argv[1][0]); else usage(); break; case 'n': argv++; argc--; if ((argc > 1) && (argv[1][0] != '-')) num_moves = atoi( (const char *)&argv[1][0]); else usage(); break; case 'g': argv++; argc--; if ((argc > 1) && (argv[1][0] != '-')) wspace = atoi( (const char *)&argv[1][0]); else usage(); break; case 'w': argv++; argc--; if ((argc > 1) && (argv[1][0] != '-')) winsize = atoi( (const char *)&argv[1][0]); else usage(); break; case 'm': argv++; argc--; if ((argc > 1) && (argv[1][0] != '-')) metname = argv[1]; else usage(); break; case 'v': argv++; argc--; if ((argc > 1) && (argv[1][0] != '-')) cginame = argv[1]; else usage(); break; default: fprintf(stderr,"Unrecognized Control: %s\n",argv[1]); usage(); break; } argv++; argc--; } bs = winsize + wspace; if ((bs * 4) > 640) { fprintf(stderr,"size/space to large to fit X dimension.\n"); usage(); } if ((bs * 3) > 480) { fprintf(stderr,"size/space to large to fit Y dimension.\n"); usage(); } if ((bs % rel_move) != 0) { fprintf(stderr,"move must be a divisor of size+space.\n"); usage(); } /* seed the random number generator */ srand((unsigned int)rseed); /* get the cgi device connection */ cgiconn = rqscreatefile((STRING *) udistr(ucginame, (const char *)cginame), &except); if (except != EOK) { fprintf(stderr, "Error %d Creating Output File: %s\n",except,cginame); dqexit((WORD)1); } rqsopen(cgiconn, (BYTE)3, (BYTE)0, &except); if (except != EOK) { fprintf(stderr, "Error %d Opening Output File: %s\n", except, cginame); dqexit((WORD)1); } cgidev = cgi_initialize(cgiconn, cgibuff, sizeof cgibuff, &rgi_except); if (rgi_except != EOK) { fprintf(stderr, "Error %d Initializing RGI library: %s\n", rgi_except, cginame); dqexit((WORD)1); } /* get the metafile connection */ metconn = rqsattachfile((STRING *) udistr(ucginame, (const char *)metname), &except); if (except != EOK) { fprintf(stderr, "Error %d Attaching Input File: %s\n",except,metname); dqexit((WORD)1); } rqsopen(metconn, (BYTE)1, (BYTE)2, &except); if (except != EOK) { fprintf(stderr, "Error %d Opening Input File: %s\n",except,metname); dqexit((WORD)1); } /* Clean up any bitmaps/windows */ gqdeleteallbitmaps(cgidev); /* create a bitmap */ bmap_t = 0; gqcreatebitmap(cgidev, bmap_t, (DC)640, (DC)480, (RGI_Index)4); /* create 11 windows of size winsize at spacing winsize + wspace */ for (y=i=k=0; ((y <= (480 - bs)) && (k < 3)); y += bs, k++) { for (x=j=0; ((x <= (640 - bs)) && (j < 4)); x += bs, i++, j++) { if (i < 11) { if (same_pri == 0) pr = i + 1; else pr = same_pri; save_t[i] = wind_t[i] = i; gqcreatewindow(cgidev, wind_t[i], bmap_t, pr, (RGI_Index)VISIBLE, x, y, x, y, winsize, winsize); } } } /* Select the bitmap for drawing */ gqselectdrawingbitmap(cgidev, bmap_t); cgi_flush(cgidev, &rgi_except); /* copy the metafile to the bitmap using the EIOS directly */ actual = 1; while (actual != 0) { actual = rqsreadmove(metconn, (BYTE *)metbuff, (NATIVE_WORD)sizeof metbuff, &except); if (except != EOK) { fprintf(stderr, "Error %d Reading Input File: %s\n",except,metname); dqexit((WORD)1); } if (actual != 0) { actual = rqswritemove(cgiconn, (BYTE *)metbuff, (NATIVE_WORD)actual, &except); if (except != EOK) { fprintf(stderr, "Error %d Writing Output File: %s\n",except,cginame); dqexit((WORD)1); } } } /* get rid of the metafile connection */ rqsclose(metconn, &except); if (except != EOK) { fprintf(stderr, "Error %d Closing Input File: %s\n",except,metname); dqexit((WORD)1); } rqsdeleteconnection(metconn, &except); if (except != EOK) { fprintf(stderr, "Error %d Detaching Input File: %s\n",except,metname); dqexit((WORD)1); } /* now - randomly move a neighbor of the 'hole' into the hole forever... holes are numbered: 0 1 2 3 4 5 6 7 8 9 10 11 hole starts at 11. diagonal moves aren't allowed. 9/6 - added - can't move same tile twice... this means that if the old direction was 0 then the new direction can't be 3 and vice-versa - same holds for 1 and 2. directions are: 0 1 2 3 the following switch is the state graph... */ x = 11; save_t[11] = wind_t[11] = 255; /* mark the hole */ randir = (rand() & 0x06000) >> 13; /* pick a new direction */ /* round randomly - should test bit 13 of previous result... */ if ((rand() & 0x01) != 0) randir = (randir + 1) % 4; olddir = 255; /* invalid */ y = 0; /* done flag */ while (y == 0) { if (report_it == 1) printf("Hole is at: %d, Direction %d\n",x,randir); /* set state to indicate that the move was not accepted */ move_accepted = 0; switch(x) { case 0: switch(randir) { case 0: break; case 1: break; case 2: slowmove(1,0); x = 1; break; case 3: slowmove(4,0); x = 4; break; } break; case 1: switch(randir) { case 0: break; case 1: slowmove(0,1); x = 0; break; case 2: slowmove(2,1); x = 2; break; case 3: slowmove(5,1); x = 5; break; } break; case 2: switch(randir) { case 0: break; case 1: slowmove(1,2); x = 1; break; case 2: slowmove(3,2); x = 3; break; case 3: slowmove(6,2); x = 6; break; } break; case 3: switch(randir) { case 0: break; case 1: slowmove(2,3); x = 2; break; case 2: break; case 3: slowmove(7,3); x = 7; break; } break; case 4: switch(randir) { case 0: slowmove(0,4); x = 0; break; case 1: break; case 2: slowmove(5,4); x = 5; break; case 3: slowmove(8,4); x = 8; break; } break; case 5: switch(randir) { case 0: slowmove(1,5); x = 1; break; case 1: slowmove(4,5); x = 4; break; case 2: slowmove(6,5); x = 6; break; case 3: slowmove(9,5); x = 9; break; } break; case 6: switch(randir) { case 0: slowmove(2,6); x = 2; break; case 1: slowmove(5,6); x = 5; break; case 2: slowmove(7,6); x = 7; break; case 3: slowmove(10,6); x = 10; break; } break; case 7: switch(randir) { case 0: slowmove(3,7); x = 3; break; case 1: slowmove(6,7); x = 6; break; case 2: break; case 3: slowmove(11,7); x = 11; break; } break; case 8: switch(randir) { case 0: slowmove(4,8); x = 4; break; case 1: break; case 2: slowmove(9,8); x = 9; break; case 3: break; } break; case 9: switch(randir) { case 0: slowmove(5,9); x = 5; break; case 1: slowmove(8,9); x = 8; break; case 2: slowmove(10,9); x = 10; break; case 3: break; } break; case 10: switch(randir) { case 0: slowmove(6,10); x = 6; break; case 1: slowmove(9,10); x = 9; break; case 2: slowmove(11,10); x = 11; break; case 3: break; } break; case 11: switch(randir) { case 0: slowmove(7,11); x = 7; break; case 1: slowmove(10,11); x = 10; break; case 2: break; case 3: break; } break; default: fprintf(stderr, "Oops - Hole switch is out of bounds at %d\n",x); break; } /* pick next direction - impose rule stating no reversal of moves */ /* note that if an invalid direction is picked we won't know it here since the state machine detects/ignores it. to fix this we need a state variable saying that the machine accepted a particular move as valid. we can then test this variable before resetting olddir */ if (move_accepted == 1) { olddir = randir; if (num_moves != 0) { /* test for "run forever condition" */ current_move++; if (current_move > num_moves) exit(0); } } y = 1; while (y == 1) { randir = (rand() & 0x06000) >> 13; /* pick a new direction */ /* round randomly - should test bit 13 of previous result... */ if ((rand() & 0x01) != 0) randir = (randir + 1) % 4; switch (olddir) { case 0: if (randir != 3) y = 0; break; case 1: if (randir != 2) y = 0; break; case 2: if (randir != 1) y = 0; break; case 3: if (randir != 0) y = 0; break; default: /* olddir was not yet set - proceed */ y = 0; break; } } /* test for game end */ /* if the window id's in wind_t match those in save_t then we are back to the original arrangement... */ y = 1; /* assume we are done */ for (i = 0; (i < 12) && (y == 1); i++) { if (wind_t[i] != save_t[i]) y = 0; /* not done */ } } /* get rid of the cgi connection */ cgi_terminate(cgidev, &rgi_except); if (rgi_except != EOK) dqexit((WORD)1); rqsclose(cgiconn, &except); if (except != EOK) dqexit((WORD)1); rqsdeleteconnection(cgiconn, &except); if (except != EOK) dqexit((WORD)1); /* return */ }