优化代码(康威的生命游戏)

Optimizing code (Conway's Game of Life)

我刚刚制作了康威生命游戏的控制台版本。 它适用于 "small" 网格,例如 100 x 100 像素,但对于更大的网格则非常慢。你能帮我优化一下吗,这样它可以 运行 更快?

#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <string>
using namespace std;

const int m = 100;
const int n = 100; // size of the grid area
const int num_iter = 1000; // number of iterations to run

int main(){

    srand(time(0)); // the initial conditions of the grid should be random
    int n_count = 0; // variable for counting the neighbors of a particular point
    int iter = 0; // variable for counting the number of iterations done
    int grid[m][n] = {0};
    int newgrid[m][n] = {0}; // arrays filled with 1's and 0's representing a living or dead cells respectively

    HWND myconsole = GetConsoleWindow();
    HDC mydc = GetDC(myconsole);
    COLORREF WHITE = RGB(255,255,255);
    COLORREF BLACK = RGB(0,0,0);

    for(long i=0;i<m;i++){ // this for initializes the grid with random 1's
        for(long j=0;j<n;j++){
            if(rand()%2==0) grid[i][j] = 1;
        }
    }

    while(iter < num_iter){ // while loop controlling the number of iterations to be done
        for(long i=0;i<m;i++){
            for(long j=0;j<n;j++){ // nested for to count the number of neighbors of each cell
                if(i-1>=0) if(grid[i-1][j]==1) n_count++;
                if(j-1>=0) if(grid[i][j-1]==1) n_count++;
                if(i+1<=n) if(grid[i+1][j]==1) n_count++;
                if(j+1<=n) if(grid[i][j+1]==1) n_count++;
                if((i-1>=0)&&(j-1>=0)) if(grid[i-1][j-1]==1) n_count++;
                if((i-1>=0)&&(j+1<=n)) if(grid[i-1][j+1]==1) n_count++;
                if((i+1<=n)&&(j-1>=0)) if(grid[i+1][j-1]==1) n_count++;
                if((i+1<=n)&&(j+1<=n)) if(grid[i+1][j+1]==1) n_count++; // all possible 8 neighbors checked and counted by now
                if(grid[i][j]==1){ // if the cell is alive and...
                    if(n_count<2) newgrid[i][j] = 0; // ...it has less than 2 neighbors, then it dies
                    else if(n_count>3) newgrid[i][j] =0; // ... it has more than 3 neighbors, then it dies
                    else if((n_count==2)||(n_count==3)) newgrid[i][j] = 1; // ... it has 2 or 3 neighbors, then it lives
                }
                else if(n_count==3) newgrid[i][j] = 1; // if the cell is dead and it has 3 neighbors, then it lives
                n_count = 0;
            }
        }
        for(long i=0;i<m;i++){ // nested for to display a white pixel if the cell is alive, or black if it is dead
            for(long j=0;j<n;j++){
                grid[i][j] = newgrid[i][j];
                if(grid[i][j]==1) SetPixel(mydc,i+50,j+40,WHITE);
                else SetPixel(mydc,i+50,j+40,BLACK);
            }
        }
        Sleep(1);
        iter++;
    }

    ReleaseDC(myconsole, mydc);
    cin.ignore();
    return 0;
}

我认为优化 Conway 的生命游戏本身就是一门科学,我相信 NPE 提供的 link 对此进行了很好的介绍,但如果我可以提出建议,SetPixel 太浪费时间了。

所以,两个优化:

  1. 只对那些实际发生变化的像素执行 SetPixel。而不是这个:

            grid[i][j] = newgrid[i][j];
            if(grid[i][j]==1) SetPixel(mydc,i+50,j+40,WHITE);
            else SetPixel(mydc,i+50,j+40,BLACK);
    

    这样做:

            if( grid[i][j] != newgrid[i][j] )
            {
                grid[i][j] = newgrid[i][j];
                if(grid[i][j]==1) SetPixel(mydc,i+50,j+40,WHITE);
                else SetPixel(mydc,i+50,j+40,BLACK);
            }
    
  2. 完全停止使用 SetPixel;尝试获取位图,锁定它以访问其内存缓冲区,直接操作内存缓冲区的字节以将颜色值存储在其中,然后最后将其解锁并将其 blit 到设备上下文。这听起来可能需要大量工作,但请相信我,与对 SetPixel 的无数次调用相比,它实际上代表了 巨大 的性能改进。