Click here to Skip to main content
16,019,107 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello everyone, please I need clarification about some sections of John Conway's Game of life code written in C that is parallelized with OpenMp. The code is below, please if any of the questions is too elementary please don't be offended.

#include <stdio.h>
#include <string.h>
#include <omp.h>

#define NR 15
#define NC 15
int mod(int x, int y) { return x % y; }

char alivep(int neighbours, char alive) {
    if (alive && (neighbours == 2 || neighbours == 3)) return 1;
    else {
        if (neighbours == 3) return 1; else return 0;
    }
}

// Swapping the two grids   
#define SWAP_BOARDS( b1, b2 )  do { \
 char* temp = b1; \
 b1 = b2; \
 b2 = temp; \
 } while(0)

// Simplifying access to grid elements 
#define BOARD( G, X, Y )  ((G)[NC*(X)+(Y)])

char* sequential_game_of_life(char* outgrid, char* ingrid,
    const int nrows, const int ncols, const int gens_max) {

    int curgen, t;


    for (curgen = 0; curgen < gens_max; curgen++)
    {
#pragma omp parallel
        {
#pragma omp for 
            for (t = 0; t < nrows * ncols; t++)
            {
                int i = t / ncols;
                int j = t % ncols;
                const int inorth = mod(i - 1, nrows);
                const int isouth = mod(i + 1, nrows);
                const int jwest = mod(j - 1, ncols);
                const int jeast = mod(j + 1, ncols);

                const char neighbor_count =
                    BOARD(ingrid, inorth, jwest) +
                    BOARD(ingrid, inorth, j) +
                    BOARD(ingrid, inorth, jeast) +
                    BOARD(ingrid, i, jwest) +
                    BOARD(ingrid, i, jeast) +
                    BOARD(ingrid, isouth, jwest) +
                    BOARD(ingrid, isouth, j) +
                    BOARD(ingrid, isouth, jeast);
 
                BOARD(outgrid, i, j) = alivep(neighbor_count, BOARD(ingrid, i, j));
            }
        }
        SWAP_BOARDS(outgrid, ingrid);
    }

    return outgrid;
}

void print_board(char* ingrid, int nrows, int ncols)
{
    for (int i = 0; i < nrows; ++i)
    {
        for (int j = 0; j < ncols; ++j)
        {
            printf("%c", BOARD(ingrid, i, j) == 0 ? '.' : '*');
        }
        printf("\n");
    }
}

int main() {
    const int GENS_MAX = 20;

    char ingrid[NR * NC];
    char outgrid[NR * NC];
    memset(ingrid, 0, NR * NC * sizeof(ingrid[0]));
    memset(outgrid, 0, NR * NC * sizeof(outgrid[0]));

    //draw an example pattern
    ingrid[5 * NC + 4] = 1;
    ingrid[5 * NC + 5] = 1;
    ingrid[5 * NC + 6] = 1;
    ingrid[5 * NC + 7] = 1;
    

    printf("Initial board\n");
    print_board(ingrid, NR, NC);

    char* out = sequential_game_of_life(outgrid, ingrid, NR, NC, GENS_MAX);

    printf("Final board\n");
    print_board(out, NR, NC);
}


Question 1 - (This has nothing to do the parallel section) At the BOARD definition -
#define BOARD( G, X, Y )  ((G)[NC*(X)+(Y)])
Why is the index cast to "G" or what is "G" ? If this code was written in Java "G" would have been used to upcast or downcast either a primitive, wrapper class data or an object reference.

Question 2 - (In the parallel section)
#pragma omp parallel
        {
#pragma omp for 
            for (t = 0; t < nrows * ncols; t++)
            {
                int i = t / ncols;
                int j = t % ncols;

Why is for int i the pointer t is divided by the number of columns and for int j the pointer t a modulus operator is applied to the number of columns as shown above ?

Question 3 - The calculated constant values of inorth, isouth, jwest, jeast in this part of the code
#pragma omp parallel
        {
#pragma omp for 
            for (t = 0; t < nrows * ncols; t++)
            {
                // why is the first two being done ?
                int i = t / ncols;
                int j = t % ncols;
                const int inorth = mod(i - 1, nrows);
                const int isouth = mod(i + 1, nrows);
                const int jwest = mod(j - 1, ncols);
                const int jeast = mod(j + 1, ncols);

Are they the positions of those cells in the game ?
Thanks for any help inadvance.

What I have tried:

I have worked on every other part of the code and I totally understand all other parts.
Posted
Updated 13-Feb-22 18:39pm
v4

1 solution

1. The macro substitution makes the expression look like this :
C++
BOARD(ingrid, inorth, jwest) -> ((ingrid)[NC*(inorth)+(iwest)])
In this the parenthesis are just enclosing the token, or ingrid in this case, to make it a singular expression.

2. i is the row index and j is the column index.

3. They are used to determine the row and column of the cells in those directions relative to the given cell at [i][j]. North is the cell one row above, south is one row below, east is one column to the right, and west is one column to the left.
 
Share this answer
 
Comments
UT7 14-Feb-22 18:41pm    
@Rick York, thanks a lot.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900