home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mega CD-ROM 1
/
megacd_rom_1.zip
/
megacd_rom_1
/
DESQVIEW
/
API_EXAM.ZIP
/
SNAKES.C
< prev
next >
Wrap
Text File
|
1988-04-28
|
10KB
|
331 lines
/****************************************************************
*
* 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);
}