This question already has answers here:
Returning an array using C
(8 answers)
Can a local variable's memory be accessed outside its scope?
(20 answers)
C: returning local struct works but returning local array does not?
(2 answers)
Closed 1 year ago.
I'm trying to implement Game of Life in C. I'm certain I programmed the rules of the game correctly, but the cells do not update correctly when running the program. In the beginning of main, I hard-coded a glider onto the map, but it doesn't 'glide' southwest like it's supposed to. I think the source of the problem might be in the update() function, but I can't find it myself.
(This isn't homework, this is just a personal project.)
#include <stdio.h>
#include <string.h>
#define MAX_Y 10 /* height */
#define MAX_X 30 /* width */
int neighbors(int grid[MAX_Y][MAX_X], int x, int y) {
int dx, dy, dstx, dsty;
int n = 0;
for (dy = -1; dy < 2; ++dy) {
for (dx = -1; dx < 2; ++dx) {
dsty = y + dy;
dstx = x + dx;
if (dsty > 0 && dsty < MAX_Y && dstx > 0 && dstx < MAX_X) {
n += !!grid[dsty][dstx]; /* use !! so that non-zero values eval to 1 */
}
}
}
/* (n > 0) ? printf("Point (%d,%d) has %d neighbors!\n", x, y, n) : 0; */
return n;
}
int **update(int grid[MAX_Y][MAX_X]) {
int new[MAX_Y][MAX_X];
memset(new, 0, sizeof new);
int i, j, n;
for (i = 0; i < MAX_Y; ++i) {
for (j = 0; j < MAX_X; ++j) {
n = neighbors(grid, i, j);
/* alive, 2 or 3 neighbors -> alive!
* dead, 3 neighbors -> alive!
* anything else -> dead :(
*/
if (grid[i][j] && (n == 2 || n == 3))
new[i][j] = 1;
else if (!grid[i][j] && n == 3)
new[i][j] = 1;
else
new[i][j] = 0;
}
}
return new;
}
void draw(int grid[MAX_Y][MAX_X]) {
int i, j;
for (i = 0; i < MAX_Y; ++i) {
for (j = 0; j < MAX_X; ++j) {
putchar((grid[i][j]) ? '#' : '.');
/* printf("|%2d", grid[i][j]); */
}
putchar('\n');
}
}
int main(void) {
int map[MAX_Y][MAX_X];
memset(map, 0, sizeof map);
map[2][2] = 1;
map[3][2] = 1;
map[4][2] = 1;
map[4][3] = 1;
map[3][4] = 1;
printf( " Game of Life v1.0\n"
"Press ENTER to step.\n");
for (;;) {
draw(map);
memcpy(map, update(map), sizeof map);
getchar();
}
}
Related
I need help with my Game of Life implementation in C. Other posts on Stackoverflow lead me to believe that my problem was to do with dangling pointers, but after modifying my program to use a global 2D array for the game grid instead of passing it to functions which return new 2D arrays, I realized that it was a problem with my update function.
I have tried hard-coding a number of simple patterns, including gliders and oscillators, and the grid doesn't update correctly. The patterns do update the same way every time the program is run, so I don't think it's a problem of uninitialized memory causing problems. I also know that there are no cells which contain values greater than 1. Therefore, the problem must lie in my mechanisms for updating the grid.
Can someone help me find the problem? I can't find anything wrong with my code and I believe I have programmed the rules correctly.
Here are my neighbors and update functions, along with the relevant variable and constant declarations.
#define MAX_Y 10 /* height */
#define MAX_X 30 /* width */
int grid[MAX_Y][MAX_X];
int neighbors(int x, int y) {
int dx, dy, dstx, dsty;
int n = 0;
for (dy = -1; dy <= 1; ++dy) {
for (dx = -1; dx <= 1; ++dx) {
dsty = y + dy;
dstx = x + dx;
if (dsty >= 0 && dsty < MAX_Y && dstx >= 0 && dstx < MAX_X)
n += !!grid[dsty][dstx]; /* use !! so that non-zero values eval to 1 */
}
}
/* (n > 0) ? printf("Point (%d,%d) has %d neighbors!\n", x, y, n) : 0; */
return n;
}
void update(void) {
int new[MAX_Y][MAX_X];
memset(new, 0, sizeof(int) * MAX_Y * MAX_X);
int i, j, n;
for (i = 0; i < MAX_Y; ++i) {
for (j = 0; j < MAX_X; ++j) {
n = neighbors(i, j);
/* alive, 2 or 3 neighbors -> alive!
* dead, 3 neighbors -> alive!
* anything else -> dead :(
*/
if (grid[i][j] && (n == 2 || n == 3))
new[i][j] = 1;
else if (!grid[i][j] && n == 3)
new[i][j] = 1;
else
new[i][j] = 0;
}
}
memcpy(grid, new, sizeof grid);
}
In your neighbors function, you need to think carefully about the loop iteration where dx and dy are both zero. Conway's Game of Life does not consider a cell to be neighbor of itself, so you need to avoid counting it.
You're also confusing yourself by using the letters i and j. You're allowing j to go all the way up to MAX_X, but then you are using j as the y coordinate when you call neighbors, so that will cause overflows and incorrect calculations. (Starting with the easier case of a 10x10 grid would sometimes save you from bugs like this.)
You should adjust the neighbors() function to omit the cell itself.
Here is a modified version:
#define MAX_Y 10 /* height */
#define MAX_X 30 /* width */
unsigned char grid[MAX_Y][MAX_X];
int neighbors(int x, int y) {
int n = -!!grid[y][x];
for (int dy = -1; dy <= 1; ++dy) {
for (int dx = -1; dx <= 1; ++dx) {
int dsty = y + dy;
int dstx = x + dx;
if (dsty >= 0 && dsty < MAX_Y && dstx >= 0 && dstx < MAX_X && grid[dsty][dstx])
n++;
}
}
return n;
}
void update(void) {
int new[MAX_Y][MAX_X] = { 0 };
for (int y = 0; y < MAX_Y; ++y) {
for (int x = 0; x < MAX_X; ++x) {
int n = neighbors(y, x);
/* alive, 2 or 3 neighbors -> alive!
* dead, 3 neighbors -> alive!
* anything else -> dead :(
*/
new[y][x] = (grid[y][x] && n == 2) || n == 3;
}
}
memcpy(grid, new, sizeof grid);
}
The neighbors() function can be simplified with fewer tests:
int neighbors(int x, int y) {
int n = -(grid[y][x] != 0);
int x1 = x - (x > 0);
int x2 = x + (x < MAX_X - 1);
int y1 = y - (y > 0);
int y2 = y + (y < MAX_Y - 1);
for (y = y1; y <= y2; y++) {
for (x = x1; x <= x2; x++) {
n += grid[y][x] != 0;
}
}
return n;
}
In line 10 I cannot find out where my problem is at first. I place int a[100][100]={0} but the cpu speed is stuck.
Then, I try to change it into a[n][n] but no output is shown.
Last, I try to change it again as if it resembles the original ones.
However, nothing works instead of a new question.
#include<stdio.h>
int main() {
int n;
while (scanf("%d", &n)) {
n *= 2;
int x = 0, y = 0, num = 1;
int a[n][n] = {0};
a[x][y] = num++;
while (n * n >= num) //定義陣列
{
while (y + 1 < n && !a[x][y + 1]) //向右
a[x][++y] = num++;
while (x + 1 < n && !a[x + 1][y]) //向下
a[++x][y] = num++;
while (y - 1 >= 0 && !a[x][y - 1]) //向左
a[x][--y] = num++;
while (x - 1 >= 0 && !a[x - 1][y]) //向上
a[--x][y] = num++;
}
for (x = 0; x < n; x++) //print 陣列
{
for (y = 0; y < n; y++) {
if (y != n - 1) {
printf("%d ", a[x][y]);
} else {
printf("%d", a[x][y]);
}
}
printf("\n");
}
break;
}
return 0;
}
At least this problem:
Variable Length Arrays (VLA) cannot be initialized via the C standard.
Alternate, assign via memset() after defining a.
// int a[n][n]={0};
int a[n][n];
memset(a, 0, sizeof a);
As you see on the image there are no * in lower part of the circle. Why is that?
Equations in the loops: y = 10 - i , x = j-10 or k-10
Circle formula = r^2 = (x-a)^2 + (y-b)^2
int i, j, k;
for (i = 0; i < 21; i++) {
if (i == 10) {
for (j = 0; j < 21; j++) {
if (pow(r * r - (j -10 -a)*(j -10 -a), 0.5) + b == 0) {
printf("*");
}
else if (j == 10) {
printf("|");
}
else {
printf("-");
}
}
}
else {
for (k = 0; k < 21; k++) {
if (pow(r * r - (k -10 -a)*(k -10 -a), 0.5) + b == 10 - i) {
printf("*");
}
else if (k == 10) {
printf("|");
}
else {
printf(" ");
}
}
}
printf("\n");
}
enter image description here
You program should be more like this:
#include <stdio.h>
#include <math.h>
int main() {
int i, j, k;
int a = 3, b = 4, r = 5;
int x, y;
for (i = 0; i < 21; i++) {
y = -(i - 10);
if (y == 0) {
for (j = 0; j < 21; j++) {
x = j - 10;
if (r * r == pow(x - a, 2) + pow(y - b, 2)) {
printf("*");
}
else if (x == 0) {
printf("|");
}
else {
printf("-");
}
}
}
else {
for (k = 0; k < 21; k++) {
x = k - 10;
if (r * r == pow(x - a, 2) + pow(y - b, 2)) {
printf("*");
}
else if (x == 0) {
printf("|");
}
else {
printf(" ");
}
}
}
printf("\n");
}
}
When you match your equation, you should allow for (-3) ^ 2 is 9, while if you take the square root of 9, you could only match a 3, unless if you also check whether the "minus" of the square root is a 3, which is troublesome.
It might also be good that if you use x and y and do the calculations, and then at the last moment, map to the screen's method of displaying it, or a similar way, instead of using i and then -(i - 10) or 10 - i every where to mean y, so I added the x and y in your program. You might also comment that (a, b) is supposed to be the center of the circle.
There is also one point about, it seems the difference between y being 0 or not is that you print out the hyphen (for the x-axis), vs a space, so your program could be:
#include <stdio.h>
#include <math.h>
int main() {
int i, j;
int a = 3, b = 4, r = 5;
int x, y;
for (i = 0; i < 21; i++) {
y = -(i - 10);
for (j = 0; j < 21; j++) {
x = j - 10;
if (r * r == pow(x - a, 2) + pow(y - b, 2)) {
printf("*");
}
else if (x == 0) {
printf("|");
}
else {
printf(y == 0 ? "-" : " ");
}
}
printf("\n");
}
}
and in fact, you don't need i and j, but can directly iterate through x and y, as your way of displaying is only one character each time:
#include <stdio.h>
#include <math.h>
int main() {
int a = 3, b = 4, r = 5;
int x, y;
for (y = 10; y >= -10; y--) {
for (x = -10; x <= 10; x++) {
if (r * r == pow(x - a, 2) + pow(y - b, 2)) {
printf("*");
}
else if (x == 0) {
printf("|");
}
else {
printf(y == 0 ? "-" : " ");
}
}
printf("\n");
}
}
I made this backtracking recursive code.
this code shows every 4x4 array filled with 1, 2, 3, 4
but no duplication in every one row and line.
but this prints only one answers, what I expected is every answers.
#include <stdio.h>
#include <stdbool.h>
// initializing array
void init_arr(int arr[][4])
{
int x;
int y;
y = 0;
while (y < 4)
{
x = 0;
while (x < 4)
{
arr[y][x] = 0;
x++;
}
y++;
}
}
// check about promising correct
bool promising(int arr[][4], int x, int y)
{
int i;
i = 0;
while (i < 4)
{
if (arr[y][i] == arr[y][x] && i != x)
return (0);
i++;
}
i = 0;
while (i < 4)
{
if (arr[i][x] == arr[y][x] && i != y)
return (0);
i++;
}
return (1);
}
// recursive function
void fill_arr(int arr[][4], int x, int y)
{
int n;
if (x == 0 && y == 0)
init_arr(arr);
if (y == 4)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
printf("%d ", arr[i][j]);
printf("\n");
}
printf("\n");
return ;
}
else if (x == 4)
fill_arr(arr, 0, y + 1);
else
{
n = 1;
while (n < 5)
{
arr[y][x] = n;
if (promising(arr, x, y))
fill_arr(arr, x + 1, y);
n++;
}
}
}
int main(void)
{
int arr[4][4];
fill_arr(arr, 0, 0);
return (0);
}
when I put printf in if(promising), this comes out
it looks like some variables are not initializing, but when I put init function to every other line, it getting messier.
Your fill_arr() isn't cleaning up before it leaves.
Add this line before the final brace:
arr[y][x] = 0;
I am using eclipse 3.2020 on WIN10 and I have a problem executing my main function.
When I run the program as it is, I get no output to conole, even when I add a printf in the first line, and the exit code is -1,073,741,819. When I comment out/ delete the line solve(s); the code run as intended and gives exit code 0.
Edit: added full code (both solve and print_sol are in solver.c)
Edit 2: As mentioned in the comments, the problem was in the code (bug) and not eclipse, I just assumed that an error message will be printed if there is one.
p.s.: I still find the fact a printf in the start won't print if there is a runtime error in another part of the main function quite weird.
main.c:
#include "solver.h"
#include <stdlib.h>
int main(int argc, char** argv){
int **grid = (int**) malloc(sizeof(int*) * 4);
for (int i = 0; i < 4 ; i++){
grid[i] = (int*) malloc(sizeof(int) * 4);
}
int mat[4][4] = {{1,0,3,0}
,{2,0,0,0}
,{3,0,0,0}
,{4,2,0,0}};
for (int i = 0; i < 4; i++){
for (int j = 0; j < 4; j++){
grid[i][j] = mat[i][j];
}
}
solver *s = create_solver(4, &grid);
solve(s);
print_sol(s);
}
solver.h:
#ifndef SOLVER_H_
#define SOLVER_H_
typedef struct sudoku_solver solver;
/*creates a new solver using the length of one row of the board.
*Then, the user will follow the instructions on screen to input the board*/
solver* create_solver(int row_len, int ***input_board_ptr);
/*if solver is NULL, an error will appear.
*Otherwise, The board that was given won't be changed, and neither
*the solver nor the solution (unless saved before using get_sol)
*will be accessible after this*/
void destroy_solver(solver *solver);
/*if solver is NULL, an error will appear.
*Otherwise, it will solve the inputed board*/
void solve(solver *solver);
/*if "solve" wasn't executed before, an error will appear.
*Otherwise, it will print a solution to the inputed board*/
void print_sol(solver *solver);
/*if "solve" wasn't executed before, an error will appear.
*Otherwise, returns a solution to the inputed board as a matrix of integers*/
int** get_sol(solver *solver);
#endif /* SOLVER_H_ */
solver.c:
#include "solver.h"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
/*the board will be represented by an array of size NxN.
*the value of every board cell is between 0 and N when 0
*means "default value"*/
typedef struct sudoku_solver{
/*length of one row of the board*/
int N;
/*a pointer to the solution board*/
int ***sol_ptr;
}solver;
solver* create_solver(int row_len, int ***input_board_ptr){
solver *s = (solver*) malloc(sizeof(solver));
/*throw an ERROR if the malloc failed*/
/*row_len is a variable, so we have to declare everything dynamically */
/*allocating the sol matrix as an array of pointers (1 out of 2D)*/
int **sol = (int**) malloc(row_len * sizeof(int*));
for (int i = 0; i < row_len; i++){
/*allocating every row (the second D)
*while making sol equal to input_board*/
sol[i] = (int*) malloc(row_len * sizeof(int));
for (int j = 0; j < row_len; j++){
sol[i][j] = (*input_board_ptr)[i][j];
}
}
s->N = row_len;
/*if row_len != pow(sqrt(row_len),2) then throw invalid input ERROR*/
s->sol_ptr = /
return s;
}
void destroy_solver(solver *s){
for (int i = 0; i < s->N; i++){
free((*(s->sol_ptr))[i]);
}
free(*(s->sol_ptr));
free(s->sol_ptr);
free(s);
}
int* calc_next(int x, int y, int *next, solver *s);
bool isSafe(int x, int y, int val, solver *s);
bool solve_rec(int x, int y, solver *s);
void solve(solver *s){
int n = s->N;
int next[2];
int ***sp = s->sol_ptr;
//find next empty space
if ((*sp)[0][0] == 0){
next[0] = 0;
next[1] = 1;
}
else{
calc_next(0, 0, next, s);
}
int nextX = next[0];
int nextY = next[1];
for (int i = 1; i < n; i++){
if (isSafe(nextX, nextY, i, s)){
(*sp)[nextX][nextY] = i;
if(solve_rec(nextX, nextY, s)){
return;
}
//backtrack
(*sp)[nextX][nextY] = 0;
}
}
printf("no sol");
return;
}
bool solve_rec(int x, int y, solver *s){
int n = s->N;
int next[2];
int ***sp = s->sol_ptr;
if (x == n - 1 && y == n - 1){
return true;
}
//find next empty space
calc_next(x, y, next, s);
int nextX = next[0];
int nextY = next[1];
for (int i = 1; i < n; i++){
if (isSafe(nextX, nextY, i, s)){
(*sp)[nextX][nextY] = i;
if(solve_rec(nextX, nextY, s)){
return true;
}
//backtrack
(*sp)[nextX][nextY] = 0;
}
}
return false;
}
bool isSafe(int x, int y, int val, solver *s){
int n = s->N;
int ***sp = s->sol_ptr;
/*check row*/
for (int j = 0; j < n; j++){
if ((*sp)[x][j] == val){
return false;
}
}
/*check col*/
for (int i = 0; i < n; i++){
if ((*sp)[i][y] == val){
return false;
}
}
/*check block
*the index of a block in a grid is just like the index of entry in block.
*In sudoku, there are bs*bs blocks, and each has bs rows and bs columns*/
int bs = sqrt(n); // block size
int block_x_index = x / bs;
int block_y_index = y / bs;
for(int i = block_x_index * bs; i < bs * (block_x_index + 1); i++){
for(int j = block_y_index * bs; j < bs * (block_y_index + 1); j++){
if ((*sp)[i][j] == val){
return false;
}
}
}
return true;
}
/*assuming x,y is not the last place in the grid,
* finds the next empty place after it*/
int* calc_next(int x, int y, int *next, solver *s){
int n;
int ***sp = s->sol_ptr;
/*find the first empty place*/
do{
n = s->N;
if (y == n - 1){
x++;
y = 0;
}
else{
y++;
}
}while ((*sp)[x][y] != 0);
next[0] = x;
next[1] = y;
return next;
}
void print_sol(solver *s){
int n = s->N;
int bs = sqrt(n); // block size
char curr;
int rows_passed, col_passed;
for (int i = 0; i < n + bs - 1; i++){
for (int j = 0; j < n + bs - 1; j++){
//if it's a grid row
if (i == bs || ((i - bs) % (bs + 1)) == 0){
//if it's also a grid col
if (j == bs || ((j - bs) % (bs + 1) == 0)){
curr = '+';
}
else{
curr = '-';
}
}
//if it's only a grid col
else if (j == bs || ((j - bs) % (bs + 1) == 0)){
curr = '|';
}
else{
rows_passed = i / (bs + 1);
col_passed = j / (bs + 1);
curr = '0' + (*(s->sol_ptr))[i-rows_passed][j-col_passed];
}
printf("%c",curr);
}
printf("\n");
}
}
int** get_sol(solver *solver){
return *(solver->sol_ptr);
}
Thank you.
Please learn how to use your debugger. In this case, it would take you directly to the problem: you're crashing with an access violation (Windows 0xc0000005) here:
void solve(solver *s) {
int n = s->N;
int next[2];
int ***sp = s->sol_ptr;
//find next empty space
if ((*sp)[0][0] == 0) { // <-- Access violation here: "sp" incorrectly initialized!
next[0] = 0;
next[1] = 1;
}
The underlying problem is that although sudoku_solver.N was initialized to "4" ... sudoku_solver.sol_ptr[0][0] is pointing to uninitialized memory.
PS:
Yes, it's very definitely "executing". It wouldn't crash if it didn't run ;)