// ecoDraw.c // Each byte hand carved by K. J. Rock // (c) December 5th, 2024 - January 30, 2025 // Merry Christmas // Version 1.07.7 sync with ecology.html // gnuplot script // set logscale y or set logscale for a log,log chart // plot 'dt.dat' using 1:4 title 'Carnivore' with line, 'dt.dat' using 1:3 title 'Herbivore' with line, 'dt.dat' using 1:2 title 'Plant' with line // plot 'dt.dat' using 1:4 title 'Carnivore' with line, 'dt.dat' using 1:2 title 'Plant' with line, 'dt.dat' using 1:3 title 'Herbivore' with line #include // Win32 API #include #include #include #include "resource.h" #define WINX 300 #define WINY 300 // 3000 is larger than my largest monitor. So I don't need to fix WM_SIZE :) //#define SZ 5000 // Height = Width for a square ecosystem #define SZ 3500 // Make sure there are no *.dat files with application #define NUMCOL 768 // Blue to Red to Yellow to White #define min(a,b) (((a)<(b))?(a):(b)) // Find the minimum #define max(a,b) (((a)>(b))?(a):(b)) // Find the maximum typedef unsigned int chromosome; // Chromosome - 31 bits of genetic information float fRan( void ) { return (float) rand() / (float) RAND_MAX; } // {0.0 <= rn <= 1.0} struct vt { int x, y; }; // 2D integer space struct vt dir[9]; // 2D direction vector from D2Q9 LBM now mathematical struct color { int R, G, B; }; // Rudimentary color structure struct color palette[ NUMCOL ]; // An array of color structures int kk = 0; // Global cycle counter int delay = 3; // SleepEx( delay ); int newPpop, newHpop, newCpop; // New plant, herbivore, carnivore counter static int iVscrollPos, iVscrollMax, iVscrollInc ; static int iHscrollPos, iHscrollMax, iHscrollInc ; struct pnode // Plant node { struct vt X; // X is an i,j pair based on an SZxSZ grid float energy; // Life force bool alive; // Deva int age; // Metabolize chromosome EN, PL; // EN for energy genes, PL for plant genes chromosome GM; // GM is a genetic marker passed directly from mom }; struct hnode // Herbivore node { struct vt X; // Location // int Psense[9], Csense[9]; // Sensor network // Remove?? TODO float energy; // Life force bool alive; // Starve or get eaten? int age; // Metabolize, entropy, senescence chromosome EN, HB; // Energy and herbivore chromosomes chromosome SN, DR; // Sensor and direction chromosomes chromosome GM; // GM is a genetic marker passed directly from mom }; struct cnode // Carnivore node { struct vt X; // 2D location vector // int Hsense[9]; // Sensor network // Remove?? TODO float energy; // Chi bool alive; // Energy above zero. int age; // Used in reproduce() chromosome EN, CN; // Energy and carnivore chromosomes chromosome SN, DR; // Sensor and direction chromosomes chromosome GM; // GM is a genetic marker passed directly from mom }; struct enode // Ecology node { float nutrient; // The nutrient energy level of this cell struct pnode *P; // Point to plant, struct hnode *H; // herbivore, and/or struct cnode *C; // carnivore living here. }; // Ecosystem and organism buffers ///////// struct enode *E = (struct enode *) malloc( SZ * SZ * sizeof( struct enode )); struct pnode *PL1 = (struct pnode *) malloc( SZ * SZ * sizeof( struct pnode )); struct pnode *PL2 = (struct pnode *) malloc( SZ * SZ * sizeof( struct pnode )); struct hnode *HL1 = (struct hnode *) malloc( SZ * SZ * sizeof( struct hnode )); struct hnode *HL2 = (struct hnode *) malloc( SZ * SZ * sizeof( struct hnode )); struct cnode *CL1 = (struct cnode *) malloc( SZ * SZ * sizeof( struct cnode )); struct cnode *CL2 = (struct cnode *) malloc( SZ * SZ * sizeof( struct cnode )); // Lists for new plants, herbivores, and carnivores struct pnode *NP = (struct pnode *) malloc( SZ * SZ * sizeof( struct pnode )); struct hnode *NH = (struct hnode *) malloc( SZ * SZ * sizeof( struct hnode )); struct cnode *NC = (struct cnode *) malloc( SZ * SZ * sizeof( struct cnode )); // Buffer indirection indices ///////////// struct pnode *PL = PL1; // Initial condition struct hnode *HL = HL1; struct cnode *CL = CL1; struct pnode *OPL = PL2; // Pointers to the "Other" buffers struct hnode *OHL = HL2; struct cnode *OCL = CL2; bool even = true; // Buffer indirection flag bool data = true; // Floating data display bool high = false; // Toggle extra energy during replenish() bool mark = false; // Toggle GM marked plant display bool pause = true; // Toggle Run/Pause mode bool store = false; // Save sample.dat HINSTANCE hInst; HWND hwnd; // Window handle HFONT hf; // Font handle HDC hdc, bkhdc; // Foreground and background device contexts HDC hdcdata; // Data display DC HBITMAP bkBitmap; // Background bitmap HBITMAP dataBitmap; // Data display bitmap HANDLE displayThreadHandle; // Animation thread handle HANDLE ecoThreadHandle; // ecoNode thread handle // Main functions ///////////////////////// void initEcosystem( void ); // Initialize ecosystem framework void initPlants( void ); // Create plants to fill the ecosystem void initHerbivores( void ); // Create herbivores for the ecosystem void initCarnivores( void ); // Create carnivores to fill the ecosystem void moveHerbivores( void ); // Call move() on each herbivore void moveCarnivores( void ); // Call move() on each carnivore float metabolize( void ); // metabolize() void replenish( float ); // replenish() nutrient layer in the E buffer void eat( void ); // Absorb nutrients, eat plants, or eat herbivores void reproduce( void ); // reproduce() if you have the energy and age void die( void ); // die() from energy loss void cull( void ); // Bring out your dead void addNew( void ); // Catenate new organisms to their lists void bufferSwap( void ); // Swap even/odd buffers // Useful tools /////////////////////////// struct vt vector( int, int ); // 2D integer vector for cell or pixel use struct vt sum( struct vt, struct vt ); // Add 2D vectors struct vt bound( struct vt ); // Place 2D vector into toroidal space struct vt scale( int, struct vt ); // Find an open cell around current location float fRan( void ); // Floating point random number generator void initDir( void ); // Initialize the direction vector buffer struct vt move( chromosome ); // Use motion genes to relocate animals chromosome crossover( chromosome, chromosome ); // Find most fit chromosome mutation( chromosome ); // Explore neighboring regions of gene space // Data Logging functions ///////////////// void loadGMSamples( void ); // Read new, genetically marked samples void storeGMSamples( void ); // Store random sampline every 50 cycles void spotSample( void ); // Sample from running simulation void stamp( void ); // Add timestamp to terminal window void loadNutrients( void ); // Read 'nut.dat' void newPlants( void ); // GM 61680 void newHerbivores( void ); void newCarnivores( void ); // Create 5000 random carnivores GM 61680 void createPlants( void ); // Create 5000 random plants GM 3855 void createHerbivores( void ); // Create 5000 random herbivores void createCarnivores( void ); // Create 5000 random carnivores void matureSamples( void ); // Fill buffers for matureNutrients() void matureNutrients( void ); // Fill ecosystem from nut.dat, random, and sample9.dat void initPalette( void ); // Create a Blue to Red to Yellow to White palette int colorTransform( int, int, float, float, float ); void drawFrame( void ); // Paint the display with nutrients, plants, etc. void displayData( int ); // Paint data over the ecosystem bitmap. DWORD WINAPI display( LPVOID ); // Display thread DWORD WINAPI ecoNode( LPVOID ); // Ecosystem thread INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, INT ); LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM); // User Tweakable Values // // int Ppop = 400000, Hpop = 200000, Cpop = 25000; // Initial populations // int Ppop = 3900000, Hpop = 900000, Cpop = 80000; // Alternate initial populations int Ppop = 500000, Hpop = 230000, Cpop = 50000; // float PRenergy = 12.5, HRenergy = 65.0, CRenergy = 35.5; // Reproduction energy level hard wire int PNoffset = 5, HNoffset = 19, CNoffset = 39; // Senescence - EN::G1 + offset float PSoffset = 29.1, HSoffset = 56.1, CSoffset = 1.2; // Satiety - EN::G3 + offset float PMoffset = 3.1, HMoffset = 4.2, CMoffset = 5.3; // Metabolism - EN::G5 + offset 5.3 - 12.3 int PAoffset = 1, HAoffset = 1, CAoffset = 3; // Age of sexual maturiety EN::G2 LRESULT CALLBACK InitializeDialogProc( HWND, UINT, WPARAM, LPARAM); // 'i' INT_PTR CALLBACK MaturityDialogProc( HWND, UINT, WPARAM, LPARAM); // 'a' LRESULT CALLBACK MetabolicDialogProc( HWND, UINT, WPARAM, LPARAM); // 'm' LRESULT CALLBACK ReproductionDialogProc( HWND, UINT, WPARAM, LPARAM); // 'r' INT_PTR CALLBACK SenescenceDialogProc( HWND, UINT, WPARAM, LPARAM ); // 's' LRESULT CALLBACK SatietyDialogProc( HWND, UINT, WPARAM, LPARAM); // 't' INT_PTR CALLBACK HelpDialogProc( HWND, UINT, WPARAM, LPARAM); // 'h' // Spot sample user interface functions ////////////////////////////////////// INT_PTR CALLBACK RadioDialogProc( HWND, UINT, WPARAM, LPARAM); int displayHelp( void ); // Use message box to display help list 'h' void logNutrients( void ); // Store the present nutrient layer energy values void seeEN( void ); void seeHDR( void ); void seeCDR( void ); void countGM( void ); void compareGenes( void ); void Pabsorbs( void ); void Habsorbs( void ); void Cabsorbs( void ); void camoWar( void ); void seeWar( void); void strengthWar( void ); void resistWar( void ); void spineWar( void ); void eatWar( void ); /////////////////////////////////////////////////////////////////////////////// /////// Make this a variable block for spot sample reports ////////////////// /////////////////////////////////////////////////////////////////////////////// #define SS 1000 // Maximum spot sample selection size is SS^2 // Lists for new plants, herbivores, and carnivores Reproduction & addNew() struct pnode *SP = (struct pnode *) malloc( SS * SS * sizeof( struct pnode )); struct hnode *SH = (struct hnode *) malloc( SS * SS * sizeof( struct hnode )); struct cnode *SC = (struct cnode *) malloc( SS * SS * sizeof( struct cnode )); int Psamp = 0, Hsamp = 0, Csamp = 0; bool firstClick = false; // Left click indicator POINT UL, LR; // Spot sample click spots char text[ 80 ]; // Data buffer int num; // Character count int hist[ 10 ]; float metab, absorb, satiety; // Globalize variables?? Argh ! int maturity, Psenescence, Hsenescence, Csenescence; int psum, hsum, ssum, camSum, seeSum, eatSum, page, hage, cage; int pMin, pMax; int Peat, Heat, Ceat; // Number of eaten or died each cycle float pmin, pmax, hmin, hmax, cmin, cmax; float emin, emax; // Population extrema float sumEn, sumAbs, sumEnergy, sumSat; float sumPsen, sumHsen, sumCsen; float sumPAbs, sumHAbs, sumCAbs; float dirProb[ 9 ]; // Normalized Direction Probability Vector int Hmin = 1, Cmin = 3; // Need offset variables TODO int Hspeed, Cspeed; /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// DWORD WINAPI display( LPVOID pV ) // Transform, display thread { // Or Black Red Yellow White for black body initPalette(); // Create a Blue Red Yellow White palette while( TRUE ) // City on the edge of forever { SleepEx( delay, FALSE ); // Scalosians slow to human speeds hdc = GetDC( hwnd ); // Get the device context SelectObject( bkhdc, bkBitmap ); // Draw in background, WM_PAINT displays it drawFrame(); // Draw ecosystem bitmap if( data ) displayData( kk ); // Overlay data bitmap ReleaseDC( hwnd, hdc ); // Return DC to the operating system. InvalidateRect( hwnd, NULL, TRUE ); // Force WM_PAINT } ExitProcess( 0 ); // Running Light Without Overbyte. return 0; } DWORD WINAPI ecoNode( LPVOID pV ) // Ecology Engine { FILE *fp = fopen("dt.dat", "w"); // Instantiate data file fclose( fp ); // Clear data file for writing pause = false; /* I really don't use these. Leave them for actual users in the future. if( pause ) // Allow the user to change parameters { DialogBox( hInst, MAKEINTRESOURCE( IDD_INITIALIZE_DIALOG ), hwnd, &InitializeDialogProc ); DialogBox( hInst, MAKEINTRESOURCE( IDD_METABOLIC_DIALOG ), hwnd, &MetabolicDialogProc ); DialogBox( hInst, MAKEINTRESOURCE( IDD_REPRODUCTION_DIALOG ), hwnd, &ReproductionDialogProc ); DialogBox( hInst, MAKEINTRESOURCE( IDD_MATURITY_DIALOG ), hwnd, &MaturityDialogProc ); // DialogBox( hInst, MAKEINTRESOURCE( IDD_SENESCENCE_DIALOG ), hwnd, &SenescenceDialogProc ); DialogBox( hInst, MAKEINTRESOURCE( IDD_SATIETY_DIALOG ), hwnd, &SatietyDialogProc ); pause = false; } */ matureNutrients(); // Initialize the ecosystem while( true ) // Enter a forever loop { SleepEx( delay, FALSE ); // Scalosians slow to human speeds // printf("%4d %8d %7d %6d %7d %6d %5d\n", kk, Ppop, Hpop, Cpop, Peat, Heat, Ceat ); printf("%4d %8d %7d %6d %7.2f %7.2f %7.2f %7.2f ", kk, Ppop, Hpop, Cpop, pmax, hmax, cmax, emax ); stamp(); // Add a time stamp to display fp = fopen("dt.dat", "a"); // Append to end of file fprintf(fp, "%d %d %d %d %d %d %d\n", kk, Ppop, Hpop, Cpop, Peat, Heat, Ceat ); fclose( fp ); // Print a PAUSE msg in dataDisplay window. while( pause ) ; // Spin lock if( (kk>0) && (kk%1000 == 0) ) // Store genetic samples storeGMSamples(); // in 'sample9GM.dat' // herbScan(); // Fill sensor array moveHerbivores(); // Check randomness, checked! // carnScan(); // Fill sensor array moveCarnivores(); // dir[] and scale() replenish( metabolize() ); // Balance energy in with energy out eat(); // Surviving organisms gain energy reproduce(); // Mate organisms for the future die(); // Set organism alive flag to false :( cull(); // NULL the dead while collecting survivors addNew(); // Add offspring to 'other' buffers bufferSwap(); // Swap to 'other' buffers kk++; // Count the cycles as they pass if( Ppop < 2 || Hpop < 2 || Cpop < 2 ) // It takes two to tango break; } ExitProcess( 0 ); // Running Light Without Overbyte. return 0; } //////////////////////////////////////////////////////////////////////////////////////// ///////////// Windows Tools ////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// INT WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow ) { const char ClassName[] = "MainWindowClass"; WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE( IDI_ICON )); wc.hIconSm = LoadIcon( hInstance, MAKEINTRESOURCE( IDI_ICON )); wc.hCursor = LoadCursor( NULL, IDC_ARROW ); wc.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 ); wc.lpszMenuName = NULL; wc.lpfnWndProc = (WNDPROC) WndProc; // User Interface thread wc.lpszClassName = ClassName; if (!RegisterClassEx( &wc )) // Depends on UNICODE constant, I think it's ASCII now. { MessageBox( NULL, "Failed To Register Window Class", "Error", MB_OK | MB_ICONERROR ); return 0; } hwnd = CreateWindowEx( NULL, ClassName, "The Veldt", WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL, 10, 10, 1200, 1000+30, NULL, NULL, hInstance, NULL ); if ( !hwnd ) { MessageBox( NULL, "Window Creation Failed", "Error", MB_OK | MB_ICONERROR ); return 0; } ShowWindow( hwnd, SW_SHOW ); UpdateWindow( hwnd ); // Use for fixed frame rate // SetTimer( hwnd, IDT_TIMER, 65, (TIMERPROC) TimerProc ); DWORD displayThreadID; // Graphics thread displayThreadHandle = CreateThread( 0, 0, display, 0, 0, &displayThreadID ); DWORD ecoThreadID; // Ecology thread ecoThreadHandle = CreateThread( 0, 0, ecoNode, 0, 0, &ecoThreadID ); MSG msg; // Message loop while (GetMessage( &msg, NULL, 0, 0 )) { TranslateMessage( &msg ); DispatchMessage( &msg ); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hdc; // Device context (DC) for window PAINTSTRUCT ps; // Paint data for BeginPaint and EndPaint POINT ptClientUL; // Client area upper left corner POINT ptClientLR; // Client area lower right corner POINT mouseClickDownPos, curMousePos; MINMAXINFO FAR *minMax; static int cxClient = WINX, cyClient = WINY; static RECT rct, rcClient; // Client-area rectangle int zDelta; // Mouse wheel torsion up/down control long lfHeight; // Store the font height in graphics units switch (msg) { case WM_CREATE: srand( (unsigned) time( NULL ) ); // Seed random number generator initDir(); // Fill dir[] array with motion vectors hdc = GetDC( hwnd ); bkhdc = CreateCompatibleDC( hdc ); bkBitmap = CreateCompatibleBitmap( hdc, SZ, SZ ); // Problem space size SZ = 5000 square SelectObject( bkhdc, bkBitmap ); // Draw in background, WM_PAINT displays it hdcdata = CreateCompatibleDC( hdc ); dataBitmap = CreateCompatibleBitmap( hdc, 350, 200 ); SelectObject( bkhdc, dataBitmap ); // Draw in background, WM_PAINT displays it // lfHeight = -MulDiv( 20, GetDeviceCaps( hdc, LOGPIXELSY ), 72 ); // for Leto, etc. lfHeight = -MulDiv( 14, GetDeviceCaps( hdc, LOGPIXELSY ), 72 ); // for Loki hf = CreateFontA( lfHeight, 0, 0, 0, 600, 0, 0, 0, 0, 0, 0, 0, FIXED_PITCH, "Liberation Mono"); SelectObject( hdcdata, hf ); // Add the new font to the data display hdc iVscrollMax = SZ - (cyClient-1); iVscrollPos = 0; SetScrollRange (hwnd, SB_VERT, 0, iVscrollMax, FALSE) ; SetScrollPos (hwnd, SB_VERT, iVscrollPos, TRUE) ; iHscrollMax = SZ - (cxClient-1); iHscrollPos = 0; SetScrollRange (hwnd, SB_HORZ, 0, iHscrollMax, FALSE) ; SetScrollPos (hwnd, SB_HORZ, iHscrollPos, TRUE) ; break; case WM_PAINT: // Blit background to foreground hdc = BeginPaint( hwnd, &ps ); SelectObject( bkhdc, bkBitmap ); // Select background bitmap SelectObject( bkhdc, dataBitmap ); // Select data bitmap BitBlt( hdc , 0, 0, cxClient, cyClient, bkhdc, iHscrollPos, iVscrollPos, SRCCOPY ); if( data ) // Display population data BitBlt( hdc, cxClient-350, 0, cxClient, cyClient, hdcdata, 0, 0, SRCINVERT); // Notice source DC EndPaint( hwnd, &ps ); break; case WM_RBUTTONDOWN: firstClick = false; // Cancel inadvertent clicks break; case WM_LBUTTONDOWN: mouseClickDownPos.x = LOWORD(lParam); mouseClickDownPos.y = HIWORD(lParam); if( !firstClick ) // First click of sample area { firstClick = true; UL.x = mouseClickDownPos.x; UL.y = mouseClickDownPos.y; // printf("First click at %ld, %ld\n", UL.x, UL.y ); // printf("bitmap coordinates %ld, %ld\n", iHscrollPos + UL.x, iVscrollPos + UL.y ); } else { LR.x = mouseClickDownPos.x; // The second click of the area LR.y = mouseClickDownPos.y; // printf("Second click at %ld, %ld\n", LR.x, LR.y ); // printf("bitmap coordinates %ld, %ld\n", iHscrollPos + LR.x, iVscrollPos + LR.y ); // printf("Width %ld, Height %ld\n", LR.x - UL.x, LR.y - UL.y ); firstClick = false; spotSample(); // Store a spot sample of the ecosystem } break; case WM_LBUTTONUP: break; case WM_KEYDOWN: switch (wParam) // Redundancies and gaps { case VK_HOME: SendMessage( hwnd, WM_VSCROLL, SB_TOP, 0L); break; case VK_END: SendMessage( hwnd, WM_VSCROLL, SB_BOTTOM, 0L); break; case VK_PRIOR: SendMessage( hwnd, WM_VSCROLL, SB_PAGEUP, 0L); break; case VK_NEXT: SendMessage( hwnd, WM_VSCROLL, SB_PAGEDOWN, 0L); break; case VK_UP: SendMessage( hwnd, WM_VSCROLL, SB_PAGEUP, 0L); break; case VK_DOWN: SendMessage( hwnd, WM_VSCROLL, SB_PAGEDOWN, 0L); break; case VK_LEFT: SendMessage( hwnd, WM_HSCROLL, SB_PAGELEFT, 0L); break; case VK_RIGHT: SendMessage( hwnd, WM_HSCROLL, SB_PAGERIGHT, 0L); break; case 'a': // Call Age of Maturity dialog case 'A': pause = true; DialogBox( hInst, MAKEINTRESOURCE( IDD_MATURITY_DIALOG ), hwnd, &MaturityDialogProc ); pause = false; break; case 'd': // Toggle data display case 'D': data ^= true; break; case 'h': // Display help message case 'H': DialogBox( hInst, MAKEINTRESOURCE( IDD_HELP_DIALOG ), hwnd, &HelpDialogProc ); break; case 'l': // Save spot sample file case 'L': store ^= true; break;// This is in spotSample case 'm': // Call Metabolic dialog case 'M': pause = true; DialogBox( hInst, MAKEINTRESOURCE( IDD_METABOLIC_DIALOG ), hwnd, &MetabolicDialogProc ); pause = false; break; case 'n': case 'N': logNutrients(); break; // Store the current E(i,j)->nutrient layer case 'r': // Call Reproduction dialog case 'R': pause = true; DialogBox( hInst, MAKEINTRESOURCE( IDD_REPRODUCTION_DIALOG ), hwnd, &ReproductionDialogProc ); pause = false; break; case 's': // Call Senescence dialog case 'S': pause = true; DialogBox( hInst, MAKEINTRESOURCE( IDD_SENESCENCE_DIALOG ), hwnd, &SenescenceDialogProc ); pause = false; break; case 't': // Call Satiety dialog case 'T': pause = true; DialogBox( hInst, MAKEINTRESOURCE( IDD_SATIETY_DIALOG ), hwnd, &SatietyDialogProc ); pause = false; break; case 'q': // Quit the application case 'Q': ExitProcess(0); break; } break; case WM_GETMINMAXINFO: minMax = (MINMAXINFO FAR *) lParam; // Set the MINMAXINFO structure pointer minMax->ptMaxSize.x = SZ; minMax->ptMaxSize.y = SZ; minMax->ptMinTrackSize.x = WINX; minMax->ptMinTrackSize.y = WINY; minMax->ptMaxTrackSize.x = SZ; minMax->ptMaxTrackSize.y = SZ; break; case WM_SIZE: cxClient = LOWORD (lParam); // Width of rectangle cyClient = HIWORD (lParam); // Height of rectangle iVscrollMax = SZ - (cyClient-1); // Lower boundary iVscrollPos = min( iVscrollPos, iVscrollMax ); SetScrollRange( hwnd, SB_VERT, 0, iVscrollMax, FALSE); SetScrollPos ( hwnd, SB_VERT, iVscrollPos, TRUE); if( (SZ - (cxClient-1)) < 0 ) // If the client window is wider than SZ { iHscrollMax = SZ; cxClient = SZ; // Try commenting this out Jan 14 9:24 PM kjr } else iHscrollMax = SZ - (cxClient-1); // Right boundary iHscrollPos = min (iHscrollPos, iHscrollMax); SetScrollRange (hwnd, SB_HORZ, 0, iHscrollMax, FALSE); SetScrollPos (hwnd, SB_HORZ, iHscrollPos, TRUE); break; case WM_VSCROLL : switch (LOWORD (wParam)) { case SB_TOP : iVscrollInc = -iVscrollPos ; break ; case SB_BOTTOM : iVscrollInc = iVscrollMax - iVscrollPos ; break ; case SB_LINEUP : iVscrollInc = -20 ; break ; case SB_LINEDOWN : iVscrollInc = 20 ; break ; case SB_PAGEUP : iVscrollInc = -100 ; break ; case SB_PAGEDOWN : iVscrollInc = 100 ; break ; case SB_THUMBTRACK : iVscrollInc = HIWORD (wParam) - iVscrollPos ; break ; default : iVscrollInc = 0 ; } iVscrollInc = max( -iVscrollPos, min( iVscrollInc, iVscrollMax - iVscrollPos)) ; if (iVscrollInc != 0) { iVscrollPos += iVscrollInc ; ScrollWindow( hwnd, 0, -iVscrollInc, NULL, NULL) ; SetScrollPos( hwnd, SB_VERT, iVscrollPos, TRUE) ; UpdateWindow( hwnd) ; } break; case WM_MOUSEWHEEL: // Adjust torsion rate zDelta = GET_WHEEL_DELTA_WPARAM( wParam ); if( zDelta > 0 ) SendMessage( hwnd, WM_VSCROLL, SB_LINEUP, 0L); // This may be opposite else SendMessage( hwnd, WM_VSCROLL, SB_LINEDOWN, 0L);// It is CORRECT!! :) break; case WM_HSCROLL : switch (LOWORD (wParam)) { case SB_LINEUP : iHscrollInc = -20 ; break ; case SB_LINEDOWN : iHscrollInc = 20 ; break ; case SB_PAGEUP : iHscrollInc = -100 ; break ; case SB_PAGEDOWN : iHscrollInc = 100 ; break ; case SB_THUMBTRACK : iHscrollInc = HIWORD (wParam) - iHscrollPos ; break ; default : iHscrollInc = 0 ; } iHscrollInc = max( -iHscrollPos, min( iHscrollInc, iHscrollMax - iHscrollPos)) ; if (iHscrollInc != 0) { iHscrollPos += iHscrollInc ; ScrollWindow (hwnd, -iHscrollInc, 0, NULL, NULL) ; SetScrollPos (hwnd, SB_HORZ, iHscrollPos, TRUE) ; } break; case WM_DESTROY: DeleteObject( bkBitmap ); // Clean up on aisle six. DeleteObject( dataBitmap ); DeleteDC( bkhdc ); DeleteDC( hdcdata ); PostQuitMessage(0); // Hilsen break; default: return DefWindowProc(hwnd, msg, wParam, lParam); } return (LRESULT) NULL; } ////////////////////////////////////////////////////////////////////////////////////////// ////// Functions() ///////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// void initEcosystem( void ) // Initialize primary ecosystem buffer { for(int j=0; jnutrient = 250; // PFA number (E +j*SZ +i)->P = NULL; // No one lives here at present (E +j*SZ +i)->H = NULL; (E +j*SZ +i)->C = NULL; // Dave's not here man } } void initPlants( void ) { int X, Y; // Prospective location for(int i=0; iP ); // When a plant is resident (PL+i)->X.x = X; // Remember where I live. (PL+i)->X.y = Y; (E +Y*SZ +X)->P = (PL+i); // Point at plant. (PL+i)->EN = (chromosome) rand(); // Create energy chromosome. (PL+i)->PL = (chromosome) rand(); // Create plant chromosome. (PL+i)->GM = (chromosome) 3115; // Maternal genetic marker. (PL+i)->alive = true; // I can feel the sun. (PL+i)->energy = 80; // PFA number (PL+i)->age = 1; // Day of birth } } void initHerbivores( void ) { int X, Y; // Prospective location of herbivore for(int i=0; iH ); // Occupado (HL+i)->X.x = X; // Where are my keys? (HL+i)->X.y = Y; (E +Y*SZ +X)->H = (HL+i); // Point at herbivore (HL+i)->EN = (chromosome) rand(); // Create energy chromosome (HL+i)->SN = (chromosome) rand(); // Create sensor chromosome (HL+i)->HB = (chromosome) rand(); // Create herbivore chromosome (HL+i)->DR = (chromosome) rand(); // Create direction chromosome (HL+i)->GM = (chromosome) 3049; (HL+i)->alive = true; (HL+i)->energy = 120; // PFA number (HL+i)->age = 1; } } void initCarnivores( void ) { int X, Y; // Prospective location of herbivore for(int i=0; iC ); // Find your own lair (CL+i)->X.x = X; // Remember where I live (CL+i)->X.y = Y; (E +Y*SZ +X)->C = (CL+i); // Point at carnivore (CL+i)->EN = (chromosome) rand(); // Create energy chromosome (CL+i)->SN = (chromosome) rand(); // Create sensor chromosome (CL+i)->CN = (chromosome) rand(); // Create carnivore chromosome (CL+i)->DR = (chromosome) rand(); // Create direction chromosome (CL+i)->GM = (chromosome) 4021; (CL+i)->alive = true; (CL+i)->energy = 300; // PFA number (CL+i)->age = 1; } } void moveHerbivores( void ) { struct vt A, B, C; // Working vectors int min, ring, ch, speed; for(int i=0; iDR & (7 << 28)) >> 28) + min; A = (HL+i)->X; // Current location do { // Find an open spot within range ring = min + rand()%speed; // {min <= ring < speed} B = scale( ring, move( (HL+i)->DR ) ); // Express direction genes C = bound( sum( A, B ) ); // Prospective new location if( ch > 8 ) break; else ch++; // Limit search count to 8 choices } while( (E +C.y*SZ +C.x)->H ); // While location is occupied (E +A.y*SZ +A.x)->H = NULL; // Empty old location (HL+i)->X = C; // Remember where I live (E +C.y*SZ +C.x)->H = (HL+i); // Fill new location } } void moveCarnivores( void ) { struct vt A, B, C; // Current position, move, prospective int min, ring, ch, speed; for(int i=0; iDR & (7 << 28)) >> 28) + min; A = (CL+i)->X; // Current location do { // Find an open spot within range ring = min + rand()%speed; // {min <= ring < speed} B = scale( ring, move( (CL+i)->DR ) ); // Motion vector from DR chromosome C = bound( sum( A, B ) ); // Search location if( ch > 8 ) break; else ch++; // All your choice are us } while( (E +C.y*SZ +C.x)->C ); // Carnivore already lives here (E +A.y*SZ +A.x)->C = NULL; // Blank old spot (CL+i)->X = C; // Remember where I live (E +C.y*SZ +C.x)->C = (CL+i); // Inhabit new spot } } //////////////////////////////////////////////////////////////////////////////////////// ///////////// Parameter Tweaking Section ///////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// // float PMoffset = 3.1, HMoffset = 4.2, CMoffset = 5.3; // (PL+i)->energy -= (float) ((PL+i)->EN & 3) + PMoffset; // EN::G5 3.1 - 10.1 // (HL+i)->energy -= (float) ((HL+i)->EN & 7) + HMoffset; // EN::G5 4.2 - 11.2 // (CL+i)->energy -= (float) ((CL+i)->EN & 7) + CMoffset; // EN::G5 5.3 - 12.3 float metabolize( void ) // Sum energy lost by all organisms { float energy = 0; // Balance global energy loss and gain for(int i=0; iage += 1; // EN::G5 3.1 - 6.1 (PL+i)->energy -= (float) ((PL+i)->EN & 3) + PMoffset; energy += (float) ((PL+i)->EN & 3) + PMoffset; } for(int i=0; iage += 1; // EN::G5 4.2 - 11.2 (HL+i)->energy -= (float) ((HL+i)->EN & 7) + HMoffset; energy += (float) ((HL+i)->EN & 7) + HMoffset; } for(int i=0; iage += 1; // EN::G5 5.3 - 12.3 (CL+i)->energy -= (float) ((CL+i)->EN & 7) + CMoffset; energy += (float) ((CL+i)->EN & 7) + CMoffset; } return energy; // Pass energy use to replenish() } void replenish( float energy ) // Balance energy lost during metabolism { emin = 1e5; emax = -1e5; // Guard the endpoints for(int i=0; inutrient += energy / (SZ*SZ) + 0.7; // Spread energy evenly across ecosystem if( (E+i)->nutrient < emin ) emin = (E+i)->nutrient; // Determine extrema if( (E+i)->nutrient > emax ) emax = (E+i)->nutrient; } } // int PNoffset = 5, HNoffset = 19, CNoffset = 39; // Psenescence = (int) (((PL+i)->EN & (7 << 22)) >> 22) + PNoffset; // 5 - 12 // Hsenescence = (int) (((HL+i)->EN & (31 << 22)) >> 22) + HNoffset; // 19 - 50 // Csenescence = (int) (((CL+i)->EN & (31 << 22)) >> 22) + CNoffset; // 39 - 70 void die( void ) { for(int i=0; iEN & (15 << 22)) >> 22) + PNoffset; // 5 - 20 if( (PL+i)->energy < 0 ) (PL+i)->alive = false; // Like a tumblin' tumbleweed. else if( (PL+i)->age > Psenescence ) { (E +(PL+i)->X.y*SZ +(PL+i)->X.x)->nutrient = (PL+i)->energy; (PL+i)->alive = false; } } for(int i=0; iEN & (31 << 22)) >> 22) + HNoffset; if( (HL+i)->energy < 0 ) (HL+i)->alive = false; // Dave's not here man! else if( (HL+i)->age > Hsenescence ) { (E + (HL+i)->X.y*SZ +(HL+i)->X.x)->nutrient = (HL+i)->energy; (HL+i)->alive = false; } } Ceat = 0; // Count Ceat here even though it's not really eaten, just dead. for(int i=0; iEN & (31 << 22)) >> 22) + CNoffset; if( (CL+i)->energy < 0 ) (CL+i)->alive = false; else if( (CL+i)->age > Csenescence ) { // Ceat is stored in dt.dat along with Peat, and Heat (E +(CL+i)->X.y*SZ + (CL+i)->X.x)->nutrient = (CL+i)->energy; (CL+i)->alive = false; // This parrot has ceased to be. Ceat++; } } } // absorb = (float) ((((PL+i)->EN & (7 << 7)) >> 7) + 1.0) / 15.0; // EN::G4 0.07 - 0.53 // absorb = (float) ((((HL+i)->EN & (7 << 7)) >> 7) + 1.0) / 10.0; // EN::G4 0.1 - 0.8 // absorb = (float) ((((CL+i)->EN & (7 << 7)) >> 7) + 1.0) / 8.0; // EN::G4 0.125 - 1.0 // float PSoffset = 29.1, HSoffset = 56.1, CSoffset = 1.2; // satiety = (float) (((PL+i)->EN & (63 << 10)) >> 10) + PSoffset; // EN::G3 19.1 - 82.1 // satiety = (float) (((HL+i)->EN & (63 << 10)) >> 10) + HSoffset; // EN::G3 56.1 - 119.1 // satiety = (float) (((CL+i)->EN & (7 << 10)) >> 10) + CSoffset; // EN::G3 8.0 - 15.0 void eat( void ) { struct pnode *P; // Point at plants struct hnode *H; // Point at herbivores struct vt A, B, C; // Working vectors int j, ring; // Direction, ring# int ch, speed; // Choice counter, express gene DR::G0 float satiety, absorb; // Genetic expression buffers float spine, eat; // Plant vs Herbivore spine war float strength, resist; // Plant vs Herbivore poison war float camo, see; // Herbivore vs Carnivore camo war Peat = Heat = 0; // Count the eaten // Ceat is calculated in die() // Plants eat nutrients at E(x,y) only for(int i=0; iX; // 29.1 - 92.1 satiety = (float) (((PL+i)->EN & (63 << 10)) >> 10) + PSoffset; // EN::G3 19.1 - 82.1 if( (PL+i)->energy < satiety ) // Am I hungry? { // printf("p"); // EN::G4 7.1% - 53.3% 1/15 to 8/15 absorb = (float) ((((PL+i)->EN & (7 << 7)) >> 7) + 1.0) / 15.0; (PL+i)->energy += (E +C.y*SZ +C.x)->nutrient * absorb; // Add energy to plant (E +C.y*SZ +C.x)->nutrient -= (E +C.y*SZ +C.x)->nutrient * absorb;// Remove from nutrient layer } } // Herbivores eat at E(x,y) and the rings around it for(int i=0; iDR & (7 << 24)) >> 24) + 12; // 12 - 19 DR::G0 satiety = (float) (((HL+i)->EN & (63 << 10)) >> 10) + HSoffset; // EN::G3 56.1 - 119.1 eat = (float) ((((HL+i)->HB & (63 << 6)) >> 6) + 1.0) / 65.0; // HB::G1 Eat spines resist = (float) ((((HL+i)->HB & (63 << 12)) >> 12) + 1.0) / 65.0; // HB::G0 Resist poisons A = (HL+i)->X; // Current location while( true ) // Forever loop requires break out { ring = rand()%speed; // {0 <= ring < speed} B = scale( ring, move( (HL+i)->DR ) ); // Express direction genes DR::G1..G8 C = bound( sum( A, B ) ); // Prospective new location // If there's a plant & you're hungry if( (E +C.y*SZ +C.x)->P && ((HL+i)->energy < satiety )) { P = (E +C.y*SZ +C.x)->P; // Point to plant at E(x,y) absorb EN::G4 spine = (float) ((((PL+i)->PL & (63 << 18)) >> 18) + 1.0) / 65.0; // PL::G1 spine probability strength = (float) ((((PL+i)->PL & (63 << 12)) >> 12) + 1.0) / 65.0; // PL::G2 poison strength // if( (resist >= strength) && (eat >= spine) ) if( resist >= strength ) { // HL::HB::G4 > PL::PL::G2 && HL::HB::G3 >= PL::PL::G3 absorb = (float) ((((HL+i)->EN & (7 << 7)) >> 7) + 1.0) / 12.0; // 0.083 0.667 (HL+i)->energy += P->energy * absorb; // Add energy to herbivore P->energy -= P->energy * absorb; // Remove energy from plant (E +C.y*SZ +C.x)->nutrient += P->energy; // Remainder to nutrient layer (E +C.y*SZ +C.x)->P = NULL; // Plant no longer exists here P->alive = false; // Plant is deceased Peat++; // Count the fodder } } if( ch > 29 ) break; else ch++; // Limit search count } } // Carnivores eat in rings around E(x,y) along the 8 primary directions. for(int i=0; iDR & (7 << 24)) >> 24) + 12; // DR::G0 12 - 27 see = (float) (((CL+i)->SN & 63) + 1.0) / 65.0; // SN::G5 sight ability satiety = (float) (((CL+i)->EN & (15 << 10)) >> 10) + CSoffset; // 1.2 - 16.2 // A = (CL+i)->X; // Where did I park my car? while( true ) // Feast until sated { ring = rand()%speed; // {0 <= ring < speed} DR::G1..G8 B = scale( ring, move( (CL+i)->DR ) ); // Motion vector from DR chromosome C = bound( sum( A, B ) ); // Prospective new location // Is there a herbivore and am I hungry? if( (E +C.y*SZ +C.x)->H && ((CL+i)->energy < satiety) ) { // HB::G5 camouflage effectiveness H = (E +C.y*SZ +C.x)->H; // Point to herbivore at E(x,y) 1/9 to 8/9 camo = (float) (((HL+i)->HB & 63) + 1.0) / 65.0; // HB::G2 Herbivore camouflage if( see >= camo ) // CL::SN::G5 >= HL::HB::G5 { absorb = (float) ((((CL+i)->EN & (7 << 7)) >> 7) + 1.0) / 9.0; // 0.111 - 0.889 (CL+i)->energy += H->energy * absorb; // Add energy to carnivore H->energy -= H->energy * absorb; // Remove energy from herbivore (E +C.y*SZ +C.x)->nutrient += H->energy; // Remainder to nutrient layer (E +C.y*SZ +C.x)->H = NULL; // Herbivore no longer exists here H->alive = false; // Herbivore is deceased Heat++; // Count the fallen } } // Is 57 excessive? if( ch > 57 ) break; else ch++; // All your choice are us. } } } // End of eat() // float PRenergy = 12.5, HRenergy = 65.0, CRenergy = 35.5; // int PAoffset = 1, HAoffset = 1, CAoffset = 3; void reproduce( void ) { int maturity, nw; // Age, new organism counter float satiety; // Am I hungry? struct vt A, B, C; // Working vectors newPpop = newHpop = newCpop = 0; // Clear population counters here // 4000 * 4000 = 16,000,000 9/16 = 0.5625 9.5 Million seg faulted if( Ppop < SZ*SZ*0.5 ) // HARD limit proportional to grid size { nw = 0; for(int i=0; iEN & (7 << 10)) >> 10) + 1.0; EN::G3 1.0 - 8.0 // if( ((PL+i)->age > maturity ) && ((PL+i)->energy > satiety ) ) // maturity = (int) (((PL+i)->EN & (3 << 19)) >> 19) + PAoffset; // EN::G2 maturity = 2; if( ((PL+i)->age > maturity) && ((PL+i)->energy > PRenergy) ) { // && pollen > 0.25??? A = (PL+i)->X; // Location of parent plant. int r = rand()%Ppop; // Select random mate // maturity = (int) (((PL+r)->EN & (3 << 19)) >> 19) + PAoffset; // 1 - 4 maturity = 2; if( ((PL+r)->age > maturity) && ((PL+r)->energy > PRenergy) ) { // Need to find an empty spot in E int j = 1; // Skip center spot int ring = 5; // Pollination inner boundary do { B = scale( ring, dir[j] ); // Motion vector C = bound( sum( A, B ) ); // Prospective new location j++; // Walk around direction vector if( j > 8 ) // End of dir[] { j = 1; // Skip center location ring++; // Search next outer ring } if( ring > 25 ) break; // The Outer Limit!! PFA number } while( (E +C.y*SZ +C.x)->P ); // Occupied // New plant needs to be filled (NP+nw)->X = C; // Put plant at new location (NP+nw)->energy = (PL+i)->energy * 0.125; // Natal energy (NP+nw)->energy += (PL+r)->energy * 0.125; // 1/8 from each parent // 1/16 energy of each parent goes to the nutrient layer (E +(PL+i)->X.y*SZ + (PL+i)->X.x)->nutrient += (PL+i)->energy * 0.0625; (E +(PL+r)->X.y*SZ + (PL+r)->X.x)->nutrient += (PL+r)->energy * 0.0625; // 3/16 of the energy of each parent is expended during reproduction (PL+i)->energy -= (PL+i)->energy * 0.1875; // Mother loses 3/16 of her energy (PL+r)->energy -= (PL+r)->energy * 0.1875; // Father loses 3/16 of his energy // Form new chromosomes for offspring (NP+nw)->EN = crossover( (PL+i)->EN, (PL+r)->EN ); // Crossover both plant's (NP+nw)->PL = crossover( (PL+i)->PL, (PL+r)->PL ); // Chromosomes (NP+nw)->GM = (PL+i)->GM; // Pass Mom's genetic marker on intact. /* if( (NP+nw)->GM != 3855 ) if( fRan() > 0.5 ) // Mutate marked plants { (NP+nw)->EN = mutation( (NP+nw)->PL ); (NP+nw)->PL = mutation( (NP+nw)->PL ); } */ // My name is 905 (NP+nw)->alive = true; // and I've just become alive (NP+nw)->age = 1; // I'm the newest populator // of the planet called Earth. (E +C.y*SZ +C.x)->P = (NP+nw); // Point to plant data nw++; // Add new plant to count } } } newPpop = nw; // Set new plant list counter } // End of plant population limiter nw = 0; for(int i=0; iEN & 3 + HAoffset; // EN::G2 // satiety = (float) (((HL+i)->EN & (31 << 10)) >> 10) + 21.0; // if( ( (HL+i)->age > maturity ) && ((HL+i)->energy > satiety ) ) if( ((HL+i)->age > maturity) && ((HL+i)->energy > HRenergy) ) // PFA number { A = (HL+i)->X; // Location of parent plant. int r = rand()%Hpop; // Select random mate // Check whether (PL+r) is Old enough maturity = (int) (HL+r)->EN & 3 + HAoffset; // At least one day old // satiety = (float) (((HL+i)->EN & (31 << 10)) >> 10) + 21.0; // if( ( (HL+r)->age > maturity ) && ((HL+r)->energy > satiety ) ) if( ((HL+r)->age > maturity) && ((HL+r)->energy > HRenergy) ) // PFA number 125.0 { // Need to find an empty spot in E int j = 1; // Skip center spot int ring = 4; // Offspring inner boundary do { B = dir[ j ]; // Walk around each direction B = scale( ring, B ); // Motion vector C = bound( sum( A, B ) ); // Prospective new location j++; // Walk around direction vector if( j > 8 ) // End of dir[] { j = 1; // Search ring++; // next outer ring } if( ring > 14 ) break; } while( (E +C.y*SZ +C.x)->H ); // Is this seat taken? // New herbivore needs to be prepared (NH+nw)->X = C; // Remember where I left my keys (NH+nw)->energy = (HL+i)->energy * 0.125; // Offspring gains natal energy (NH+nw)->energy += (HL+r)->energy * 0.125; // 1/8 from each parent // 1/16 energy of each parent goes to the nutrient layer (E +(PL+i)->X.y*SZ + (HL+i)->X.x)->nutrient += (HL+i)->energy * 0.0625; (E +(PL+r)->X.y*SZ + (HL+r)->X.x)->nutrient += (HL+r)->energy * 0.0625; // Afterbirth from mother (E +C.y*SZ +C.x)->nutrient += (HL+i)->energy * 0.0625; // 1/16 // Energy of each parent is expended during reproduction (HL+i)->energy -= (HL+i)->energy * 0.250; // Mother loses 1/4 of her energy (HL+r)->energy -= (HL+r)->energy * 0.1875; // Father loses 3/16 of his energy (NH+nw)->EN = crossover( (HL+i)->EN, (HL+r)->EN ); // Crossover: Energy (NH+nw)->DR = crossover( (HL+i)->DR, (HL+r)->DR ); // Direction genes (NH+nw)->SN = crossover( (HL+i)->SN, (HL+r)->SN ); // Sensor genes (NH+nw)->HB = crossover( (HL+i)->HB, (HL+r)->HB ); // Herbivore genes (NH+nw)->GM = (HL+i)->GM; // Pass Mom's genetic marker on intact. (NH+nw)->alive = true; // The Quickening (NH+nw)->age = 1; // Day one of a new life (E +C.y*SZ +C.x)->H = (NH + nw); // Take up residence in my new home nw++; // Add new plant to count } } } newHpop = nw; // Set new herbivore list counter nw = 0; for(int i=0; iEN & 7 + CAoffset; // EN::G2 // satiety = (float) (((CL+i)->EN & (15 << 10)) >> 10) + 20.0; // if( ( (CL+i)->age > maturity ) && ((CL+i)->energy > satiety ) ) if( ((CL+i)->age > maturity) && ((CL+i)->energy > CRenergy) ) // PFA number 43.7 { A = (CL+i)->X; // Location of parent herbivore. int r = rand()%Cpop; // Select random mate // Check whether (PL+r) is Old enough maturity = (int) (CL+r)->EN & 7 + CAoffset; // EN::G2 // satiety = (float) (((CL+i)->EN & (15 << 10)) >> 10) + 20.0; // if( ((CL+r)->age > maturity) && ((CL+r)->energy > satiety) ) if( ((CL+r)->age > maturity) && ((CL+r)->energy > CRenergy) ) // PFA number { // Need to find an empty spot in E and in OE int j = 1; // Skip the center spot int ring = 3; // Inner offspring boundary do { B = dir[ j ]; // Walk around B = scale( ring, B ); // the motion vector C = bound( sum( A, B ) ); // Prospective new location j++; // Walk around motion vector if( j > 8 ) // Limit search count { j = 1; ring++; } if( ring > 9 ) break; // You have examined them all } while( (E +C.y*SZ +C.x)->C ); // New carnivore needs to be filled (NC+nw)->X = C; // Put carnivore at new location // Do we need a reproductive efficiency gene?? on HB and CN ?? (NC+nw)->energy = (CL+i)->energy * 0.125; // Natal energy (NC+nw)->energy += (CL+r)->energy * 0.125; // 1/8 from each parent // 1/8 energy of each parent goes to the nutrient layer (E +(CL+i)->X.y*SZ + (CL+i)->X.x)->nutrient += (CL+i)->energy * 0.0625; (E +(CL+r)->X.y*SZ + (CL+r)->X.x)->nutrient += (CL+r)->energy * 0.0625; // Afterbirth energy loss from mother (E +C.y*SZ +C.x)->nutrient += (CL+i)->energy * 0.0625; // 1/16 // Energy of each parent is expended during reproduction (CL+i)->energy -= (CL+i)->energy * 0.250; // Mother loses 1/4 of her energy (CL+r)->energy -= (CL+r)->energy * 0.1875; // Father loses 3/16 of his energy (NC+nw)->EN = crossover( (CL+i)->EN, (CL+r)->EN ); // Crossover (NC+nw)->SN = crossover( (CL+i)->SN, (CL+r)->SN ); // Chromosomes (NC+nw)->CN = crossover( (CL+i)->CN, (CL+r)->CN ); // for offspring (NC+nw)->DR = crossover( (CL+i)->DR, (CL+r)->DR ); // genetics (NC+nw)->GM = (CL+i)->GM; // Pass Mom's genetic marker on intact. (NC+nw)->alive = true; (NC+nw)->age = 1; // Newly born (E +C.y*SZ +C.x)->C = (NC + nw); // Point to plant data nw++; // Add new plant to count } } } newCpop = nw; // Set new plant list counter with offset } // End of reproduce() void cull( void ) // Garbage collection using twin buffers { int k=0, q=0, c=0; // Organism counters Need globally struct vt T; // Working vector pmin = hmin = cmin = 1e5; // Guard the Outer Limits pmax = hmax = cmax = -1e5; for(int i=0; ialive ) { if( (PL+i)->energy < pmin ) pmin = (PL+i)->energy; if( (PL+i)->energy > pmax ) pmax = (PL+i)->energy; *(OPL+k) = *(PL+i); // Point at survivor node from alternate buffer k++; // Count the survivors. } else { T = (PL+i)->X; // Index Ecosystem plant location (E +T.y*SZ +T.x)->P = NULL; // NULL plant pointer } for(int i=0; ialive ) { if( (HL+i)->energy < hmin ) hmin = (HL+i)->energy; if( (HL+i)->energy > hmax ) hmax = (HL+i)->energy; *(OHL+q) = *(HL+i); // Does indeed deep copy all information q++; // Not quite, it is simply that the pointers } // Point to the same data. else { T = (HL+i)->X; (E +T.y*SZ +T.x)->H = NULL; } for(int i=0; ialive ) { if( (CL+i)->energy < cmin ) cmin = (CL+i)->energy; if( (CL+i)->energy > cmax ) cmax = (CL+i)->energy; *(OCL+c) = *(CL+i); // Copy survivor to 'other' list c++; // Count survivors } else { T = (CL+i)->X; (E +T.y*SZ +T.x)->C = NULL; } Ppop = k; Hpop = q; Cpop = c; // Update counters } // End of cull() void addNew( void ) { int X, Y; for(int i=0; iX.x; // Create indices Y = (NP+i)->X.y; (E +SZ*Y +X)->P = (OPL+Ppop+i); // Add new plant to ecosystem } for(int i=0; iX.x; Y = (NH+i)->X.y; (E +SZ*Y +X)->H = (OHL+Hpop+i); // Add new herbivore to ecosystem } for(int i=0; iX.x; Y = (NC+i)->X.y; (E +SZ*Y +X)->C = (OCL+Cpop+i); // Add new carnivore to ecosystem } Ppop += newPpop; Hpop += newHpop; Cpop += newCpop; } // End of addNew() void bufferSwap( void ) { if( even ) { PL = PL1; HL = HL1; CL = CL1; // Even step buffers OPL = PL2; OHL = HL2; OCL = CL2; // 'Other' list pointers :) even = false; } else { PL = PL2; HL = HL2; CL = CL2; // Odd step buffers OPL = PL1; OHL = HL1; OCL = CL1; even = true; } } //////////////////////////////////////////////////////////////////////////////////////// ///////////// Useful Tools /////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// struct vt vector( int x, int y ) // Mimic contents of v2.c { struct vt A; A.x = x; A.y = y; return A; } struct vt sum( struct vt A, struct vt B ) { struct vt C; C.x = A.x + B.x; C.y = A.y + B.y; return C; } struct vt scale( int sc, struct vt B ) { struct vt A; A.x = B.x * sc; A.y = B.y * sc; return A; } struct vt bound( struct vt C ) { if( C.x < 0 ) C.x += SZ; // Connect ends else if( C.x > SZ-1 ) C.x -= SZ; // to wrap if( C.y < 0 ) C.y += SZ; // around into else if( C.y > SZ-1 ) C.y -= SZ; // a toroidal space. return C; } // Mathematical dir[] :: { E, NE, N, NW, W, SW, S, SE } void initDir( void ) { int x = 1, y = 1; // For unit vectors dir[0] = vector( 0, 0 ); // Center dir[1] = vector( x, 0 ); // East dir[2] = vector( x, y ); // Northeast dir[3] = vector( 0, y ); // North dir[4] = vector( -x, y ); // Northwest dir[5] = vector( -x, 0 ); // West dir[6] = vector( -x, -y ); // Southwest dir[7] = vector( 0, -y ); // South dir[8] = vector( x, -y ); // Southeast } struct vt move( chromosome DR ) // Get direction from chromosome { float dirProb[9]; // LBM version Math version dirProb[8] = (float) (DR & 7); // SW DR::G8 SE dirProb[7] = (float) ((DR & (7 << 3)) >> 3); // NW S dirProb[6] = (float) ((DR & (7 << 6)) >> 6); // SE SW dirProb[5] = (float) ((DR & (7 << 9)) >> 9); // NE W dirProb[4] = (float) ((DR & (7 << 12)) >> 12); // S NW dirProb[3] = (float) ((DR & (7 << 15)) >> 15); // N N dirProb[2] = (float) ((DR & (7 << 18)) >> 18); // W NE dirProb[1] = (float) ((DR & (7 << 21)) >> 21); // E DR::G1 E dirProb[0] = 0.0; // 0 is at the center DR::G0 is speed float tt = 0; // Eight directions, 3 bit probability range for(int i=1; i<9; i++) tt += dirProb[i]; // Sum probabilities for(int i=1; i<9; i++) dirProb[i] /= tt; // Normalize direction probabilities float rn = fRan(); // Gives us a number from 0.0 to 1.0 inclusive float sum = 0; int dr = 0; // Direction buffer while (sum < rn) // Sum probabilities until they exceed rn { dr++; // Step from 1 to 8 if necessary if (dr > 8) dr = 0; sum += dirProb[ dr ]; // Probabilities must total 1.00 } // for this to work properly // That is why we normalized the vector return dir[ dr ]; // Prospective direction } chromosome crossover( chromosome CM, chromosome CP ) // Chromosome crossover { int i = rand() % 31; // Determine crossover point CM >>= i; // Clear upper bits of Mama chromosome CM <<= i; CP <<= 31 - i; // Clear lower bits of Papa chromosome CP >>= 31 - i; if( fRan() > 0.97 ) return mutation( CM | CP ); // Mutate chromosome 3.0% of the time else return ( CM | CP ); // Merge upper and lower parts } chromosome mutation( chromosome C ) // Mutate DNA in this chromosome { int i = rand() % 31; return C ^= (1 << i); // Flip a single bit at i } // Returns index into palette[i] int colorTransform( int hiColor, int loColor, float hiProblem, float loProblem, float xw ) { return( (hiColor-loColor) / (hiProblem-loProblem) * (xw-loProblem) + loColor ); } void initPalette( void ) { int q = 0; // br[q++] = CreateSolidBrush( RGB( i, 0, 0) ); // Black to red transition // pn[k++] = CreatePen( PS_SOLID, 1, RGB( i, 0, 0) ); for(int i=0; i<256; i++) // from blue to red { palette[q].R = i; palette[q].G = 0; palette[q].B = 255-i; q++; } for(int i=0; i<256; i++) // from red to yellow { palette[q].R = 255; palette[q].G = i; palette[q].B = 0; q++; } for(int i=0; i<256; i++) // from yellow to white { palette[q].R = 255; palette[q].G = 255; palette[q].B = i; q++; } // for 768 colors from blue to white } ///////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// void displayData( int dd ) // Draw all of this to hdcdata { TCHAR text[80]; // Data buffer int num; // Character count SelectObject( hdcdata, dataBitmap ); // Draw text to background SetBkMode( hdcdata, TRANSPARENT ); // Letters float over scene SetTextColor( hdcdata, RGB( 220, 250, 247 ) ); // Sort of gray Is this necessary? TODO PatBlt( hdcdata, 0, 0, 350, 200, BLACKNESS ); // Set background of Data Display area num = sprintf( text, "Carnivores: %7d", Cpop ); TextOut( hdcdata, 20, 22, text, num ); num = sprintf( text, "Herbivores: %7d", Hpop ); TextOut( hdcdata, 20, 54, text, num ); num = sprintf( text, "Plants: %7d", Ppop ); TextOut( hdcdata, 20, 86, text, num ); num = sprintf( text, "Cycle: %7d", dd ); TextOut( hdcdata, 20, 118, text, num ); if( pause ) { num = sprintf( text, "PAUSED" ); TextOut( hdcdata, 20, 150, text, num ); } // num = sprintf( text, "Emax: %7d", emax ); // TextOut( hdcdata, 20, 182, text, num ); } void drawFrame( void ) // Draw frame of simulation { // emax starts at ~2200 float minE = 500.0, maxE = 6000.0; // PFA end point values for(int j=0; jnutrient ); SetPixel( bkhdc, i, j, RGB( palette[t].R, palette[t].G, palette[t].B ) ); } for(int i=0; iX.x, (PL+i)->X.y, RGB( 10, 250, 0 )); for(int i=0; iX.x, (HL+i)->X.y, RGB( 0, 10, 250 )); for(int i=0; iX.x, (CL+i)->X.y, RGB( 250, 0, 10 )); } #ifdef NOTES // How about toggle between show marked or unmarked plants??? if( mark ) { if( (PL+i)->GM == 3855 ) // Show only GM plants SetPixel( bkhdc, (PL+i)->X.x, (PL+i)->X.y, RGB( 0, 250, 250 )); } else SetPixel( bkhdc, (PL+i)->X.x, (PL+i)->X.y, RGB( 10, 250, 0 )); #endif ///////////////////////////////////////////////////////////////////////////////////////////////// /////////////// Data Logging Functions //////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// #define SAMPLE 5000 // Size of random organism samples // Sample buffers struct pnode *PS = (struct pnode *) malloc( SAMPLE * sizeof( struct pnode )); struct hnode *HS = (struct hnode *) malloc( SAMPLE * sizeof( struct hnode )); struct cnode *CS = (struct cnode *) malloc( SAMPLE * sizeof( struct cnode )); // Second sample buffers struct pnode *PB = (struct pnode *) malloc( SAMPLE * sizeof( struct pnode )); struct hnode *HB = (struct hnode *) malloc( SAMPLE * sizeof( struct hnode )); struct cnode *CB = (struct cnode *) malloc( SAMPLE * sizeof( struct cnode )); void logNutrients( void ) // And a count here too for SZ = ?? { FILE *fp = fopen("nut.dat", "w"); for(int i=0; inutrient ); fclose( fp ); } void loadNutrients( void ) // A count would be nice here { FILE *fp = fopen("nut.dat", "r"); if( fp ) // Check for NULL file { for(int i=0; inutrient ); fclose( fp ); } else initEcosystem(); // If there is no nutrient file } void storeGMSamples( void ) // Store 1000 samples of P, H, C population { FILE *fp; fp = fopen( "sample9GM.dat", "w" ); for(int i=0; i<1000; i++) { int R = rand()%Ppop; fprintf(fp, "%u %u %u %f %d\n", (PL+R)->EN, (PL+R)->PL, (PL+R)->GM, (PL+R)->energy, (PL+R)->age ); } for(int i=0; i<1000; i++) { int R = rand()%Hpop; fprintf(fp, "%u %u %u %u %u %f %d\n", (HL+R)->EN, (HL+R)->SN, (HL+R)->HB, (HL+R)->DR, (HL+R)->GM, (HL+R)->energy, (HL+R)->age ); } for(int i=0; i<1000; i++) { int R = rand()%Cpop; fprintf(fp, "%u %u %u %u %u %f %d\n", (CL+R)->EN, (CL+R)->SN, (CL+R)->CN, (CL+R)->DR, (CL+R)->GM, (CL+R)->energy, (CL+R)->age ); } fclose( fp ); } void loadGMSamples( void ) { FILE *fp; fp = fopen( "sample9GM.dat", "r" ); if( fp ) // Does .dat file exist? { for(int i=0; i<1000; i++) { fscanf(fp, "%u %u %u %f %d", &(PB+i)->EN, &(PB+i)->PL, &(PB+i)->GM, &(PB+i)->energy, &(PB+i)->age ); // if( fRan() > 37.5 ) (PB+i)->GM = 119; } for(int i=0; i<1000; i++) { fscanf(fp, "%u %u %u %u %u %f %d", &(HB+i)->EN, &(HB+i)->SN, &(HB+i)->HB, &(HB+i)->DR, &(HB+i)->GM, &(HB+i)->energy, &(HB+i)->age ); // if( fRan() > 13.1 ) (HB+i)->GM = 225; } for(int i=0; i<1000; i++) { fscanf(fp, "%u %u %u %u %u %f %d", &(CB+i)->EN, &(CB+i)->SN, &(CB+i)->CN, &(CB+i)->DR, &(CB+i)->GM, &(CB+i)->energy, &(CB+i)->age ); // if( fRan() > 43.9 ) (CB+i)->GM = 345; } fclose( fp ); } else // There was no data file to read { // initPlants(); // Create plants, fill ecosystem // initHerbivores(); // Create herbivores, fill ecosystem // initCarnivores(); // Into PL, HL, CL directly newPlants(); // Build in PB, HB, CB newHerbivores(); newCarnivores(); } } // All happy families are alike; every unhappy family is unhappy in its own way. void newPlants( void ) { int X, Y; // Prospective location for(int i=0; iEN = (chromosome) rand(); // Create energy chromosome. (PB+i)->PL = (chromosome) rand(); // Create plant chromosome. (PB+i)->GM = (chromosome) 61680; // Maternal genetic marker. // 61680 = 1111 0000 1111 0000 // 3855 = 0000 1111 0000 1111 (PB+i)->alive = true; // I can feel the sun. (PB+i)->energy = 80; // PFA number (PB+i)->age = 1; // Day of birth } } void newHerbivores( void ) // Make 5000 samples { int X, Y; // Prospective location of herbivore for(int i=0; iEN = (chromosome) rand(); // Create energy chromosome (HB+i)->SN = (chromosome) rand(); // Create sensor chromosome (HB+i)->HB = (chromosome) rand(); // Create herbivore chromosome (HB+i)->DR = (chromosome) rand(); // Create direction chromosome (HB+i)->GM = (chromosome) 61680; // Blank genetic marking (HB+i)->alive = true; (HB+i)->energy = 120; // PFA number (HB+i)->age = 1; } } void newCarnivores( void ) { int X, Y; // Prospective location of herbivore for(int i=0; iEN = (chromosome) rand(); // Create energy chromosome (CB+i)->SN = (chromosome) rand(); // Create sensor chromosome (CB+i)->CN = (chromosome) rand(); // Create carnivore chromosome (CB+i)->DR = (chromosome) rand(); // Create direction chromosome (CB+i)->GM = (chromosome) 61680; // Blank genetic marker (CB+i)->alive = true; (CB+i)->energy = 300; // PFA number (CB+i)->age = 1; } } void createPlants( void ) { int X, Y; // Prospective location for(int i=0; iEN = (chromosome) rand(); // Create energy chromosome. (PS+i)->PL = (chromosome) rand(); // Create plant chromosome. (PS+i)->GM = (chromosome) 3855; // Maternal genetic marker. // 61680 = 1111 0000 1111 0000 // 3855 = 0000 1111 0000 1111 (PS+i)->alive = true; // I can feel the sun. (PS+i)->energy = 80; // PFA number (PS+i)->age = 1; // Day of birth } } void createHerbivores( void ) // Make 1000 samples { int X, Y; // Prospective location of herbivore for(int i=0; iEN = (chromosome) rand(); // Create energy chromosome (HS+i)->SN = (chromosome) rand(); // Create sensor chromosome (HS+i)->HB = (chromosome) rand(); // Create herbivore chromosome (HS+i)->DR = (chromosome) rand(); // Create direction chromosome (HS+i)->GM = (chromosome) 3855; // Blank genetic marking (HS+i)->alive = true; (HS+i)->energy = 120; // PFA number (HS+i)->age = 1; } } void createCarnivores( void ) { int X, Y; // Prospective location of herbivore for(int i=0; iEN = (chromosome) rand(); // Create energy chromosome (CS+i)->SN = (chromosome) rand(); // Create sensor chromosome (CS+i)->CN = (chromosome) rand(); // Create carnivore chromosome (CS+i)->DR = (chromosome) rand(); // Create direction chromosome (CS+i)->GM = (chromosome) 3855; // Blank genetic marker (CS+i)->alive = true; (CS+i)->energy = 300; // PFA number (CS+i)->age = 1; } } void matureSamples( void ) // PB is filled by newPlants(), etc. { int X, Y; // Nutrient layer is already full from loadNutrients() // Ppop = 800000; Hpop = 200000; Cpop = 30000; // Numbers from current run time // Ppop = 500000; Hpop = 230000; Cpop = 50000; // Use global values instead for(int i=0; iP ); // When a plant is resident (PL+i)->X.x = X; // Find location (PL+i)->X.y = Y; (E +SZ*Y +X)->P = (PL+i); // Index it into E(i,j) (PL+i)->EN = (PS+R)->EN; // Copy chromosomes (PL+i)->PL = (PS+R)->PL; // 3855 = 0000 1111 0000 1111 (PL+i)->GM = (PS+R)->GM; // Maternal genetic marker (PL+i)->energy = (PS+R)->energy; // 61680 = 1111 0000 1111 0000 (PL+i)->age = (PS+R)->age; (PL+i)->alive = true; } for(int i=Ppop/2; iP ); // When a plant is resident (PL+i)->X.x = X; (PL+i)->X.y = Y; (E +SZ*Y +X)->P = (PL+i); (PL+i)->EN = (PB+R)->EN; (PL+i)->PL = (PB+R)->PL; (PL+i)->GM = (PB+R)->GM; (PL+i)->energy = (PB+R)->energy; (PL+i)->age = (PB+R)->age; (PL+i)->alive = true; } for(int i=0; iH ); // I'm busy here! (HL+i)->X.x = X; (HL+i)->X.y = Y; (E +SZ*Y +X)->H = (HL+i); (HL+i)->EN = (HS+R)->EN; (HL+i)->SN = (HS+R)->SN; (HL+i)->HB = (HS+R)->HB; (HL+i)->DR = (HS+R)->DR; (HL+i)->GM = 0; (HL+i)->energy = (HS+R)->energy; (HL+i)->age = (HS+R)->age; (HL+i)->alive = true; } for(int i=Hpop/2; iH ); (HL+i)->X.x = X; (HL+i)->X.y = Y; (E +SZ*Y +X)->H = (HL+i); (HL+i)->EN = (HB+R)->EN; (HL+i)->SN = (HB+R)->SN; (HL+i)->HB = (HB+R)->HB; (HL+i)->DR = (HB+R)->DR; (HL+i)->GM = (HB+R)->GM; // Pass mom's GM chromosome intact (HL+i)->energy = (HB+R)->energy; (HL+i)->age = (HB+R)->age; (HL+i)->alive = true; } for(int i=0; iC ); // Hey Yogi (CL+i)->X.x = X; (CL+i)->X.y = Y; (E +SZ*Y +X)->C = (CL+i); (CL+i)->EN = (CS+R)->EN; (CL+i)->SN = (CS+R)->SN; (CL+i)->CN = (CS+R)->CN; (CL+i)->DR = (CS+R)->DR; (CL+i)->GM = 0; (CL+i)->energy = (CS+R)->energy; (CL+i)->age = (CS+R)->age; (CL+i)->alive = true; } for(int i=Cpop/2; iC ); (CL+i)->X.x = X; (CL+i)->X.y = Y; (E +SZ*Y +X)->C = (CL+i); (CL+i)->EN = (CB+R)->EN; (CL+i)->SN = (CB+R)->SN; (CL+i)->CN = (CB+R)->CN; (CL+i)->DR = (CB+R)->DR; (CL+i)->GM = (CB+R)->GM; (CL+i)->energy = (CB+R)->energy; (CL+i)->age = (CB+R)->age; (CL+i)->alive = true; } } void matureNutrients( void ) { // We could call a dialog box here. // Ask if you want a new or old nutrient layer // Then ask about new PHC or old ones // or a mix of two populations // One marked for comparisons // Now we have an old nutrient layer // With a 1/2 :: 1/2 mix of old and new PHC loadNutrients(); // Read nutrient layer 'nut.dat' createPlants(); createHerbivores(); // Into buffer PS, HS, CS createCarnivores(); // loadSampTwo(); // Into buffers PB, HB, CB loadGMSamples(); // sample9GM.dat into PB, etc. or newPlants() ** matureSamples(); // Insert PS into 1/2, PB into 1/2 } void stamp( void ) // Add a time stamp to the data print out { time_t t; struct tm *nt; time( &t ); nt = localtime( &t ); if( nt->tm_hour < 10 ) printf("0"); printf("%d:", nt->tm_hour ); if( nt->tm_min < 10 ) printf("0"); printf("%d:", nt->tm_min ); if( nt->tm_sec < 10 ) printf("0"); printf("%d\n", nt->tm_sec ); } //////////////////////////////////////////////////////////////////////////////////////// ///////////// Dialog Box Procedures ////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// // Ppop = 500000; Hpop = 230000; Cpop = 50000; INT_PTR CALLBACK InitializeDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { // 'i' triggers me char strPpop[20]; char strHpop[20]; char strCpop[20]; switch (uMsg) { case WM_COMMAND: { switch(wParam) { case IDC_PUP: Ppop += 1000; if( Ppop > 5000000 ) Ppop = 5000000; sprintf( strPpop, "%d", Ppop ); SetDlgItemText( hwndDlg, IDC_PP, strPpop ); break; case IDC_PDN: Ppop -= 1000; if( Ppop < 50000 ) Ppop = 50000; sprintf( strPpop, "%d", Ppop ); SetDlgItemText( hwndDlg, IDC_PP, strPpop ); break; case IDC_HUP: Hpop += 1000; if( Hpop > 1000000 ) Hpop = 1000000; sprintf( strHpop, "%d", Hpop ); SetDlgItemText( hwndDlg, IDC_HP, strHpop ); break; case IDC_HDN: Hpop -= 1000; if( Hpop < 100000 ) Hpop = 100000; sprintf( strHpop, "%d", Hpop ); SetDlgItemText( hwndDlg, IDC_HP, strHpop ); break; case IDC_CUP: Cpop += 1000; if( Cpop > 1000000 ) Cpop =1000000; sprintf( strCpop, "%d", Cpop ); SetDlgItemText( hwndDlg, IDC_CP, strCpop ); break; case IDC_CDN: Cpop -= 1000; if( Cpop < 2000 ) Cpop = 2000; sprintf( strCpop, "%d", Cpop ); SetDlgItemText( hwndDlg, IDC_CP, strCpop ); break; case IDOK: GetDlgItemText( hwndDlg, IDC_PP, strPpop, 20 ); sprintf( strPpop, "%d", Ppop ); GetDlgItemText( hwndDlg, IDC_HP, strHpop, 20 ); sprintf( strHpop, "%d", Hpop ); GetDlgItemText( hwndDlg, IDC_CP, strCpop, 20 ); sprintf( strCpop, "%d", Cpop ); EndDialog( hwndDlg, 0 ); break; } switch (LOWORD(wParam)) { case IDCANCEL: { EndDialog( hwndDlg, (INT_PTR) LOWORD(wParam)); return (INT_PTR) TRUE; } } break; } case WM_INITDIALOG: sprintf( strPpop, "%d", Ppop ); // What variable ??? SetDlgItemText( hwndDlg, IDC_PP, strPpop); sprintf( strHpop, "%d", Hpop ); SetDlgItemText( hwndDlg, IDC_HP, strHpop); sprintf( strCpop, "%d", Cpop ); SetDlgItemText( hwndDlg, IDC_CP, strCpop ); return (INT_PTR) TRUE; } return (INT_PTR) FALSE; } // float PMoffset = 7.5, HMoffset = 4.2, CMoffset = 5.3; // EN::G5 7.5 - 14.5 INT_PTR CALLBACK MetabolicDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { // 'm' triggers me char strPenergy[20]; char strHenergy[20]; char strCenergy[20]; switch (uMsg) { case WM_COMMAND: { switch(wParam) { case IDC_PUP: PMoffset += 0.1; if( PMoffset > 20.0 ) PMoffset = 20.0; sprintf( strPenergy, "%6.2f", PMoffset ); SetDlgItemText( hwndDlg, IDC_PE, strPenergy ); break; case IDC_PDN: PRenergy -= 0.1; if( PMoffset < 1.0 ) PMoffset = 1.0; sprintf( strPenergy, "%6.2f", PMoffset ); SetDlgItemText( hwndDlg, IDC_PE, strPenergy ); break; case IDC_HUP: HMoffset += 0.1; if( HMoffset > 60.0 ) HMoffset = 60.0; sprintf( strHenergy, "%6.2f", HMoffset ); SetDlgItemText( hwndDlg, IDC_HE, strHenergy ); break; case IDC_HDN: HMoffset -= 0.1; if( HMoffset < 3.0 ) HMoffset = 3.0; sprintf( strHenergy, "%6.2f", HMoffset ); SetDlgItemText( hwndDlg, IDC_HE, strHenergy ); break; case IDC_CUP: CMoffset += 0.1; if( CMoffset > 70.0 ) CMoffset = 70.0; sprintf( strCenergy, "%6.2f", CMoffset ); SetDlgItemText( hwndDlg, IDC_CE, strCenergy ); break; case IDC_CDN: CMoffset -= 0.1; if( CMoffset < 3.0 ) CMoffset = 3.0; sprintf( strCenergy, "%6.2f", CMoffset ); SetDlgItemText( hwndDlg, IDC_CE, strCenergy ); break; case IDOK: GetDlgItemText( hwndDlg, IDC_PE, strPenergy, 20 ); sprintf( strPenergy, "%6.2f", PMoffset ); GetDlgItemText( hwndDlg, IDC_HE, strHenergy, 20 ); sprintf( strHenergy, "%6.2f", HMoffset ); GetDlgItemText( hwndDlg, IDC_CE, strCenergy, 20 ); sprintf( strCenergy, "%6.2f", CMoffset ); EndDialog( hwndDlg, 0 ); break; } switch (LOWORD(wParam)) { case IDCANCEL: { EndDialog( hwndDlg, (INT_PTR) LOWORD(wParam)); return (INT_PTR) TRUE; } } break; } case WM_INITDIALOG: sprintf( strPenergy, "%6.2f", PMoffset ); SetDlgItemText( hwndDlg, IDC_PE, strPenergy); sprintf( strHenergy, "%6.2f", HMoffset ); SetDlgItemText( hwndDlg, IDC_HE, strHenergy); sprintf( strCenergy, "%6.2f", CMoffset ); SetDlgItemText( hwndDlg, IDC_CE, strCenergy ); return (INT_PTR) TRUE; } return (INT_PTR) FALSE; } // float PRenergy = 12.5, HRenergy = 65.0, CRenergy = 35.5; INT_PTR CALLBACK ReproductionDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { // 'r' triggers me char strPenergy[20]; char strHenergy[20]; char strCenergy[20]; switch (uMsg) { case WM_COMMAND: { switch(wParam) { case IDC_PUP: PRenergy += 0.1; if( PRenergy > 90.0 ) PRenergy = 90.0; sprintf( strPenergy, "%6.2f", PRenergy ); SetDlgItemText( hwndDlg, IDC_PR, strPenergy ); break; case IDC_PDN: PRenergy -= 0.1; if( PRenergy < 5.0 ) PRenergy = 5.0; sprintf( strPenergy, "%6.2f", PRenergy ); SetDlgItemText( hwndDlg, IDC_PR, strPenergy ); break; case IDC_HUP: HRenergy += 0.1; if( HRenergy > 100.0 ) HRenergy = 100.0; sprintf( strHenergy, "%6.2f", HRenergy ); SetDlgItemText( hwndDlg, IDC_HR, strHenergy ); break; case IDC_HDN: HRenergy -= 0.1; if( HRenergy < 20.0 ) HRenergy = 20.0; sprintf( strHenergy, "%6.2f", HRenergy ); SetDlgItemText( hwndDlg, IDC_HR, strHenergy ); break; case IDC_CUP: CRenergy += 0.1; if( CRenergy > 100.0 ) CRenergy = 100.0; sprintf( strCenergy, "%6.2f", CRenergy ); SetDlgItemText( hwndDlg, IDC_CR, strCenergy ); break; case IDC_CDN: CRenergy -= 0.1; if( CRenergy < 10.0 ) CRenergy = 10.0; sprintf( strCenergy, "%6.2f", CRenergy ); SetDlgItemText( hwndDlg, IDC_CR, strCenergy ); break; case IDOK: GetDlgItemText( hwndDlg, IDC_PR, strPenergy, 20 ); sprintf( strPenergy, "%6.2f", PRenergy ); GetDlgItemText( hwndDlg, IDC_HR, strHenergy, 20 ); sprintf( strHenergy, "%6.2f", HRenergy ); GetDlgItemText( hwndDlg, IDC_CR, strCenergy, 20 ); sprintf( strCenergy, "%6.2f", CRenergy ); EndDialog( hwndDlg, 0 ); break; } switch (LOWORD(wParam)) { case IDCANCEL: { EndDialog( hwndDlg, (INT_PTR) LOWORD(wParam)); return (INT_PTR) TRUE; } } break; } case WM_INITDIALOG: sprintf( strPenergy, "%6.2f", PRenergy ); SetDlgItemText( hwndDlg, IDC_PR, strPenergy); sprintf( strHenergy, "%6.2f", HRenergy); SetDlgItemText( hwndDlg, IDC_HR, strHenergy); sprintf( strCenergy, "%6.2f", CRenergy); SetDlgItemText( hwndDlg, IDC_CR, strCenergy ); return (INT_PTR) TRUE; } return (INT_PTR) FALSE; } // PSoffset, HSoffset, CSoffset // satiety = (float) (((PL+i)->EN & (63 << 10)) >> 10) + 19.1; // EN::G3 19.1 - 82.1 // satiety = (float) (((HL+i)->EN & (63 << 10)) >> 10) + 56.1; // EN::G3 56.1 - 119.1 // satiety = (float) (((CL+i)->EN & (7 << 10)) >> 10) + 8.0; // EN::G3 8.0 - 15.0 INT_PTR CALLBACK SatietyDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { // 't' triggers me char strPenergy[20]; char strHenergy[20]; char strCenergy[20]; switch (uMsg) { case WM_COMMAND: { switch(wParam) { case IDC_PUP: PSoffset += 0.1; if( PSoffset > 100.0 ) PSoffset = 100.0; // {0..63} + sprintf( strPenergy, "%6.2f", PSoffset ); SetDlgItemText( hwndDlg, IDC_PS, strPenergy ); break; case IDC_PDN: PSoffset -= 0.1; if( PSoffset < 5.0 ) PSoffset = 5.0; sprintf( strPenergy, "%6.2f", PSoffset ); SetDlgItemText( hwndDlg, IDC_PS, strPenergy ); break; case IDC_HUP: HSoffset += 0.1; if( HSoffset > 130.0 ) HSoffset = 130.0; // {0..63} + sprintf( strHenergy, "%6.2f", HSoffset ); SetDlgItemText( hwndDlg, IDC_HS, strHenergy ); break; case IDC_HDN: HSoffset -= 0.1; if( HSoffset < 20.0 ) HSoffset = 20.0; sprintf( strHenergy, "%6.2f", HSoffset ); SetDlgItemText( hwndDlg, IDC_HS, strHenergy ); break; case IDC_CUP: CSoffset += 0.1; if( CSoffset > 120.0 ) CSoffset = 120.0; // {0..7} + sprintf( strCenergy, "%6.2f", CSoffset ); SetDlgItemText( hwndDlg, IDC_CS, strCenergy ); break; case IDC_CDN: CSoffset -= 0.1; if( CSoffset < 3.0 ) CSoffset = 3.0; sprintf( strCenergy, "%6.2f", CSoffset ); SetDlgItemText( hwndDlg, IDC_CS, strCenergy ); break; case IDOK: GetDlgItemText( hwndDlg, IDC_PS, strPenergy, 20 ); sprintf(strPenergy, "%6.2f", PSoffset); GetDlgItemText( hwndDlg, IDC_HS, strHenergy, 20 ); sprintf(strHenergy, "%6.2f", HSoffset); GetDlgItemText( hwndDlg, IDC_CS, strCenergy, 20 ); sprintf( strCenergy, "%6.2f", CSoffset ); EndDialog( hwndDlg, 0 ); break; } switch (LOWORD(wParam)) { case IDCANCEL: { EndDialog(hwndDlg, (INT_PTR) LOWORD(wParam)); return (INT_PTR) TRUE; } } break; } case WM_INITDIALOG: sprintf( strPenergy, "%6.2f", PSoffset ); SetDlgItemText( hwndDlg, IDC_PS, strPenergy ); sprintf( strHenergy, "%6.2f", HSoffset); SetDlgItemText( hwndDlg, IDC_HS, strHenergy ); sprintf( strCenergy, "%6.2f", CSoffset); SetDlgItemText( hwndDlg, IDC_CS, strCenergy ); return (INT_PTR) TRUE; } return (INT_PTR) FALSE; } // Psenescence = (int) (((PL+i)->EN & (7 << 22)) >> 22) + PNoffset; // 3 - 10 // Hsenescence = (int) (((HL+i)->EN & (31 << 22)) >> 22) + HNoffset; // 19 - 50 // Csenescence = (int) (((CL+i)->EN & (31 << 22)) >> 22) + CNoffset; // 39 - 70 INT_PTR CALLBACK SenescenceDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { // 's' triggers me char strPage[20]; char strHage[20]; char strCage[20]; switch (uMsg) { case WM_COMMAND: { switch(wParam) { case IDC_PUP: PNoffset += 1; if( PNoffset > 7 ) PNoffset = 7; // {0..7} + sprintf( strPage, "%d", PNoffset ); SetDlgItemText( hwndDlg, IDC_PM, strPage ); break; case IDC_PDN: PNoffset -= 1; if( PNoffset < 5 ) PNoffset = 5; sprintf( strPage, "%d", PNoffset ); SetDlgItemText( hwndDlg, IDC_PM, strPage ); break; case IDC_HUP: HNoffset += 1; if( HNoffset > 30 ) HNoffset = 30; // {0..31} + sprintf( strHage, "%d", HNoffset ); SetDlgItemText( hwndDlg, IDC_HM, strHage ); break; case IDC_HDN: HNoffset -= 1; if( HNoffset < 1 ) HNoffset = 1; sprintf( strHage, "%d", HNoffset ); SetDlgItemText( hwndDlg, IDC_HM, strHage ); break; case IDC_CUP: CNoffset += 1; if( CNoffset > 40 ) CNoffset = 40; // {0..31} + sprintf( strCage, "%d", CNoffset ); SetDlgItemText( hwndDlg, IDC_CM, strCage ); break; case IDC_CDN: CNoffset -= 1; if( CNoffset < 1 ) CNoffset = 1; sprintf( strCage, "%d", CNoffset ); SetDlgItemText( hwndDlg, IDC_CM, strCage ); break; case IDOK: GetDlgItemText( hwndDlg, IDC_PM, strPage, 20 ); PNoffset = atoi( strPage ); GetDlgItemText( hwndDlg, IDC_HM, strHage, 20 ); HNoffset = atoi( strHage ); GetDlgItemText( hwndDlg, IDC_CM, strCage, 20 ); CNoffset = atoi( strCage ); EndDialog( hwndDlg, 0 ); break; } switch (LOWORD(wParam)) { case IDCANCEL: { EndDialog( hwndDlg, (INT_PTR) LOWORD(wParam)); return (INT_PTR) TRUE; } } break; } case WM_INITDIALOG: sprintf( strPage, "%d", PNoffset ); SetDlgItemText( hwndDlg, IDC_PM, strPage ); sprintf( strHage, "%d", HNoffset ); SetDlgItemText( hwndDlg, IDC_HM, strHage ); sprintf( strCage, "%d", CNoffset ); SetDlgItemText( hwndDlg, IDC_CM, strCage ); return (INT_PTR) TRUE; } return (INT_PTR) FALSE; } // maturity = (int) (PL+i)->EN & 7 + PAoffset; Hard wired at 2. // EN::G2 3 - 10 // maturity = (int) (HL+i)->EN & 3 + HAoffset; // EN::G2 1 - 4 // maturity = (int) (CL+i)->EN & 7 + CAoffset; // EN::G2 3 - 10 // int PAoffset = 1, HAoffset = 1, CAoffset = 3; INT_PTR CALLBACK MaturityDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { // 'a' triggers me char strPage[20]; char strHage[20]; char strCage[20]; switch (uMsg) { case WM_COMMAND: { switch(wParam) { case IDC_PUP: PAoffset += 1; if( PAoffset > 7 ) PAoffset = 7; // {0..7} + sprintf( strPage, "%d", PAoffset ); SetDlgItemText( hwndDlg, IDC_PA, strPage ); break; case IDC_PDN: PAoffset -= 1; if( PAoffset < 1 ) PAoffset = 1; sprintf( strPage, "%d", PAoffset ); SetDlgItemText( hwndDlg, IDC_PA, strPage ); break; case IDC_HUP: HAoffset += 1; if( HAoffset > 30 ) HAoffset = 30; // {0..31} + sprintf( strHage, "%d", HAoffset ); SetDlgItemText( hwndDlg, IDC_HA, strHage ); break; case IDC_HDN: HAoffset -= 1; if( HAoffset < 1 ) HAoffset = 1; sprintf( strHage, "%d", HAoffset ); SetDlgItemText( hwndDlg, IDC_HA, strHage ); break; case IDC_CUP: CAoffset += 1; if( CAoffset > 40 ) CAoffset = 40; // {0..31} + sprintf( strCage, "%d", CAoffset ); SetDlgItemText( hwndDlg, IDC_CA, strCage ); break; case IDC_CDN: CAoffset -= 1; if( CAoffset < 1 ) CAoffset = 1; sprintf( strCage, "%d", CAoffset ); SetDlgItemText( hwndDlg, IDC_CA, strCage ); break; case IDOK: GetDlgItemText( hwndDlg, IDC_PA, strPage, 20 ); PAoffset = atoi( strPage ); GetDlgItemText( hwndDlg, IDC_HA, strHage, 20 ); HAoffset = atoi( strHage ); GetDlgItemText( hwndDlg, IDC_CA, strCage, 20 ); CAoffset = atoi( strCage ); EndDialog( hwndDlg, 0 ); break; } switch (LOWORD(wParam)) { case IDCANCEL: { EndDialog( hwndDlg, (INT_PTR) LOWORD(wParam)); return (INT_PTR) TRUE; } } break; } case WM_INITDIALOG: sprintf( strPage, "%d", PAoffset ); SetDlgItemText( hwndDlg, IDC_PA, strPage ); sprintf( strHage, "%d", HAoffset ); SetDlgItemText( hwndDlg, IDC_HA, strHage ); sprintf( strCage, "%d", CAoffset ); SetDlgItemText( hwndDlg, IDC_CA, strCage ); return (INT_PTR) TRUE; } return (INT_PTR) FALSE; } INT_PTR CALLBACK HelpDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch( uMsg ) { case WM_COMMAND: { switch ( LOWORD(wParam) ) { case IDOK: { EndDialog( hwndDlg, (INT_PTR) LOWORD(wParam) ); return (INT_PTR) TRUE; } } break; } case WM_INITDIALOG: return (INT_PTR) TRUE; } return (INT_PTR) FALSE; } /////////////////////////////////////////////////////////////////////////////////// //////// Spot Sample Reports //////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// void seeEN( void ) // seePEnergy() seeHEnergy() & seeCEnergy() ?? { pMin = 5000, pMax = -5000; page = 0, hage = 0, cage = 0; sumEn=0, sumAbs=0, sumEnergy=0, sumSat=0, sumPsen=0, sumHsen=0, sumCsen=0; for(int i=0; iEN & 3) + PMoffset; // EN::G4 7.5 - 10.5 absorb = (float) ((((SP+i)->EN & (7 << 3)) >> 3) + 1.0) / 15.0; // EN::G3 0.71 - 0.53 satiety = (float) (((SP+i)->EN & (63 << 6)) >> 6) + PSoffset; // EN::G2 19.1 - 82.1 // maturity = (int) (((SP+i)->EN & (3 << 12)) >> 12) + PAoffset; // EN::G2 1 - 4 Psenescence = (int) (((SP+i)->EN & (15 << 22)) >> 22) + 5; // EN::G0 5 - 12 page += (SP+i)->age; if( (SP+i)->age < pMin ) pMin = (SP+i)->age; if( (SP+i)->age > pMax ) pMax = (SP+i)->age; sumEn += metab; // Metabolic energy requirement sumAbs += absorb; // sumSat += satiety; sumPsen += Psenescence; sumEnergy += (SP+i)->energy; } } void seeHDR( void ) { // Herbivore DR for(int i=0; iDR & 7); // SE DR::G8 dirProb[7] = (float) (((SH+i)->DR & (7 << 3)) >> 3); // S dirProb[6] = (float) (((SH+i)->DR & (7 << 6)) >> 6); // SW dirProb[5] = (float) (((SH+i)->DR & (7 << 9)) >> 9); // W dirProb[4] = (float) (((SH+i)->DR & (7 << 12)) >> 12); // NW dirProb[3] = (float) (((SH+i)->DR & (7 << 15)) >> 15); // N dirProb[2] = (float) (((SH+i)->DR & (7 << 18)) >> 18); // NE dirProb[1] = (float) (((SH+i)->DR & (7 << 21)) >> 21); // E DR::G1 // DR::G0 is speed for(int j=1; j<9; j++) tt += dirProb[j]; // Sum probabilities for(int j=1; j<9; j++) if( tt > 0.0 ) // -nan guard dirProb[j] /= tt; // Normalize direction probabilities else dirProb[j] = 0.0; } Hspeed = 0, Cspeed = 0; // Clear speed buffers for(int i=0; iDR & (7 << 28)) >> 28) + Hmin; } for(int i=0; iDR & (7 << 28)) >> 28) + Cmin; } } void seeCDR( void ) { // Carnivore DR for(int i=0; iDR & 7); // SE DR::G8 dirProb[7] = (float) (((SC+i)->DR & (7 << 3)) >> 3); // S dirProb[6] = (float) (((SC+i)->DR & (7 << 6)) >> 6); // SW dirProb[5] = (float) (((SC+i)->DR & (7 << 9)) >> 9); // W dirProb[4] = (float) (((SC+i)->DR & (7 << 12)) >> 12); // NW dirProb[3] = (float) (((SC+i)->DR & (7 << 15)) >> 15); // N dirProb[2] = (float) (((SC+i)->DR & (7 << 18)) >> 18); // NE dirProb[1] = (float) (((SC+i)->DR & (7 << 21)) >> 21); // E DR::G1 // DR::G0 is speed for(int j=1; j<9; j++) tt += dirProb[j]; // Sum probabilities for(int j=1; j<9; j++) if( tt > 0.0 ) dirProb[j] /= tt; // Normalize direction probabilities else dirProb[j] = 0.0; } } void countGM( void ) { for(int i=0; i<10; i++) hist[i] = 0; for(int i=0; iGM != 61680 ) hist[0]++; else hist[1]++; for(int i=0; iGM != 61680 ) hist[2]++; else hist[3]++; for(int i=0; iGM != 61680 ) hist[4]++; else hist[5]++; // GM = 61680 } void compareGenes( void ) { pmin = hmin = cmin = 1e5; pmax = hmax = cmax = -1e5; psum = 0, hsum = 0, ssum = 0, camSum = 0, seeSum = 0, eatSum = 0; for(int i=0; iPL & (63 << 12)) >> 12) + 1.0) / 65.0; if( strength < 0.9846 ) psum++; // PL::G1 spine presence float spine = (float) ((((SP+i)->PL & (63 << 18)) >> 18) + 1.0) / 65.0; if( spine < 0.9846 ) ssum++; if( (SP+i)->energy < pmin ) pmin = (SP+i)->energy; if( (SP+i)->energy > pmax ) pmax = (SP+i)->energy; } for(int i=0; iHB & (63 << 12)) >> 12) + 1.0) / 65.0; // HB::G0 if( resist < 0.9846 ) hsum++; if( (SH+i)->energy < hmin ) hmin = (SH+i)->energy; if( (SH+i)->energy > hmax ) hmax = (SH+i)->energy; // HB::G1 ability to eat spines float eat = (float) ((((SH+i)->HB & (63 << 6)) >> 6) + 1.0) / 65.0; // HB::G1 if( eat < 0.9846 ) eatSum++; // HB::G2 camouflage effectiveness float camo = (float) (((SH+i)->HB & 63) + 1.0) / 65.0; // HB::G2 if( camo < 0.9846 ) camSum++; } for(int i=0; iSN & 63) + 1.0) / 65.0; // {0.0156 .. 0.9846} if( see < 0.9846 ) seeSum++; if( (SC+i)->energy < cmin ) cmin = (SC+i)->energy; if( (SC+i)->energy > cmax ) cmax = (SC+i)->energy; } } void Pabsorbs( void ) { float absorb; // EN::G4 absorption coefficient sumPAbs = 0.0; for(int i=0; i<10; i++) hist[i] = 0; for(int j=0; jEN & (7 << 3)) >> 3) + 1.0) / 15.0; sumPAbs += absorb; for(int i=0; i<10; i++) // Scan histogram bins { if( (absorb >= i*0.1) && (absorb < (i+1)*0.1) ) hist[i]++; } } } void Habsorbs( void ) { float absorb; // EN::G4 absorption coefficient sumHAbs = 0.0; for(int i=0; i<10; i++) hist[i] = 0; for(int j=0; jEN & (7 << 7)) >> 7) + 1.0) / 12.0; sumHAbs += absorb; for(int i=0; i<10; i++) // Scan histogram bins { if( (absorb >= i*0.1) && (absorb < (i+1)*0.1) ) hist[i]++; } } } void Cabsorbs( void ) { float absorb; // EN::G4 absorption coefficient sumCAbs = 0.0; for(int i=0; i<10; i++) hist[i] = 0; for(int j=0; jEN & (7 << 7)) >> 7) + 1.0) / 9.0; sumCAbs += absorb; for(int i=0; i<10; i++) // Scan histogram bins { if( (absorb >= i*0.1) && (absorb < (i+1)*0.1) ) hist[i]++; } } } void camoWar( void ) { float camo; // HB::G2 Herbivore camouflage for(int i=0; i<10; i++) hist[i] = 0; for(int j=0; jHB & 63) + 1.0) / 65.0; for(int i=0; i<10; i++) // Scan histogram bins { if( (camo >= i*0.1) && (camo < (i+1)*0.1) ) hist[i]++; } } } void seeWar( void) { float see; // SN::G5 sight ability for(int i=0; i<10; i++) // Clear histogram bins hist[i] = 0; for(int j=0; jSN & 63) + 1.0) / 65.0; // Extract gene for(int i=0; i<10; i++) // Fill histogram bins { if( (see >= i*0.1) && (see < (i+1)*0.1) ) hist[i]++; } } } void strengthWar( void ) { float strength; // PL::G2 poison strength for(int i=0; i<10; i++) hist[i] = 0; for(int j=0; jPL & (63 << 12)) >> 12) + 1.0) / 65.0; for(int i=0; i<10; i++) // Scan histogram bins { if( (strength >= i*0.1) && (strength < (i+1)*0.1) ) hist[i]++; } } } void resistWar( void ) { float resist; // HB::G0 Resist poisons for(int i=0; i<10; i++) hist[i] = 0; for(int j=0; jHB & (63 << 12)) >> 12) + 1.0) / 65.0; for(int i=0; i<10; i++) // Scan histogram bins { if( (resist >= i*0.1) && (resist < (i+1)*0.1) ) hist[i]++; } } } void spineWar( void ) { float spine; // PL::G1 spine probability for(int i=0; i<10; i++) hist[i] = 0; for(int j=0; jPL & (63 << 18)) >> 18) + 1.0) / 65.0; for(int i=0; i<10; i++) // Scan histogram bins { if( (spine >= i*0.1) && (spine < (i+1)*0.1) ) hist[i]++; } } } void eatWar( void ) { float eat; // HB::G1 Eat spines for(int i=0; i<10; i++) hist[i] = 0; for(int j=0; jHB & (63 << 6)) >> 6) + 1.0) / 65.0; for(int i=0; i<10; i++) // Scan histogram bins { if( (eat >= i*0.1) && (eat < (i+1)*0.1) ) hist[i]++; } } } float max; // Maximum absorption value for each species //int sums; // Collect count of histogram bins for a sanity check :) INT_PTR CALLBACK RadioDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch( uMsg ) { case WM_INITDIALOG: num = sprintf( text, " On cycle #%d you sampled:", kk ); SetDlgItemText( hwndDlg, ID_TEXT1, text ); num = sprintf( text, "%d plants, %d herbivores, and %d carnivores", Psamp, Hsamp, Csamp ); SetDlgItemText( hwndDlg, ID_TEXT2, text ); SendMessage( hwndDlg, WM_COMMAND, ID_ONE, 0L); // Call seeEN() function CheckRadioButton( hwndDlg, ID_ONE, ID_SIX, ID_ONE ); // first, last, check return (INT_PTR) TRUE; case WM_COMMAND: switch( wParam ) { case ID_ONE: // printf("BN energy has been clicked.\n"); seeEN(); for(int i=ID_TEXT4; iP ) // Is there a plant here? { *(SP + Psamp) = *(F->P); // Store plant data Psamp++; // Increment the plant counter } if( F->H ) // Is there a herbivore here? { *(SH + Hsamp) = *(F->H); Hsamp++; } if( F->C ) // Is there a carnivore here? { *(SC + Csamp) = *(F->C); Csamp++; } } if( store ) { FILE *fp = fopen( "spot.dat", "w" ); // Store spot sample fprintf( fp, "%d\n", kk ); // Store current cycle fprintf( fp, "%d %d %d\n", Psamp, Hsamp, Csamp ); for(int i=0; iEN, (SP+i)->PL, (SP+i)->GM, (SP+i)->energy, (SP+i)->age ); for(int i=0; iEN, (SH+i)->SN, (SH+i)->HB, (SH+i)->DR, (SH+i)->GM, (SH+i)->energy, (SH+i)->age ); for(int i=0; iEN, (SC+i)->SN, (SC+i)->CN, (SC+i)->DR, (SC+i)->GM, (SC+i)->energy, (SC+i)->age ); fclose( fp ); } DialogBox( hInst, MAKEINTRESOURCE( IDD_RADIO_DIALOG ), hwnd, &RadioDialogProc ); } //=========================//=========================//=========================// //=========================//=========================//=========================// //=========================//=========================//=========================// void displayBits( chromosome seq ) { int k=0; // Character counter int j=0; // Space counter chromosome mask = 1 << 31; // Shift mask all the way left for(int i=0; i<32; i++) { if( seq & mask ) // Compare mask bit to present bit text[ k++ ] = '1'; else text[ k++ ] = '0'; if( j++ == 3 ) // Separate into bit quartets { text[ k++ ] = ' '; // Green bar print out j=0; } seq <<= 1; // Shift sequence to the left } } void seePL( void ) { float strength, spine; printf("How defensive are my plants?\n"); printf("spine, strength\n"); for(int i=100; i<200; i++) // Notice endpoints!!!! TODO Psamp; { displayBits( (SP+i)->PL ); printf("%s\n", text ); strength = (float) ((((SP+i)->PL & (63 << 12)) >> 12) + 1.0) / 65.0; // PL::G2 poison strength spine = (float) ((((SP+i)->PL & (63 << 18)) >> 18) + 1.0) / 65.0; // PL::G1 spine probability printf("%8.4f %8.4f\n", spine, strength ); } } void seeSN( void ) { float see; printf("How well can your carnivore see?\n"); for(int i=0; i<20; i++) { displayBits( (SC+i)->SN ); // {0.0156 .. 0.9846} printf("%s\n", text ); see = (float) (((SC+i)->SN & 63) + 1.0) / 65.0; // SN::G4 sight ability printf("%6.2f\n", see ); } } void seeCN( void ) { int speed; printf("How fast are my cheetahs?\n"); for(int i=0; i<20; i++) { // displayBits( (SC+i)->CN ); // printf("%s\n", text ); displayBits( (SC+i)->DR ); printf("%s\n", text ); // What is Carnivore minimum speed speed = (int) (((SC+i)->DR & (15 << 24)) >> 24) + 12; // DR::G0 4b printf("%d\n", speed ); } } void seeHB( void ) { float camo, eat, resist; int speed; int sum = 0, poisonSum = 0, spineSum = 0; printf("Herbivore genes exposed!\n"); printf("speed, resist, eat, camo\n"); for(int i=0; i<20; i++) { displayBits( (SH+i)->HB ); // {0.0156 .. 0.9846} printf("%s\n", text ); camo = (float) (((SH+i)->HB & 63) + 1.0) / 65.0; // HB::G2 camo effect eat = (float) ((((SH+i)->HB & (63 << 6)) >> 6) + 1.0) / 65.0; // HB::G1 eat spines resist = (float) ((((SH+i)->HB & (63 << 12)) >> 12) + 1.0) / 65.0; // HB::G0 resist poison speed = (int) (((SH+i)->DR & (15 << 24)) >> 24) + 12; // DR::G0 moved 1-1-25 4b // speed = (int) (((HL+i)->HB & (7 << 28)) >> 28) + min; // in moveH() min = 1 // speed = (int) (((CL+i)->CN & (7 << 28)) >> 28) + min; // in moveC() min = 3 // speed = (int) (((CL+i)->CN & (15 << 27)) >> 27) + 12; // in eat() CN::G1 printf("%d %8.4f %8.4f %8.4f\n", speed, resist, eat, camo ); } printf("\n"); for(int i=0; iHB & (63 << 6)) >> 6) + 1.0) / 65.0; // HB::G1 resist = (float) ((((SH+i)->HB & (63 << 12)) >> 12) + 1.0) / 65.0; // HB::G0 if( eat > 0.98 ) spineSum++; // {0.0156 .. 0.9846} if( resist > 0.98 ) poisonSum++; } printf("%8.4f of herbivores ability to eat spines is above 0.98\n", (float) spineSum/sum ); printf("%8.4f of herbivores ability to eat poison is above 0.98\n", (float) poisonSum/sum ); printf("%d %d\n", spineSum, poisonSum ); } ///////////////////////////////////////////////////////////////////////////////////////////////// /////////////// Notes ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////// void CALLBACK TimerProc( HWND hwnd, UINT iMsg, UINT iTimerID, DWORD dwTime ) { } int displayHelp( void ) // Rudimentary help screen. { int msgboxID = MessageBox( hwnd, (LPCSTR) "Type 'h' for this screen\nType 'd' to toggle data display\nType 'n' to log the nutrient layer\nType 'a' for age of maturity\nType 'm' for metabolism choices\nType 'r' for reproduction energy\nType 's' to control sensescence\nType 't' to control satiety levels\nType 'q' to quit\n\nJanuary 16, 2025\n(c) Bacona Design\nVersion 1.07.5", (LPCSTR) "ecoDraw Keyboard Commands", MB_ICONINFORMATION | MB_OK ); // Change in resource.rc I don't use this message now. switch (msgboxID) { case IDOK: break; } return msgboxID; } #ifdef NOTES float strength = (float) ((((PS+i)->PL & (63 << 12)) >> 12) + 1.0) / 65.0; // PL::G2 float spine = (float) ((((PS+i)->PL & (63 << 18)) >> 18) + 1.0) / 65.0; // PL::G1 float camo = (float) (((HS+i)->HB & 63) + 1.0) / 65.0; // HB::G2 float eat = (float) ((((HS+i)->HB & (63 << 6)) >> 6) + 1.0) / 65.0; // HB::G1 float resist = (float) ((((HS+i)->HB & (63 << 12)) >> 12) + 1.0) / 65.0; // HB::G0 #endif #ifdef NOTES Currently Tweakable parameters int Ppop = 500000, Hpop = 230000, Cpop = 50000; // float PRenergy = 12.5, HRenergy = 65.0, CRenergy = 35.5; // Reproduction energy level hard wire int PNoffset = 3, HNoffset = 19, CNoffset = 39; // Senescence - EN::G1 + offset float PSoffset = 19.1, HSoffset = 56.1, CSoffset = 8.0; // Satiety - EN::G3 + offset float PMoffset = 7.5, HMoffset = 4.2, CMoffset = 5.3; // Metabolism - EN::G5 + offset 5.3 - 12.3 Tweakable parameters: 36 right now int Ppop = 3900000, Hpop = 900000, Cpop = 80000; in main() Ppop = 500000; Hpop = 230000; Cpop = 50000; in useSamples *** initEcosystem() E->nutrient = 250 *** initPlants() PL->energy = 80 initHerbivores() HL->energy = 120 initCarnivores() CL->energy = 300 metabolize() PL->energy = EN::G4 + 7.5 *** 7.5 - 14.5 HL->energy = EN::G4 + 4.2 || *** 4.2 - 11.2 CL->energy = EN::G4 + 5.3 \/ *** 5.3 - 12.3 replenish() E(i,j)->nutrient += energy / (SZ*SZ) + 0.7 *** eat() PL satiety = PL->EN::G2 + 19.1 *** 19.1 - 82.1 PL absorb = (PL->EN::G3 + 1.0) / 15.0 0.071 - 0.533 PL spine = PL->PL::G1 / 94.0 0.0 - 0.67 float spine = (float) ((((PS+i)->PL & (63 << 18)) >> 18) + 1.0) / 65.0; // PL::G1 PL strength = PL->PL::G2 / 94.0 0.0 - 0.67 float strength = (float) ((((PS+i)->PL & (63 << 12)) >> 12) + 1.0) / 65.0; // PL::G2 HL satiety = HL->EN::G2 + 56.1 *** 56.1 - 119.1 HL absorb = (HL->EN::G3 + 1.0) / 10.0 0.1 - 0.8 HL speed = HL->HB::G0 + 12 12 - 27 Moved to DR 1-1-25 HL resist = HL->HB::G2 / 31.0 0.0 - 1.0 float resist = (float) ((((HS+i)->HB & (63 << 12)) >> 12) + 1.0) / 65.0; // HB::G0 // camo = (float) (((HS+i)->HB & (31 << 10)) >> 10) / 31.0; // camo = (float) ((H->HB & (31 << 10)) >> 10) / 50.0; // Herbivore camouflage in eat() float camo = (float) (((HS+i)->HB & 63) + 1.0) / 65.0; // HB::G2 ch > 29 plant search count limit CL satiety = CL->EN::G2 + 8.0 *** 8.0 - 15.0 CL absorb = (CL->EN::G3 + 1.0) / 8.0 0.125 - 1.0 CL speed = CL->CN::G0 + 12 12 - 27 Moved to DR 1-1-25 CL see = CL->SN::G4 / 255.0 0.0 - 1.0 ch > 57 herbivore search count limit This a search limit and an eating limit. It eats what it finds 57 times. reproduce() PL->age > 2 hard wired HL maturity = HL->EN::G1 + 1 1 - 4 CL maturity = CL->EN::G1 + 3 3 - 10 PL->energy > 12.5 hard wired *** HL->energy > 65.0 hard wired *** CL->energy > 35.5 hard wired *** die() PL senescence = EN::G0 + 3 *** 3 - 10 HL senescence = EN::G0 + 19 *** 19 - 50 CL senescence = EN::G0 + 39 *** 39 - 70 #endif #ifdef NOTES Display a chromosome at a time for the chosen organism. Genes should show as decimal numbers then the offset then the total of the two Or if they are factors, do the arithmetic and casting to get the proper floating point values. This list needs to be expanded and updated to reflect what is written in the code. Each plant, herbivore, and carnivore do NOT use the same mask to create the expressed values. // float PMoffset = 7.5, HMoffset = 4.2, CMoffset = 5.3; // EN::G4 7.5 - 14.5 (PL+i)->energy -= (float) ((PL+i)->EN & 7) + PMoffset; // EN::G4 7.5 - 14.5 (HL+i)->energy -= (float) ((HL+i)->EN & 7) + HMoffset; // EN::G4 4.2 - 11.2 (CL+i)->energy -= (float) ((CL+i)->EN & 7) + CMoffset; // EN::G4 5.3 - 12.3 absorb = (float) ((((PL+i)->EN & (7 << 3)) >> 3) + 1.0) / 15.0; // EN::G3 0.71 - 0.53 absorb = (float) ((((HL+i)->EN & (7 << 3)) >> 3) + 1.0) / 10.0; // EN::G3 0.1 - 0.8 absorb = (float) ((((CL+i)->EN & (7 << 3)) >> 3) + 1.0) / 8.0; // EN::G3 0.125 - 1.0 // float PSoffset = 19.1, HSoffset = 56.1, CSoffset = 8.0; satiety = (float) (((PL+i)->EN & (63 << 6)) >> 6) + PSoffset; // EN::G2 19.1 - 82.1 satiety = (float) (((HL+i)->EN & (63 << 6)) >> 6) + HSoffset; // EN::G2 56.1 - 119.1 satiety = (float) (((CL+i)->EN & (7 << 6)) >> 6) + CSoffset; // EN::G2 8.0 - 15.0 // int PAoffset = 1, HAoffset = 1, CAoffset = 3; maturity = (int) (((PL+i)->EN & (3 << 12)) >> 12) + 3; Hard wired at 2 right now. // EN::G2 1 - 4 maturity = (int) (((HL+i)->EN & (3 << 12)) >> 12) + 1; // EN::G1 1 - 4 maturity = (int) (((CL+i)->EN & (7 << 12)) >> 12) + 3; // EN::G1 3 - 10 // int PNoffset = 3, HNoffset = 19, CNoffset = 39; Psenescence = (int) (((PL+i)->EN & (7 << 15)) >> 15) + PNoffset; // EN::G0 3 - 10 Hsenescence = (int) (((HL+i)->EN & (31 << 15)) >> 15) + HNoffset; // EN::G0 19 - 50 Csenescence = (int) (((CL+i)->EN & (31 << 15)) >> 15) + CNoffset; // EN::G0 39 - 70 These are GOOD. Now check all others for correct shift amounts // TODO (PL+i)->PL for plant genes { pollination%, poison%, poison strength, spine%, spine length } 6b:6b:6b:6b:2b to 6b:6b:6b G0, G1, G2 pollen = (float) (((PS+i)->PL & 63) + 1.0) / 65.0; // PL::G0 pollination % // PL::G1 spine probability spine = (float) ((((PS+i)->PL & (63 << 6)) >> 6) + 1.0) / 65.0; // PL::G1 // PL::G2 poison strength strength = (float) ((((PS+i)->PL & (63 << 12)) >> 12) + 1.0) / 65.0; // PL::G2 (HL+i)->HB for herbivore genes { run%, hide%, camo%, eat spine%, eat poison% } 5b:5b:5b:5b:5b:5b:2b camo = (float) ((H->HB & (31 << 20)) >> 20) / 50.0; // HB::G4 camouflage effectiveness //eat = (float) (((HL+i)->HB & (31 << 15)) >> 15) / 31.0; // HB::G3 ability to eat spines eat = (float) ((((HS+i)->HB & (63 << 6)) >> 6) + 1.0) / 65.0; // HB::G1 //resist = (float) (((HL+i)->HB & (31 << 10)) >> 10) / 31.0; // HB::G2 resist poison resist = (float) ((((HS+i)->HB & (63 << 12)) >> 12) + 1.0) / 65.0;// HB::G0 //speed = (int) (((HL+i)->HB & (15 << 27)) >> 27) + 12; // HB::G0 12 - 27 speed = (int) (((HL+i)->DR & (7 << 24)) >> 24) + 12; DR::G0 moved 1-1-25 4b New Version of Herbivore gene map float strength = (float) ((((PS+i)->PL & (63 << 12)) >> 12) + 1.0) / 65.0; // PL::G2 float spine = (float) ((((PS+i)->PL & (63 << 6)) >> 6) + 1.0) / 65.0; // PL::G1 float camo = (float) (((HS+i)->HB & 63) + 1.0) / 65.0; // HB::G2 float eat = (float) ((((HS+i)->HB & (63 << 6)) >> 6) + 1.0) / 65.0; // HB::G1 float resist = (float) ((((HS+i)->HB & (63 << 12)) >> 12) + 1.0) / 65.0; // HB::G0 5b:5b:5b:5b:5b:5b:2b //run = (float) ((HL+i)->HB & 31) / 31.0; HB::G6 run probability //hide = (float) (((HL+i)->HB & (31 << 5)) >> 5) / 31.0; HB::G5 hide probability //camo = (float) (((HL+i)->HB & (31 << 10)) >> 10) / 31.0; HB::G4 camouflage effectiveness * float camo = (float) (((HS+i)->HB & 63) + 1.0) / 65.0; // HB::G2 float eat = (float) ((((HS+i)->HB & (63 << 6)) >> 6) + 1.0) / 65.0; // HB::G1 //eat = (float) (((HL+i)->HB & (31 << 15)) >> 15) / 31.0; HB::G3 ability to eat spines * //resist = (float) (((HL+i)->HB & (31 << 20)) >> 20)/31.0; HB::G2 resist poison * resist = (float) ((((HS+i)->HB & (63 << 12)) >> 12) + 1.0) / 65.0; // HB::G0 //escape = (int) ((HL+i)->HB & (31 << 25)) >> 25; HB::G1 escape range //speed = (int) ((HL+i)->HB & (3 << 30)) >> 30; HB::G0 speed gene 2 b?? * speed = (int) (((HL+i)->DR & (7 << 24)) >> 24) + 12; DR::G0 moved 1-1-25 4b 1/17 = 0.058 16/17 = 0.941 1/33 = 0.0303 32/33 = 0.970 camo = (HB + 1.0) / 33.0 see = (SN + 1.0) / 256.0?? or 33.0? 1/65 = 0.0154 64/65 = 0.985 see = (CN::SN + 1.0) / 65.0 (CL+i)->CN for carnivore genes { attack%, attack range, sleep%, hide%, camo%, pursuit time } 6b:2b:6b:6b:6b:3b:2b This needs to be rethought. //speed = (int) (((CL+i)->CN & (7 << 27)) >> 27) + 12; // CN::G0 12 - 27 speed = (int) (((CL+i)->DR & (7 << 24)) >> 24) + 12; // DR::G0 Moved 1-1-25 (HL+i)->SN for sensor genes { touch range, hearing range, seeing range, smelling range } 8b:8b:8b:4b:4b see = (float) ((CL+i)->SN & 255) / 255.0; // SN::G5 sight ability (CL+i)->DR for direction genes { E, W, N, S, NE, SE, NW, SW } 3b:3b:3b:3b:3b:3b:3b:3b = 24 bits, we have room for a speed gene 31 - 24 = 7 bits? how about we use four of them for speed Speed for both herbivores and carnivores in the DR chromosome 3b:3b:3b:3b:3b:3b:3b:3b + 4b = 28 bits used on DR dirProb[8] = (float) (DR & 7); // SE DR::G7 dirProb[7] = (float) ((DR & (7 << 3)) >> 3); // S dirProb[6] = (float) ((DR & (7 << 6)) >> 6); // SW dirProb[5] = (float) ((DR & (7 << 9)) >> 9); // W DR::G4 dirProb[4] = (float) ((DR & (7 << 12)) >> 12); // NW dirProb[3] = (float) ((DR & (7 << 15)) >> 15); // N DR::G2 dirProb[2] = (float) ((DR & (7 << 18)) >> 18); // NE dirProb[1] = (float) ((DR & (7 << 21)) >> 21); // E DR::G0 #endif #ifdef NOTES BOOL StretchBlt( [in] HDC hdcDest, hdc [in] int xDest, upper left [in] int yDest, [in] int wDest, width [in] int hDest, height [in] HDC hdcSrc, hdcdata [in] int xSrc, upper left [in] int ySrc, [in] int wSrc, width [in] int hSrc, height [in] DWORD rop ); This may come in handy. A square window say 100 x 100 filled with the whole bitmap from 0,0 to 5000,5000 Let the StretchBlt( algorithm do the work. Use it as a directory window on the main view. Hmm... needs thought. SetStretchBltMode( hdc, HALFTONE ); SetBrushOrgEx( hdc, 0, 0, NULL ); StretchBlt( hdc, 0, 0, WINX, WINY, bkhdc, 0, 0, SZ, SZ, SRCCOPY ); https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-scrollwindowex xPos = GET_X_LPARAM(lParam); yPos = GET_Y_LPARAM(lParam); #endif // 1/65 = 0.0154 64/65 = 0.985 see = (CN::SN + 1.0) / 65.0 #ifdef NOTES *** void storeData( void ); // Backup ecosystem to file *** void loadData( void ); // Restore ecosystem from file *** void storeSamples( void ); // Collect 1000 P,H,C samples void loadSamples( void ); // Read the samples into their own buffers void loadSampTwo( void ); // Read second sample into secondary buffers void useSamples( void ); // Build an ecosystem from those samples void loadSamples( void ) { FILE *fp; fp = fopen( "sample.dat", "r" ); for(int i=0; i<1000; i++) { fscanf(fp, "%u %u %u %f %d", &(PS+i)->EN, &(PS+i)->PL, &(PS+i)->GM, &(PS+i)->energy, &(PS+i)->age ); // (PS+i)->GM = (chromosome) 3855; // Maternal genetic marker // 3855 = 0000 1111 0000 1111 } for(int i=0; i<1000; i++) fscanf(fp, "%u %u %u %u %f %d", &(HS+i)->EN, &(HS+i)->SN, &(HS+i)->HB, &(HS+i)->DR, &(HS+i)->energy, &(HS+i)->age ); for(int i=0; i<1000; i++) fscanf(fp, "%u %u %u %u %f %d", &(CS+i)->EN, &(CS+i)->SN, &(CS+i)->CN, &(CS+i)->DR, &(CS+i)->energy, &(CS+i)->age ); fclose( fp ); } void loadSampTwo( void ) // Fill second sample buffers { FILE *fp; fp = fopen( "sample9.dat", "r" ); // Naming scheme ?? Hmm... for(int i=0; i<1000; i++) fscanf(fp, "%u %u %u %f %d", &(PB+i)->EN, &(PB+i)->PL, &(PB+i)->GM, &(PB+i)->energy, &(PB+i)->age ); for(int i=0; i<1000; i++) fscanf(fp, "%u %u %u %u %f %d", &(HB+i)->EN, &(HB+i)->SN, &(HB+i)->HB, &(HB+i)->DR, &(HB+i)->energy, &(HB+i)->age ); for(int i=0; i<1000; i++) fscanf(fp, "%u %u %u %u %f %d", &(CB+i)->EN, &(CB+i)->SN, &(CB+i)->CN, &(CB+i)->DR, &(CB+i)->energy, &(CB+i)->age ); fclose( fp ); } // Create a new ecosystem using sampled genetic data. void useSamples( void ) { int X, Y; initEcosystem(); // Fill the nutrient layer to initial levels // Ppop = 800000; Hpop = 200000; Cpop = 30000; // Numbers from current run time // Ppop = 500000; Hpop = 230000; Cpop = 50000; // Use global values instead for(int i=0; iP ); // When a plant is resident (PL+i)->X.x = X; // Find location (PL+i)->X.y = Y; (E +SZ*Y +X)->P = (PL+i); // Index it into E(i,j) (PL+i)->EN = (PS+R)->EN; // Copy chromosomes (PL+i)->PL = (PS+R)->PL; // (PL+i)->GM = 3855; (PL+i)->GM = (chromosome) 3855; // Maternal genetic marker TODO // From 'sample.dat' (PL+i)->energy = (PS+R)->energy; (PL+i)->age = (PS+R)->age; (PL+i)->alive = true; } for(int i=Ppop/2; iP ); // When a plant is resident (PL+i)->X.x = X; (PL+i)->X.y = Y; (E +SZ*Y +X)->P = (PL+i); (PL+i)->EN = (PB+R)->EN; (PL+i)->PL = (PB+R)->PL; // (PL+i)->GM = 3855; (PL+i)->GM = (chromosome) 0; //(PB+R)->GM; // Maternal genetic marker TODO // From 'sample9.dat' (PL+i)->energy = (PB+R)->energy; (PL+i)->age = (PB+R)->age; (PL+i)->alive = true; } for(int i=0; iH ); (HL+i)->X.x = X; (HL+i)->X.y = Y; (E +SZ*Y +X)->H = (HL+i); (HL+i)->EN = (HS+R)->EN; (HL+i)->SN = (HS+R)->SN; (HL+i)->HB = (HS+R)->HB; (HL+i)->DR = (HS+R)->DR; (HL+i)->energy = (HS+R)->energy; (HL+i)->age = (HS+R)->age; (HL+i)->alive = true; } for(int i=Hpop/2; iH ); (HL+i)->X.x = X; (HL+i)->X.y = Y; (E +SZ*Y +X)->H = (HL+i); (HL+i)->EN = (HB+R)->EN; (HL+i)->SN = (HB+R)->SN; (HL+i)->HB = (HB+R)->HB; (HL+i)->DR = (HB+R)->DR; (HL+i)->energy = (HB+R)->energy; (HL+i)->age = (HB+R)->age; (HL+i)->alive = true; } for(int i=0; iC ); (CL+i)->X.x = X; (CL+i)->X.y = Y; (E +SZ*Y +X)->C = (CL+i); (CL+i)->EN = (CS+R)->EN; (CL+i)->SN = (CS+R)->SN; (CL+i)->CN = (CS+R)->CN; (CL+i)->DR = (CS+R)->DR; (CL+i)->energy = (CS+R)->energy; (CL+i)->age = (CS+R)->age; (CL+i)->alive = true; } for(int i=Cpop/2; iC ); (CL+i)->X.x = X; (CL+i)->X.y = Y; (E +SZ*Y +X)->C = (CL+i); (CL+i)->EN = (CB+R)->EN; (CL+i)->SN = (CB+R)->SN; (CL+i)->CN = (CB+R)->CN; (CL+i)->DR = (CB+R)->DR; (CL+i)->energy = (CB+R)->energy; (CL+i)->age = (CB+R)->age; (CL+i)->alive = true; } } // Animal sensor array functions ////////// void herbScan( void ); // Local sensor scan for plants and carnivores void carnScan( void ); // Local sensor scan for herbivores int maxHerb( int CS[] ); // Find best feeding vector void herbScan( void ) { struct vt A, B, C; // Working vectors int maxRing = 3; // PFA number for(int i=0; iX; // Current location for(int k=1; k<9; k++) // Clear Psense[] and Csense { (HL+i)->Psense[ k ] = 0; // (HL+i)->Csense[ k ] = 0; } // Scan from inner ring to outer ring defined by sensor strength for(int ring=1; ringP) (HL+i)->Psense[ k ]++; // I found a plant // if( (E +C.y*SZ +C.x)->C) (HL+i)->Csense[ k ]++; // I found a carnivore } } } void carnScan( void ) // Sense herbivores in local area { // 8*8 = 64 possible cells int maxRing = 8; // PFA number potential gene 111 + 1 struct vt A, B, C; // Working vectors for(int i=0; iX; // You are here. for(int k=1; k<9; k++) // Clear Hsense[] (CL+i)->Hsense[ k ] = 0; for(int ring=1; ringH ) (CL+i)->Hsense[ k ]++; // I found a herbivore :) } } } int maxHerb( int CS[] ) // Find the best feasting { int Hmax; // Most dense direction int max = -100; // Guard for(int i=1; i<9; i++) if( CS[ i ] > max ) // Compare with current maximum { Hmax = i; // Seek supremum max = CS[ Hmax ]; // One shot } // Recalculate each step ?? return Hmax; } #endif // https://learn.microsoft.com/en-us/windows/win32/menurc/resource-definition-statements