Игра жизни Конвей: изменения ячейки вычисляются неправильно после изменения функции подсчета соседей

Интересно, сможет ли кто-нибудь помочь мне решить эту небольшую проблему. Я написал функцию для подсчета живых соседей в ячейке в игре «Жизнь жизни Конвея»:

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; } 

В качестве аргумента требуется 2-мерный массив всех ячеек, а также координаты x и y ячейки, которую мы хотим проверить.

При запуске программы, использующей эту функцию для подсчета живых соседей, это приводит к некоторому сбою. Трудно описать, поэтому я разместил изображение одной последней компоновки ячейки, которую у меня было:

Пример ячейки

Обычно бывают видимые шаблоны, фигуры и блоки, но вместо этого мы просто получаем строки.

Если бы кто-нибудь мог мне помочь, это было бы здорово!

Я также опубликую полный код, если я неправильно определил проблему:

 #include  #include  #include  #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)  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); } } } } в #include  #include  #include  #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)  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); } } } }