home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************
- *
- * Name: SNAKES
- *
- * Function: display multiple "snakes" each controlled by a
- * separate task.
- *
- * Shows how to: 1. create and terminate subtasks.
- * 2. use mail to send initial data to a new task.
- * 3. use a semaphore to control access to a
- * resource, in this case the window.
- * 4. read and write the window contents.
- *
- ****************************************************************/
-
- #include <stdio.h>
- #include "dvapi.h"
-
- /* minimum API version required */
- #define required 0x201
-
- /* number of tasks supported and the stack size for each */
- #define ntasks 8
- #define stksize 256
-
- /* object handles */
- ulong win,kbd,sema,menuwin,menukbd,taskhan[ntasks];
-
- /* step sizes in each direction {up,right,down,left} */
- int row_offsets[4] = {-1,0,1,0};
- int col_offsets[4] = {0,2,0,-2};
-
- /* variables used to read menu data */
- char *kbuf,field;
- int klng;
-
- /* other variables */
- int next = 0; /* next task number available */
- int locked = 0; /* TRUE if snakes are suspended */
- int version; /* actual API version */
-
- /* this string defines the menu contents */
- char menu1[] = "\
- Create a new snake C \
- Kill a snake K \
- Bury dead snakes B \
- Start/Stop all snakes S \
- Exit E ";
-
- /* this string defines the menu's field table */
- char ftab1[] = {ftab(5,FTH_KEYSELECT+FTH_MODIFIED,0,0,9,1),
- 0,0,0,25,FTE_SELECT,'C',1,0,
- 1,0,1,25,FTE_SELECT,'K',1,0,
- 2,0,2,25,FTE_SELECT,'B',1,0,
- 3,0,3,25,FTE_SELECT,'S',1,0,
- 4,0,4,25,FTE_SELECT,'E',1,0,
- };
-
- /* subtask entry point - defined here to allow forward reference */
- int snake();
-
- /**********************************************************************
- * main - check for DESQview present and enable required extensions.
- ***********************************************************************/
-
- main () {
- /* initialize C interfaces and get API version number */
- version = api_init();
-
- /* if DESQview is not running or version is too low, display a message */
- if (version < required) {
- printf ("This program requires DESQview version %d.02%d or later.\n",
- required/256,required%256);
- }
-
- /* tell DESQview what extensions to enable and start application */
- else {
- api_level (required);
- program_body();
- }
-
- /* disable C interfaces and return from program */
- api_exit();
- }
-
-
- /**********************************************************************
- * program_body - create and display menu window. Loop processing
- * menu input.
- ***********************************************************************/
-
- program_body () {
- /* reserve stack space for subtasks on primary stack so that stack
- bounds checking still works. Define other local variables. */
- char stacks[ntasks][stksize];
- int i,k,done;
-
- /* get default object handles. Allocate semaphore (mailbox). */
- win = win_me();
- kbd = key_me();
- sema = mal_new();
-
- /* set logical attributes and make task window full screen */
- win_logattr (win,1);
- win_attr (win,1);
- win_erase (win);
- win_origin (win,0,0);
- win_move (win,0,0);
- win_resize (win,25,80);
- win_redraw (win);
-
- /* allocate window and keyboard objects for menu */
- menuwin = win_new ("Snakes",6,5,26);
- menukbd = key_new();
- key_open (menukbd,menuwin);
- key_addto (menukbd,KBF_FIELD);
-
- /* write contents and field table to menu. Make topmost in application. */
- win_swrite (menuwin,menu1);
- win_stream (menuwin,ftab1);
- win_move (menuwin,1,53);
- win_unhide (menuwin);
- win_top (menuwin);
-
- /* move mouse to first menu field */
- fld_point (win,1,0,0);
-
- /* loop until done becomes TRUE */
- done = 0;
- while (!done) {
-
- /* wait for menu selection, determine field #, reset to deselected */
- key_read (menukbd,&kbuf,&klng);
- field = *kbuf;
- fld_reset (menuwin);
-
- /* lockout access to screen for all snake tasks */
- mal_lock (sema);
-
- /* dispatch based on selected field number */
- switch (field) {
-
- case 1: /* Create new snake - beep if no more snakes allowed */
- if (next == ntasks)
- api_sound (2000,5);
- else {
-
- /* create a new task to run the "snake" function. */
- taskhan[next] = tsk_new (snake,stacks[next],stksize,NULL,0,0,0);
-
- /* tell task what attribute to use by sending a NULL message
- with the attribute as its status code. */
- mal_subfrom (mal_of(taskhan[next]),NULL,0,next+1);
-
- /* bump task count */
- next += 1;
- }
- break;
-
- case 2: /* Kill a snake - beep if there are no more snakes to kill */
- if (next == 0)
- api_sound (2000,5);
- else {
-
- /* decrement task count and kill most recent task */
- next -= 1;
- tsk_free (taskhan[next]);
- }
- break;
-
- case 3: /* Bury dead snakes - erase window to clear all snakes.
- Live ones redraw themselves. */
- win_attr (win,1);
- win_erase (win);
- break;
-
- case 4: /* Stop/Start snakes - stop snakes by over-locking the
- semaphore. Unlock to start. */
- (locked) ? mal_unlock(sema) : mal_lock(sema);
- locked = !locked;
- break;
-
- case 5: /* Exit - set the "done" flag */
- done = 1;
- break;
- }
-
- /* unlock snake tasks and loop until "done" */
- mal_unlock (sema);
- }
-
- /* stop all snakes and free their tasks */
- mal_lock (sema);
- for (i=0; i<next; i++) {
- tsk_free (taskhan[i]);
- }
-
- /* free allocated objects */
- mal_free (sema);
- key_free (menukbd);
- win_free (menuwin);
-
- /* change to physical attributes in case exiting to DOS */
- win_logattr (win,0);
- win_attr (win,7);
- win_erase (win);
- }
-
-
- /**********************************************************************
- * snake - continuously move a single snake.
- ***********************************************************************/
-
- snake () {
- /* all data must be dynamic */
- int row[16],col[16],head_row,head_col,old_row,old_col,i,atr,mallng;
- char *malptr;
-
- /* wait for parent to send attribute to be used */
- atr = mal_read (mal_me(),&malptr,&mallng);
-
- /* initialize array used to log position of each segment of snake */
- for (i=0; i<16; i++) row[i] = -1;
-
- /* set snake start position. Loop forever moving the snake. */
- head_row = 12;
- head_col = 40;
- while (1) {
-
- /* loop for each segment of snake */
- for (i=0; i<16; i++) {
-
- /* remember head position and compute a new position */
- old_row = head_row;
- old_col = head_col;
- find_new_head (&head_row,&head_col);
-
- /* acquire exclusive access to window and clear tail segment */
- mal_lock (sema);
- if (row[i] != -1)
- write_segment (row[i],col[i],' ',1);
-
- /* if new head position is occupied, don't move head */
- if (position_occupied(head_row,head_col)) {
- head_row = old_row;
- head_col = old_col;
- }
-
- /* write new head segment and relinquish access to window */
- write_segment (head_row,head_col,0xB2,atr);
- mal_unlock (sema);
-
- /* log new head position in array */
- row[i] = head_row;
- col[i] = head_col;
- }
- }
- }
-
-
- /**********************************************************************
- * find_new_head - get new head position
- ***********************************************************************/
-
- find_new_head (row,col) int *row,*col; {
- int dir,nrow,ncol;
-
- /* use random # to lookup horizontal and vertical steps */
- do {
- dir = rand() & 3;
- nrow = *row + row_offsets[dir];
- ncol = *col + col_offsets[dir];
- }
-
- /* loop if new position is outside window */
- while ((nrow < 0) || (nrow > 24) ||
- (ncol < 0) || (ncol > 78));
-
- /* return new position */
- *row = nrow;
- *col = ncol;
- }
-
-
- /**********************************************************************
- * position_occupied - return TRUE if there is a char at given position
- ***********************************************************************/
-
- int position_occupied (row,col) int row,col; {
- char *readptr;
- int readlng;
-
- /* set cursor to position and read a single character */
- win_cursor (win,row,col);
- win_nread (win,1,&readptr,&readlng);
-
- /* return TRUE if it isn't a space */
- return (!(*readptr == ' '));
- }
-
-
- /**********************************************************************
- * write_segment - write character twice at given position with
- * given attribute.
- ***********************************************************************/
-
- write_segment (row,col,chr,atr) int row,col,chr,atr; {
- win_cursor (win,row,col);
- win_attr (win,atr);
- win_repchar (win,2,chr);
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-