C 康威';s的生命游戏:更改邻居计数函数后计算错误的单元格更改

C 康威';s的生命游戏:更改邻居计数函数后计算错误的单元格更改,c,sdl,sdl-2,conways-game-of-life,C,Sdl,Sdl 2,Conways Game Of Life,不知是否有人能帮我解决这个小问题。我写了一个函数来计算康威生命游戏中一个细胞的活邻居: int countLivingNeighbours(int a[][GRID_WIDTH], int x, int y){ int count = 0, cx, cy; for(cy = y - 1; cy <= y + 1; cy++){ for(cx = x - 1; cx <= x + 1; cx++){ if(a[cy][cx] =

不知是否有人能帮我解决这个小问题。我写了一个函数来计算康威生命游戏中一个细胞的活邻居:

int countLivingNeighbours(int a[][GRID_WIDTH], int x, int y){
    int count = 0, cx, cy;

    for(cy = y - 1; cy <= y + 1; cy++){
        for(cx = x - 1; cx <= x + 1; cx++){
            if(a[cy][cx] == ALIVE){
                count++;
            }
        }
    }

    // subtract 1 so it's not counting it's own cell
    count--;

    return count;
}
int countlivinginneights(int a[][网格宽度],int x,int y){
整数计数=0,cx,cy;

对于(cy=y-1;cy为什么不管单元格是否处于活动状态,都要为单元格本身减去一个?首先,使用调试器跟踪这似乎是一个很好的问题。尽管如此,我有一种预感,只有当单元格处于活动状态时,您才可能要减去相邻的计数,即
如果(a[x][y])计数--;
…如
否则如果(a[cy][cx]==DEAD和countlivinginneights(a,cx,cy)==3)
其中计数将短1。@riodoro1谢谢,似乎就是这样!我需要解决的下一个问题是为什么第一次更新时随机垃圾单元会出现在屏幕的顶部/底部。@WeatherVane你是什么意思?
#include <SDL.h>
#include <stdio.h>
#include <stdbool.h>

#define CELL_SIZE 10
#define GRID_WIDTH 100
#define GRID_HEIGHT 100

typedef enum {ALIVE, DEAD} State;

// General functions
void quitAll(void);

// SDL related visual functions
void drawGrid(SDL_Renderer *r, int winWidth, int winHeight);
void drawCells(SDL_Renderer *r, int a[][GRID_WIDTH]);

// Game of Life functions
void updateCells(int a[][GRID_WIDTH]); // takes cells array as input
int countLivingNeighbours(int a[][GRID_WIDTH], int x, int y);

int main(int argc, char *argv[]){
    // Initialise SDL
    SDL_Init(SDL_INIT_VIDEO);

    // Create window
    int winWidth = GRID_WIDTH * CELL_SIZE;
    int winHeight = GRID_HEIGHT * CELL_SIZE;

    SDL_Window *window = SDL_CreateWindow(
        "Game of Life",         // Title
        SDL_WINDOWPOS_CENTERED, // Initial window x position
        SDL_WINDOWPOS_CENTERED, // Initial window y position
        winWidth,               // Window Width
        winHeight,              // Window Height
        0                       // Flags
    );

    if(window == NULL){
        printf("Failed to create window. %s\n", SDL_GetError());
        return 1;
    }

    // Create renderer
    SDL_Renderer *renderer = SDL_CreateRenderer(
        window,                     // Window
        -1,                         // Monitor index (-1 for first available)
        SDL_RENDERER_ACCELERATED    // Flags
    );

    if(renderer == NULL){
        printf("Failed to create renderer. %s\n", SDL_GetError());
        return 1;
    }

    // Setup event handling + mouse co-ordinate handling
    SDL_Event event;
    int mouseX, mouseY;
    bool mouse_left_down = false;
    bool mouse_right_down = false;

    // Set all cells to initial state of dead
    int cells[GRID_HEIGHT][GRID_WIDTH];
    int cx, cy;
    for(cy = 0; cy < GRID_HEIGHT; cy++){
        for(cx = 0; cx < GRID_WIDTH; cx++){
            cells[cy][cx] = DEAD;
        }
    }

    while(1){
        // Handle events/input
        while(SDL_PollEvent(&event) != 0){
            switch(event.type){
                case SDL_QUIT: // Check if user has quit
                    return 1;

                case SDL_MOUSEBUTTONDOWN:
                    if(event.button.button == SDL_BUTTON_LEFT){
                        mouse_left_down = true;
                        break;
                    } else if(event.button.button == SDL_BUTTON_RIGHT){
                        mouse_right_down = true;
                        break;
                    }

                case SDL_MOUSEBUTTONUP:
                    if(event.button.button == SDL_BUTTON_LEFT){
                        mouse_left_down = false;
                        break;
                    } else if(event.button.button == SDL_BUTTON_RIGHT){
                        mouse_right_down = false;
                        break;
                    }

                // If user presses space, simulate a single change
                case SDL_KEYDOWN:
                    if(event.key.keysym.sym == SDLK_SPACE){
                        updateCells(cells);
                    }


            }
        }

        // Allow user to draw new living cells
        if(mouse_left_down == true){
            SDL_GetMouseState(&mouseX, &mouseY); // Update mouse position
            cells[mouseY / CELL_SIZE][mouseX / CELL_SIZE] = ALIVE; // Set the clicked on cell to alive
        }

        // Allow user to kill cells
        else if(mouse_right_down == true){
            SDL_GetMouseState(&mouseX, &mouseY); // Update mouse position
            cells[mouseY / CELL_SIZE][mouseX / CELL_SIZE] = DEAD; // Set the clicked on cell to alive
        }



        // Set screen colour to white
        SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);

        // Render white to screen (clear screen)
        SDL_RenderClear(renderer);

        // Draw the grid and living cells
        drawGrid(renderer, winWidth, winHeight);
        drawCells(renderer, cells);

        // Update screen
        SDL_RenderPresent(renderer);
    }

    // Exit SDL and SDL_image
    SDL_Quit();
    return 0;
}

/*
1. Any live cell with fewer than two live neighbours dies, as if caused by underpopulation.
2. Any live cell with two or three live neighbours lives on to the next generation.
3. Any live cell with more than three live neighbours dies, as if by overpopulation.
4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
*/
void updateCells(int a[][GRID_WIDTH]){
    int new[GRID_HEIGHT][GRID_WIDTH];
    int cy, cx; // vertical count, horizontal count

    for(cy = 0; cy < GRID_HEIGHT; cy++){
        for(cx = 0; cx < GRID_WIDTH; cx++){
            if(a[cy][cx] == ALIVE && countLivingNeighbours(a, cx, cy) < 2){
                new[cy][cx] = DEAD;
            }

            // Any live cell with two or three live neighbours lives on to the next generation.
            if(a[cy][cx] == ALIVE && (countLivingNeighbours(a, cx, cy) == 2 || countLivingNeighbours(a, cx, cy) == 3)){
                new[cy][cx] = ALIVE;
            }

            // Any live cell with more than three live neighbours dies, as if by overpopulation.
            else if(a[cy][cx] == ALIVE && countLivingNeighbours(a, cx, cy) > 3){
                new[cy][cx] = DEAD;
            }

            // Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
            else if(a[cy][cx] == DEAD && countLivingNeighbours(a, cx, cy) == 3){
                new[cy][cx] = ALIVE;
            }

            else{
                new[cy][cx] = DEAD;
            }
        }
    }

    // Update all cells into new states
    for(cy = 0; cy < GRID_HEIGHT; cy++){
        for(cx = 0; cx < GRID_WIDTH; cx++){
            a[cy][cx] = new[cy][cx];
        }
    }
}

// THERE'S NO ERROR CHECKING HERE WHICH IS BAD
// Should ideally check if a cell even exists before checking its state
int countLivingNeighbours(int a[][GRID_WIDTH], int x, int y){
    int count = 0, cx, cy;

    for(cy = y - 1; cy <= y + 1; cy++){
        for(cx = x - 1; cx <= x + 1; cx++){
            if(a[cy][cx] == ALIVE){
                count++;
            }
        }
    }

    // subtract 1 so it's not counting it's own cell
    count--;

    return count;
}

void drawGrid(SDL_Renderer *r, int winWidth, int winHeight){
    // Draw vertical grid lines
    for(int v = CELL_SIZE; v < winWidth; v += CELL_SIZE){
        // Set draw colour to grey
        SDL_SetRenderDrawColor(r, 110, 110, 110, 110);

        // Draw vertical line
        SDL_RenderDrawLine(r, v, 0, v, winHeight);
    }

    // Draw horizontal grid lines
    for(int h = CELL_SIZE; h < winHeight; h += CELL_SIZE){
        // Set draw colour to grey
        SDL_SetRenderDrawColor(r, 110, 110, 110, 110);

        // Draw horizontal line
        SDL_RenderDrawLine(r, 0, h, winWidth, h);
    }
}

void drawCells(SDL_Renderer *r, int a[][GRID_WIDTH]){
    // Define cell width/height
    SDL_Rect cellRect;
    cellRect.w = CELL_SIZE + 1; // Same size as one cell +1 so it covers the grid line fully
    cellRect.h = CELL_SIZE + 1; // Same size as one cell +1 so it covers the grid line fully

    // Draw living cells
    int cx, cy;
    for(cy = 0; cy < GRID_HEIGHT; cy++){
        for(cx = 0; cx < GRID_WIDTH; cx++){
            if(a[cy][cx] == ALIVE){
                // Set cell x/y pos
                cellRect.x = cx * CELL_SIZE;
                cellRect.y = cy * CELL_SIZE;

                SDL_SetRenderDrawColor(r, 0, 0, 0, 0);
                SDL_RenderFillRect(r, &cellRect);
            }
        }
    }
}