Conway's Game Of Life In C - c

I have made a version of conways game of life in C, using a 2d array which should wrap around the sides. Unfortunately all that happens is the numbers flick back and forth between 1 and 0 with no clear pattern. Here is the code:
#include <stdio.h>
int main(){
int const WIDTH = 100;
int const HEIGHT = 100;
int const CYCLES = 1000;
int grid[HEIGHT][WIDTH];
int temp[HEIGHT][WIDTH];
int row;
int col;
for(row = 0; row < HEIGHT; row++){
for(col = 0; col < WIDTH; col++){
grid[row][col] = 0;
}
}
int i;
int x;
int y;
int neighbours;
for(i = 0; i < CYCLES; i++){
for(row = 0; row < HEIGHT; row++){
for(col = 0; col < WIDTH; col++){
temp[row][col] = 0;
}
}
for(row = 0; row < HEIGHT; row++){
for(col = 0; col < WIDTH; col++){
neighbours = 0;
for(y = -1; y < 2; y++){
for(x = -1; x < 2; x++){
if(x != 0 && y != 0 && grid[(row + y) % HEIGHT][(col + x) % WIDTH] == 1){
neighbours++;
}
}
}
if(grid[row][col] == 1){
if(neighbours < 2 || neighbours > 3){
temp[row][col] = 0;
}else{
temp[row][col] = 1;
}
}else if(grid[row][col] == 0){
if(neighbours == 3){
temp[row][col] = 0;
}else{
temp[row][col] = 1;
}
}
}
}
for(row = 0; row < HEIGHT; row++){
for(col = 0; col < WIDTH; col++){
grid[row][col] = temp[row][col];
printf("%d", grid[row][col]);
}
printf("\n");
}
printf("\n");
}
}

I do notice one problem.
The 4th rule states that a dead cell should become alive again if it has exactly 3 neighbors. Currently, your code does the opposite
else if(grid[row][col] == 0){
if(neighbours == 3){
temp[row][col] = 0;
}else{
temp[row][col] = 1;
}
}
This will leave the cell dead if there are exactly 3 and make it alive when that is not the case. Switch the 1 and the 0 and it should work.

The way you count your neighbors is false (what about -1%HEIGHT for example???). I suppose that you want to use a torus (leftmost column connected to rightmost column and the same for lines), so you need to make special cases for borders. A trick is to use modulus like the following.
Suppose you have a line of length N, then for each x from 0 to N-1, compute mid=x+N, get neighbors as left=mid-1 and right=mid+1, then count neighbors with grid(left%N), grid(mid%N), grid(right%N) (add second dimension the same way of course). So you will catch the torus property without any special cases...
If you want to be sure that it works as expected, I can suggested you to initialize the grid to a well-known GOL pattern (a simple glider for example).
Also verify that the GOL rules are the right ones.

Related

cs50 BLUR PSET4 invalid or unsupported image format

This is a problem form cs50 problem set 4 (less comfortable). I'm currently stuck on the blur part. It compiles fine but the output is "invalid or unsupported image format".
RGBTRIPLE temp[height][width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
float red_sum = 0;
float blue_sum = 0;
float green_sum = 0;
int count = 0;
for (int x = i-1 ; x <= i+1 ; i++)
{
for (int y = j-1 ; y <= j+1 ; j++)
{
if ( x >= 0 && x < height && y >= 0 && y < width )
{
red_sum += image[x][y].rgbtRed;
blue_sum += image[x][y].rgbtBlue;
green_sum += image[x][y].rgbtGreen;
count ++;
}
}
}
int red_avg = round(red_sum/count);
int blue_avg = round(blue_sum/count);
int green_avg = round(green_sum/count);
temp[i][j].rgbtRed = red_avg;
temp[i][j].rgbtBlue = blue_avg;
temp[i][j].rgbtGreen = green_avg;
}
}
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
image[i][j]=temp[i][j];
}
}
You have 2 typos which cause that you are corrupting lots of memory
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
float red_sum = 0;
float blue_sum = 0;
float green_sum = 0;
int count = 0;
for (int x = i-1 ; x <= i+1 ; i++) // << This loops until i overflows
{
for (int y = j-1 ; y <= j+1 ; j++) // << this loop until j overflows
{
// in second iteration you will already have negative values but due to these checks you don't access `image` out of bounds.
if ( x >= 0 && x < height && y >= 0 && y < width )
{
red_sum += image[x][y].rgbtRed;
blue_sum += image[x][y].rgbtBlue;
green_sum += image[x][y].rgbtGreen;
count ++;
}
}
}
int red_avg = round(red_sum/count);
int blue_avg = round(blue_sum/count);
int green_avg = round(green_sum/count);
// After processing data for first pixel, both `i`and `j` contain negative values causing out of bounds accesses.
temp[i][j].rgbtRed = red_avg;
temp[i][j].rgbtBlue = blue_avg;
temp[i][j].rgbtGreen = green_avg;
}
}
Due to overflow and out of bounds accesses you have lots of undefined behaviour in your program.
You can corrupt any kind of memory including your own counter variables, the image header or anything else.
Anything can happen...
The statement about negative values assumes that two's complement is used and integers overflow from highest positive value to lowest negative value. Generally this is implementation defined/undefined.
I only wonder why file type error is given because I would assume that is done before your function is called. But maybe CS50 does it again afterwards.

Setting a 2D array value overwrites another in C

When creating a 2D array and setting the value of some element, other elements get set too, what could be the reason behind such anomaly?
Following is the code example.
#include <stdio.h>
#define MAX_X 240
#define MAX_Y 2
char grid[MAX_X][MAX_Y];
int main()
{
int i,j,row,col;
col = MAX_X;
row = MAX_Y;
// Init 2D array
for (i = 0; i < row; i++) {
for (j = 0; j < col; j++) {
grid[i][j] = '.';
}
}
grid[0][121] = 'X'; // << [ISSUE HERE] `X` is written into 2 elements instead of 1
// Display 2D array
for (i = 0; i < row; i++) {
for (j = 0; j < col; j++) {
printf("%c", grid[i][j]);
}
printf("\n");
}
}
Note:
Issue showed up on g++, and was reproduced using this snippet on online gdb's compiler
You define grid as grid[240][2] which means 240 rows x 2 columns, and as #wildplasser mention you swap the col and row assignment. It should be:
row = MAX_X;
col = MAX_Y;

CS50 Pset4 Filter (less comfortable) blur function Algorithmic Issue

info about this task
when I try to implement blur function, It works fine to me on a picture, but check50 (cs50 test program) gives warning for my outputs.
Here is my code
void blur(int height, int width, RGBTRIPLE image[height][width])
{
float average_red = 0;
float average_green = 0;
float average_blue = 0;
float count = 0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
// reset values
average_red = 0;
average_blue = 0;
average_green = 0;
count = 0;
// look for around a pixel 3x3 box
// column
for (int k = i - 1; k < i + 2; k++)
{
// row
for (int l = j - 1; l < j + 2; l++)
{
// if pixel on the top
if (k == -1)
{
// it skips a column because it is out of the border
break;
}
// if pixel is on the left side
if (l == -1)
{
// skips a row otherwise it is out of the border
continue;
}
// if pixel passes the bottom
if (k >= height)
{
break;
}
// if pixels passes the right side
if (l >= width)
{
continue;
}
// everything else
else
{
average_red += image[k][l].rgbtRed;
average_green += image[k][l].rgbtGreen;
average_blue += image[k][l].rgbtBlue;
count++;
}
}
}
average_red /= count;
average_green /= count;
average_blue /= count;
image[i][j].rgbtRed = round(average_red);
image[i][j].rgbtGreen = round(average_green);
image[i][j].rgbtBlue = round(average_blue);
}
}
return;
}
expected output vs my output is here (blur functions output very down bellow)
It is working fine on the corner but other pixel values are very close to correct output, but not the same.
Any help appreciated
The code needs to take several factors into consideration. Suggest:
if the resulting row number is <0 or >(height-1) then don't calc that pixel
if the resulting column number is <0 or >(width-1) then don't calc that pixel
Therefore, for each of the surrounding 8 pixels, apply the two above criteria.
I solved my own problem, thanks for helps anyway
problem in was my sum calculation. it keeps result in image[i][j] and than again uses this value again.
I copy image values to a new value and use on this. Here is my code
void blur(int height, int width, RGBTRIPLE image[height][width])
{
// copy original value to a new value to keep changing values
RGBTRIPLE copy[height][width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
copy[i][j] = image[i][j];
}
}
float average_red = 0.0f;
float average_green = 0.0f;
float average_blue = 0.0f;
float count = 0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
// reset values
average_red = 0.0f;
average_blue = 0.0f;
average_green = 0.0f;
count = 0;
// look for around a pixel 3x3 box
// column
for (int k = i - 1; k < i + 2; k++)
{
// row
for (int l = j - 1; l < j + 2; l++)
{
// if pixel on the top
if (k == -1)
{
// it skips a column because it is out of the border
break;
}
// if pixel is on the left side
else if (l == -1)
{
// skips a row otherwise it is out of the border
continue;
}
// if pixel passes the bottom
else if (k >= height)
{
break;
}
// if pixels passes the right side
else if (l >= width)
{
continue;
}
// everything else
else
{
average_red += copy[k][l].rgbtRed;
average_green += copy[k][l].rgbtGreen;
average_blue += copy[k][l].rgbtBlue;
count++;
}
}
}
average_red /= count;
average_green /= count;
average_blue /= count;
image[i][j].rgbtRed = round(average_red);
image[i][j].rgbtGreen = round(average_green);
image[i][j].rgbtBlue = round(average_blue);
}
}
return;
}

How to check if an array location is a certain number

I am in the middle of a project (in C) where I am programming a bingo game, and there is one last function to make, which is the one to check if there is a bingo or not. I have an array of 5 x 5 generated random numbers, and I generate a random number through user input. How do I make the array change that number (if it is in fact in the array) to 0, and then check if there is a bingo or not through user input?
Here is the code to generate the array
for (int row = 0; row < 5; row++) {
for(int column = 0; column < 5; column++) {
if(row == 2 && column == 2) {
board[row][column] = 0;
} else {
int num = rand() %15 + 1 +(column * 15);
for(int i = 0; i < 75; i++) {
if(num == used[i]) {
num = rand() %15 + 1 +(column * 15);
}
}
board[row][column] = num;
used[used_counter] = num;
used_counter++;
}
}
}
int generate_number(int boneyard[75], int *boneyard_counter) {
int num = rand() %75 + 1;
for (int i = 0; i <75; i++){
if(num == boneyard[i]);
num = rand() %75 + 1;
}
boneyard[*boneyard_counter] = num;
boneyard_counter++;
return num;
}
And here is the code to generate the random number.
You'd do something like this:
int found_match = 0;
for(int row = 0; row < 5; ++row){
for(int column = 0; column < 5; ++column){
if(board[row][column] == num){
board[row][column] = 0;
found_match = 1;
goto loop_end;
}
}
}
loop_end:
if(found_match){
/*
Check all diagonals, rows, and columns to see if any one of them contains only zeroes,
stopping if you find that a diagonal/row/column that does in fact contain only zeroes
and informing the player that they've won.
*/
}

Array element disappears

I'm trying to track a player's location with x marking their spot. When the player enters a string I increment the coordinates accordingly. However when the player is located one space from the perimeter, then attempts to move to the edge of the map, the player disappears.
Example:
.....
...x.
.....
.....
.....
Player located at 'x'
If player enters string "right" and I move player_loc, array simply returns:
.....
.....
.....
.....
.....
I attempted to add a sort of buffer by increasing the size of the array. No luck. I've been stuck on this for almost a week now. Any help would be appreciated. I apologize for messy code. I'm a total newbie at this and I'm really just futzing around in the dark with all this stuff. I've researched this across the forums here and haven't found a solution. If you know of something that I possibly (probably) missed feel free to point me in that direction.
#include <stdio.h>
#include <string.h>
char map[6][6];
char player_loc = 'x';
int row;
int col;
void init_map()
{
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
map[i][j] = '.';
}
}
}
void print_map()
{
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
printf("%c", map[i][j]);
}
printf("\n");
}
}
int get_player_loc()
{
for (int j = 0; j < 5; j++) {
for (int k = 0; k < 5; k++) {
if(map[j][k] == player_loc)
{
row = k;
col = j;
}
}
}
return row;
return col;
}
void init_player_loc()
{
int check = 1;
for (int g = 0; g < 5; g++) {
for (int h = 0; h < 5; h++) {
if (map[g][h] == 'x') {
check = 0;
}
}
}
if(check == 1) {
map[0][0] = player_loc;
} else {
get_player_loc();
}
}
void move_left()
{
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (map[i][j] == player_loc) {
map[i][j-1] = player_loc;
map[i][j] = '.';
}
}
}
}
void move_right()
{
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (map[i][j] == player_loc) {
map[i][j+1] = player_loc;
map[i][j] = '.';
}
}
}
}
int main(int argc, char* argv[])
{
char input[15];
printf("You enter a room...you can go left, right, or straight. Which way do you go?\n");
int done = 0;
init_map();
map[3][3] = player_loc;
//init_player_loc();
print_map();
while (!done) {
scanf("%s", input);
if (strcmp("left", input) == 0) {
move_left();
printf("You go left...\n");
print_map();
get_player_loc();
printf("%d %d\n", row, col);
done = 1;
}
else if (strcmp("right", input) == 0) {
move_right();
printf("You go right...\n");
print_map();
get_player_loc();
printf("%d %d\n", row, col);
done = 1;
}
else if (strcmp("straight", input) == 0) {
printf("You go straight...");
done = 1;
}
else {
printf("Sorry, can't do that.\n");
}
}
}
You must break the loop if you find the player location, e.g
void move_right()
{
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (map[i][j] == player_loc) {
map[i][j+1] = player_loc;
map[i][j] = '.';
return;
}
}
}
}
In your code you move right the player, and the next loop will find the player in the new location and do the right move again, forever.
Moreover in your code you are not taking care of boundaries of your 2d matrix: j+1 is valid only if j<5.
Then a better code should be
void move_right()
{
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (map[i][j] == player_loc) {
map[i][j+1] = player_loc;
map[i][j] = '.';
return;
}
}
}
}
The problem is that your move_right function picks up the player and moves them completely off of the map. Let's say your player is at [0, 2] and step through the code.
for (int j = 0; j < 5; j++) {
if (map[i][j] == player_loc) {
map[i][j+1] = player_loc;
map[i][j] = '.';
}
}
[0, 0] No player here, move along
[0, 1] No player here, move along
[0, 2] Found a player! Move them right to [0, 3]
[0, 3] Found a player! Move them right to [0, 4]
[0, 4] Found a player! Move them right to [0, 5]
At 5, the loop ends. Because of the buffer you added, your array is 6x6, so the player is stashed in the wings without crashing the program. There are a few things you should do:
Once you've found and moved the player, break or return so they'll only move once.
Make your array 5x5 (or print all 6x6) so you can see everything.
Do some bounds checking so the player isn't allowed to move right from j = 5.
Watch out for this same bug in move_up, where it would happen as you increment i.
Your loops allow for checking the position twice, once at i,j, and again at i,(j+1) (or some other variant). This probably isn't what you intend. After you find the player you should make the updates and then break out of the loops.
Also, the code as is allows for indexing passed the bounds of the array, in theory. Also not what is desired. You may consider bounds checking. I don't know what is supposed to happen when the player moves right and there is a wall to the right. Does he not move? Wrap around? LR corner could cause seg fault as it is now.
You appear to have row and column indeces transposed in the get_player_loc function, as well as having two return statements (the compiler should warn you about unreachable code), neither of which is required or used by the calling code.
At the start, initialise the row and col variables. (Values taken from your main.)
int row = 3;
int col = 3;
Change the get_player_loc function so that it just updates the globals row and col. It sets row and col to 0 if the player is not found, as per the original.
void get_player_loc(void)
{
for (int j = 0; j < 5; j++) {
for (int k = 0; k < 5; k++) {
if(map[j][k] == player_loc)
{
// The meaning of row and col is set by how they are used
// to index the array in the move and print functions. Keep
// the same order and meaning here.
row = j;
col = k;
return;
}
}
}
// Set row and col to 0 if the location is not found.
row = 0;
col = 0;
map[0][0] = player_loc;
}
You'll still have problems when they reach an edge, due to the index into the array going out of bounds in the move functions, but that's a different problem.

Resources