//------------------------------------------------------------------- // // Program: Simple state machine simulation // Filename: TERMTOOL.C // Description: // // This program uses state machine theory to generate // 'termites'. These termites move within the window // using their individual state tables. // // Author: Hans D. Kellner // Version: 1.0 // Notes: none // //------------------------------------------------------------------- #include #include "windows.h" #include "termite.h" /* These are the values to add for each direction index. */ int xMove[4] = {0,0,1,-1}; int yMove[4] = {-1,1,0,0}; // The following tables store the state information read from // the input file. int stateTable[MAX_STATES][MAX_STATES], colorTable[MAX_STATES][MAX_STATES], motionTable[MAX_STATES][MAX_STATES]; // These tables hold the current termites state values and // locations on the screen. int miteX[MAX_MITES], miteY[MAX_MITES], direction[MAX_MITES], state[MAX_MITES]; int noFile = TRUE, // True if no file has been loaded pauseFlag = FALSE; // True if user has paused termites int termiteCount; // Current number of termites DWORD rgbColorTable[MAX_COLORS]; // Local prototypes int RGB2Color(DWORD); int moveMite(int *, int *, int *, int, int); /*-----------------------------------------------------------------*/ /* /* Name: RGB2Color /* Description: /* /* Convert an RGB value back into an array index. /* /*-----------------------------------------------------------------*/ int RGB2Color(rgbColor) DWORD rgbColor; { int color; for ( color = 0; color < MAX_COLORS; color ++ ) { if ( rgbColorTable[color] == rgbColor ) return color; } return 0; } /*-----------------------------------------------------------------*/ /* /* Name: InitTermiteData /* Description: /* /* Do like the name says... Initialize the termites data. /* /*-----------------------------------------------------------------*/ InitTermiteData() { int index; short r,g,b; noFile = TRUE; pauseFlag = FALSE; termiteCount = 1; /* Initialize the data for each Termite */ for ( index = 0; index < termiteCount; index ++ ) { state[index] = 0; /* Start in state 0 */ direction[index] = NORTH; /* heading north */ miteX[index] = (int)xClient / 2; /* and in the center of the window */ miteY[index] = (int)yClient / 2; } /* Create some default colors for color table */ rgbColorTable[0] = RGB( 0, 0, 128 ); rgbColorTable[1] = RGB( 0, 128, 0 ); rgbColorTable[2] = RGB( 128, 0, 0 ); rgbColorTable[3] = RGB( 0, 128, 128 ); rgbColorTable[4] = RGB( 128, 0, 128 ); rgbColorTable[5] = RGB( 128, 128, 0 ); rgbColorTable[6] = RGB( 128, 128, 128 ); rgbColorTable[7] = RGB( 0, 0, 255 ); rgbColorTable[8] = RGB( 0, 255, 0 ); rgbColorTable[9] = RGB( 255, 0, 0 ); rgbColorTable[10] = RGB( 0, 255, 255 ); rgbColorTable[11] = RGB( 255, 0, 255 ); rgbColorTable[12] = RGB( 255, 255, 0 ); rgbColorTable[13] = RGB( 255, 255, 255 ); return 0; } /*-----------------------------------------------------------------*/ /* /* Name: ClipTermites /* Description: /* /* When the window size has changed this routine is called. /* It moves through the list of termites and adjusts their /* position if they no longer are within the window limits. /* /*-----------------------------------------------------------------*/ ClipTermites() { int index; for ( index = 0; index < termiteCount; index ++ ) { if ( miteX[index] >= xClient ) miteX[index] = xClient / 2; if ( miteY[index] >= yClient ) miteY[index] = yClient / 2; } return 0; } /*-----------------------------------------------------------------*/ /* /* Name: LoadTermiteTables /* Description: /* /* Using the filename given, load the termite data into /* the program. /* /*-----------------------------------------------------------------*/ LoadTermiteTables( szFileName ) char *szFileName; { int row, col, rowCount, colCount; FILE *fp; InitTermiteData(); /* Open the data file, exit if unable to open */ fp = fopen( szFileName, "r" ); if ( fp == NULL ) return( -1 ); if ( fscanf( fp, "%d %d", &rowCount, &colCount ) != 2 ) goto loadError; if ( ( rowCount < 1 || rowCount > MAX_STATES ) || ( colCount < 1 || colCount > MAX_STATES ) ) goto loadError; /* Read the state table */ for ( row = 0; row < rowCount; row ++ ) for ( col = 0; col < colCount; col ++ ) if ( fscanf( fp, "%d", &stateTable[row][col] ) != 1 ) goto loadError; /* Read the color table */ for ( row = 0; row < rowCount; row ++ ) for ( col = 0; col < colCount; col ++ ) if ( fscanf( fp, "%d", &colorTable[row][col] ) != 1 ) goto loadError; /* Read the motion table */ for ( row = 0; row < rowCount; row ++ ) for ( col = 0; col < colCount; col ++ ) if ( fscanf( fp, "%d", &motionTable[row][col] ) != 1 ) goto loadError; fclose( fp ); noFile = FALSE; return 0; loadError: fclose( fp ); return -1; } /*-----------------------------------------------------------------*/ /* /* Name: InsertTermite /* Description: /* /* Add a new termite to the list. Give it default values. /* /*-----------------------------------------------------------------*/ InsertTermite() { if ( termiteCount < MAX_MITES ) { state[termiteCount] = 0; /* Start in state 0 */ direction[termiteCount] = NORTH; /* heading north */ miteX[termiteCount] = xClient / 2; /* and in the center */ miteY[termiteCount] = yClient / 2; /* of the window */ termiteCount ++; } return( termiteCount ); } /*-----------------------------------------------------------------*/ /* /* Name: DeleteTermite /* Description: /* /* Just need to decrement the number of termites. This /* will cause the last termite in the list to be lost. /* /*-----------------------------------------------------------------*/ DeleteTermite() { if ( termiteCount > 1 ) termiteCount --; return termiteCount; } /*-----------------------------------------------------------------*/ /* /* Name: moveMite /* Description: /* /* Moves the Termite depending on the direction stored in /* the motion table. /* /*-----------------------------------------------------------------*/ moveMite(x, y, direction, state, color) int *x, *y, *direction, state, color; { /* Determine if the Termite is turning left or right. */ switch ( motionTable[state][color] ) { case LEFT: /* Adjust 90' depending on current direction */ switch ( *direction ) { case NORTH: *direction = WEST; break; case WEST: *direction = SOUTH; break; case SOUTH: *direction = EAST; break; default: case EAST: *direction = NORTH; break; } break; case RIGHT: /* Adjust -90' depending on current direction */ switch ( *direction ) { case NORTH: *direction = EAST; break; case SOUTH: *direction = WEST; break; case EAST: *direction = SOUTH; break; default: case WEST: *direction = NORTH; break; } break; } *x = *x + xMove[*direction]; /* Move to new location */ *y = *y + yMove[*direction]; /* Check for wrapping at window borders. Adjust if needed. */ if (*x < 0) *x = (int)xClient-1; else if (*x >= xClient) *x = 0; if (*y < 0) *y = (int)yClient-1; else if (*y >= yClient) *y = 0; return 0; } /*-----------------------------------------------------------------*/ /* /* Name: HandleTermites /* Description: /* /* This routine is called from the main message loop whenever /* there was no message in the queue. It loops through the /* each termite and updates it position. /* /*-----------------------------------------------------------------*/ void HandleTermites( hWnd ) HWND hWnd; { int index, color, newColor; short xPos, yPos, r, g, b; DWORD rgbColor; HBRUSH hBrush; HDC hDC; if ( pauseFlag || noFile ) return; hDC = GetDC( hWnd ); /* Move each Termite */ for ( index = 0; index < termiteCount; index ++ ) { /* Get the current color at the current position */ rgbColor = GetPixel( hDC, miteX[index], miteY[index] ); color = RGB2Color( rgbColor ); /* Find new color from color table and set it at current position */ newColor = colorTable[state[index]][color]; SetPixel( hDC, miteX[index], miteY[index], rgbColorTable[newColor] ); /* Now, move the Termite */ moveMite( &miteX[index], &miteY[index], &direction[index], state[index], color ); /* Get next state */ state[index] = stateTable[state[index]][color]; } ReleaseDC( hWnd, hDC ); }