15,846,212 members
See more:
I'm simulating the interactions between two kind of particles in a square surface in C.

The steps of my simulations are the following:

1) We start with an empty surface and select at random a site of it.

2) We choose randomly between particle #1 and particle #2. To do so, we define a random number "r" so that if it's less than a given value "Y", particle #1 is chosen. Otherwise, we choose particle #2.

3) If particle #1 is chosen, we look up among the four nearest neighbors of the site. If among the nearest neighbors of such a site, any of them is occupied by particle #2, they react to form particle #3. Otherwise, particle #1 remains adsorbed.

4) If particle #2 is chosen, we look up among the four nearest neighbors of the site. If among the nearest neighbors of such a site, any of them is occupied by particle #1, they react to form particle #3. Otherwise, particle #2 remains adsorbed.

This is the code I have written so far:

What I have tried:

```#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

//define the dimensions of the grid
#define MAX_X 3
#define MAX_Y 3
#define Y 0.55

//define the states of a cell in grid`
typedef enum  { S_EMPTY, P1_OCCUPIED, P2_OCCUPIED, S_NONE } gstate;

// help generate random coordinate of the grid
int gridrnd(int max)
{
return (rand() % max);
}

// generates random coordinates of the grid
int generate_coords(int* j, int* i )
{
if (!i || !j)
return 1;

*i = gridrnd(MAX_X);
*j = gridrnd(MAX_Y);

// printf("(%d,%d)\n\n", *j, *i);
return 0;
}

//function to initialize the grid as empty
void grid_init(gstate grid[MAX_Y][MAX_X])
{
for (int j = 0; j < MAX_Y; j++) {
for (int i = 0; i < MAX_X; i++) {
grid[j][i] = S_EMPTY;
}
}
}

//Function that locates the four nearest neighbors of the chosen site, considering periodic boundary conditions
int get_limited_coord(int coord, int coord_max){
if (coord >= 0 && coord < coord_max) {
return coord;
} else if (coord >= coord_max) {
return coord - coord_max;
} else {
return coord + coord_max;
}
}

//Function that prints individually the "right" neighbor of the chosen site
gstate rightneighbor(int *x, int *y, gstate grid[MAX_X][MAX_Y], int *rx, int *ry){
*ry = get_limited_coord(*y, MAX_Y);
*rx = get_limited_coord(*x+1, MAX_X);
printf("right neighbor = (%d,%d)\n\n",*ry,*rx);
return 0;
}

//Function that prints individually the "left" neighbor of the chosen site
gstate leftneighbor(int *x, int *y, gstate grid[MAX_X][MAX_Y], int *lx, int *ly){
*ly = get_limited_coord(*y , MAX_Y);
*lx = get_limited_coord(*x-1, MAX_X);
printf("left neighbor = (%d,%d)\n\n",*ly,*lx);
return 0;
}

//Function that prints individually the "up" neighbor of the chosen site
gstate upneighbor(int *x, int *y, gstate grid[MAX_X][MAX_Y], int *ux, int *uy){;
*uy = get_limited_coord(*y-1, MAX_Y);
*ux = get_limited_coord(*x , MAX_X);
printf("up neighbor = (%d,%d)\n\n",*uy,*ux);
return 0;
}

//Function that prints individually the "down" neighbor of the chosen site
gstate downneighbor(int *x, int *y, gstate grid[MAX_X][MAX_Y], int *dx, int *dy){
*dy = get_limited_coord(*y+1, MAX_Y);
*dx = get_limited_coord(*x , MAX_X);
printf("down neighbor = (%d,%d)\n\n",*dy,*dx);
return 0;
}

//To give structure to my data
typedef struct SimulInfo
{
gstate grid[MAX_Y][MAX_X];
//int particle[3];//counters for the number of cells
int particle1;
int particle2;
int particle3;
int availcells;
int fullcells;
}   SimulInfo;

//function to fill a site with particle 1

int adsorb_particle1(SimulInfo * psi,int x, int y){
psi->grid[y][x] = P1_OCCUPIED;
psi->particle1++;
//psi->particle[0]++;
psi->availcells--;
psi->fullcells++;
//printf("particle1 = %d\n\n",psi->particle[0]);
return 0;
}

//function to fill a site with particle 2

int adsorb_particle2(SimulInfo * psi,int x, int y){
psi->grid[y][x] = P2_OCCUPIED;
psi->particle2++;
//psi->particle[1]++;
psi->availcells--;
psi->fullcells++;
//printf("particle2 = %d\n\n",psi->particle[1]);
return 0;
}

//function to form particle 3

int form_particle3(SimulInfo * psi, int x, int y){
psi->grid[y][x] = S_EMPTY;
psi->particle3++;
//psi->particle[2]++;
psi->availcells++;
psi->fullcells--;
//printf("particle3 = %d\n\n",psi->particle[2]);
return 0;
}

int main(){
int i = 0, j = 0;
gstate grid[MAX_Y][MAX_X];
int particle[3]={0};
int particle1 = 0, particle2 = 0, particle3 = 0; // counters for the number of particle1 and particle2
int availcells = MAX_X * MAX_Y; //first we initialize with all the cells of the matrix available
int fullcells = 0;
int rounds = 0;
int rx, ry, lx, ly, ux, uy, dx, dy;
double N = 1.0*sizeof(grid)/sizeof(grid[0][0]); //number of the total sites in the matrix
double r=0, r1=0, r2=0;
SimulInfo psi;

srand((unsigned)time(0));

// Initialize grid to be S_EMPTY
grid_init(grid);

while(rounds<10){
//LOCATE AN ENTRY OF THE MATRIX RANDOMLY
generate_coords(&j, &i);

//EVALUATE THE CHOOSEN SITE
switch (grid[j][i])
{
case S_EMPTY:
//printf("IT'S S_EMPTY, LET'S FILL IT WITH A PARTICLE. FIRST LET'S GENERATE TO DECIDE IFIT WILL BE TRAPPED\n\n");

r = rand()/(float)RAND_MAX;
printf("r = %lf\n",r);

if(r<=Y){//The particle #1 is chosen
printf("r = %lf is less than Y = %lf. We choose the particle #1\n\n", r, Y);

//let's find between the nearest neighbors of the particle #1 at random

r1 = rand()/(float)RAND_MAX;
printf("r1 = %lf\n",r1);

rightneighbor(&i, &j, grid, &rx, &ry);
leftneighbor(&i, &j, grid, &lx, &ly);
upneighbor(&i, &j, grid, &ux, &uy);
downneighbor(&i, &j, grid, &dx, &dy);

if(r1<=0.25){
//selects the right neighbor

if(psi.grid[ry][rx]==P2_OCCUPIED){
//if the right neighbor is occupied with the particle #2, they react and form the particle #3
form_particle3(&psi, rx, ry);
}
else{
//there is no site with particle #2, particle #1 reamins adsorbed
}
}

else if(r1<=0.50){
///selects the left neighbor

if(psi.grid[ly][lx]==P2_OCCUPIED){
//if the left neighbor is occupied with the particle #2, they react and form the particle #3
form_particle3(&psi, lx, ly);

}
else{
//there is no site with particle #2, particle #1 reamins adsorbed
}

}

else if(r1<=0.75){
//selects the up neighbor

if(psi.grid[uy][ux]==P2_OCCUPIED){
//if the up neighbor is occupied with the particle #2, they react and form the particle #3
form_particle3(&psi, ux, uy);

}
else{
//there is no site with particle #2, particle #1 reamins adsorbed
}

}

else if(r1<=1.00){
//selects the down neighbor
if(psi.grid[dy][dx]==P2_OCCUPIED){
//if the down neighbor is occupied with the particle #2, they react and form the particle #3
form_particle3(&psi, dx, dy);

}
else{
//there is no site with particle #2, particle #1 reamins adsorbed
}

}
}

else{//The particle #2 is chosen
printf("r = %lf is greater than Y = %lf. We choose the particle #2\n\n", r, Y);

//let's find between the nearest neighbors of the particle #2 at random

r2 = rand()/(float)RAND_MAX;
printf("r2 = %lf\n",r2);

rightneighbor(&i, &j, grid, &rx, &ry);
leftneighbor(&i, &j, grid, &lx, &ly);
upneighbor(&i, &j, grid, &ux, &uy);
downneighbor(&i, &j, grid, &dx, &dy);

if(r2<=0.25){
//selects the right neighbor

if(psi.grid[ry][rx]==P1_OCCUPIED){
//if the right neighbor is occupied with the particle #1, they react and form the particle #3
form_particle3(&psi, rx, ry);

}
else{
//there is no site with particle #1, particle #2 reamins adsorbed
}

}

else if(r2<=0.50){
//selects the left neighbor

if(psi.grid[ly][lx]==P1_OCCUPIED){
//if the left neighbor is occupied with the particle #1, they react and form the particle #3
form_particle3(&psi, lx, ly);
}
else{
//there is no site with particle #1, particle #2 reamins adsorbed
}

}

else if(r2<=0.75){
//selects the up neighbor

if(psi.grid[uy][ux]==P1_OCCUPIED){
//if the up neighbor is occupied with the particle #1, they react and form the particle #3
form_particle3(&psi, ux, uy);
}
else{
//there is no site with particle #1, particle #2 reamins adsorbed
}

}

else if(r2<=1.00){
//selects the down neighbor

if(psi.grid[dy][dx]==P1_OCCUPIED){
//if the down neighbor is occupied with the particle #1, they react and form the particle #3
form_particle3(&psi, dx, dy);

}
else{
//there is no site with particle #1, particle #2 reamins adsorbed
}

}
}
break;

case P1_OCCUPIED:
//printf("IT'S OCCUPIED WITH THE PARTICLE #1. PLEASE, GENERATE ANOTHER SITE ON THE SURFACE\n\n");
break;

case P2_OCCUPIED:
//printf("IT'S OCCUPIED WITH THE PARTICLE #2. PLEASE, GENERATE ANOTHER SITE ON THE SURFACE\n\n");
break;

}
rounds++;
}
printf("The process took %d rounds\n\n", rounds);
printf("#particle1 = %d\n\n", psi.particle1);//total of particle1 adsorbed
printf("#particle2 = %d\n\n", psi.particle2);//total of particle2 adsorbed
printf("#particle3 = %d\n\n", psi.particle3);//total of particle3 created
printf("#availcells = %d\n\n", psi.availcells);
printf("#fullcells = %d\n\n", psi.fullcells);
return 0;
}```

As you can see, it is large and I'm not sure how to make it easier to maintain, debug, etc, mainly because I need to add additional particles and interactions in the future. Could you give me some suggestions to rewrite my code in a more condensed way?
Posted
Updated 27-Feb-23 15:05pm
v3
Member 15627495 27-Feb-23 10:27am
hello !

to replace nested "if elseif", you can use multiple "simple if" with 'accurates conditions' as 'test'. or write again a switch/case/break..

a 'else' or 'elseif' is equal to 'not' every time.
```// origin :
if(A == true){....;}else{....;}
// is equal to :
if(A == true){ ...; } // no else
if(A == false){ ...; } // no else

it's a way of writing code. it's really accurate, you'll have to considers all your conditions tests for a new code.
```

but the crowd of test you need will stay... more readable, but not less because of your app requirements.

## Solution 2

If you structure your data, then you may use functions in order to better organize your code.
you could do something similar to
C
```typedef  struct SimulInfo
{
gstate grid[MAX_Y][MAX_X];
int particle[3]; // counters for the number of particles
int availcells;
int fullcells;
} SimulInfo;
//...
void form_particle3(SimulInfo * psi, int x, int y)
{
psi->grid[y][x] = S_EMPTY;
psi->particle[2]++;
psi->availcells++;
psi->fullcells--;
}
void absorb_particle1(SimulInfo * psi, int x, int y)
{
psi->grid[y][x] = P1_OCCUPIED;
psi->particle[0]++;
psi->availcells--;
psi->fullcells++;
}
//..```

This way, your
Quote:
if(r1<=0.25){
//selects the right neighbor

if(grid[ry][rx]==P2_OCCUPIED){
//if the right neighbor is occupied with the particle #2, they react and form the particle #3
grid[ry][rx] = S_EMPTY;
particle3++;
availcells++;
fullcells--;
}
else{
//there is no site with particle #2, particle #1 reamins adsorbed
grid[j][i] = P1_OCCUPIED;
particle1++;
availcells--;
fullcells++;
}
}

Would become
C
```if(r1<=0.25)
{//selects the right neighbor
if(si.grid[ry][rx]==P2_OCCUPIED)
{
form_particle3(&si, rx, ry);
}
else
{
absorb_particle1(&si, rx, ry);
}
}```
(my two cents...)

[update]
Try the code below.
Please note, `si` stands for 'SimulInfo struct', while `psi` stands for 'pointer to SimulInfo struct'. It is just a convention, possibly a sensible one.
Also note, there is still room for further refactoring and improvement.

C
```#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

//define the dimensions of the grid
#define MAX_X 3
#define MAX_Y 3
#define Y 0.55

//define the states of a cell in grid`
typedef enum  { S_EMPTY, P1_OCCUPIED, P2_OCCUPIED, S_NONE } gstate;

// help generate random coordinate of the grid
int gridrnd(int max)
{
return (rand() % max);
}

// generates random coordinates of the grid
int generate_coords(int* j, int* i )
{
if (!i || !j)
return 1;

*i = gridrnd(MAX_X);
*j = gridrnd(MAX_Y);

// printf("(%d,%d)\n\n", *j, *i);
return 0;
}

//function to initialize the grid as empty
void grid_init( gstate grid[MAX_Y][MAX_X] )
{
for (int j = 0; j < MAX_Y; j++)
{
for (int i = 0; i < MAX_X; i++)
{
grid[j][i] = S_EMPTY;
}
}
}

//Function that locates the four nearest neighbors of the chosen site, considering periodic boundary conditions
int get_limited_coord(int coord, int coord_max)
{
if (coord >= 0 && coord < coord_max)
{
return coord;
}
else if (coord >= coord_max)
{
return coord - coord_max;
}
else
{
return coord + coord_max;
}
}

//Function that prints individually the "right" neighbor of the chosen site
gstate rightneighbor(int x, int y, int *rx, int *ry)
{
*ry = get_limited_coord(y, MAX_Y);
*rx = get_limited_coord(x+1, MAX_X);
printf("right neighbor = (%d,%d)\n\n",*ry,*rx);
return 0;
}

//Function that prints individually the "left" neighbor of the chosen site
void leftneighbor(int x, int y, int *lx, int *ly)
{
*ly = get_limited_coord(y , MAX_Y);
*lx = get_limited_coord(x-1, MAX_X);
printf("left neighbor = (%d,%d)\n\n",*ly,*lx);
}

//Function that prints individually the "up" neighbor of the chosen site
void upneighbor(int x, int y, int *ux, int *uy)
{
*uy = get_limited_coord(y-1, MAX_Y);
*ux = get_limited_coord(x , MAX_X);
printf("up neighbor = (%d,%d)\n\n",*uy,*ux);
}

//Function that prints individually the "down" neighbor of the chosen site
void downneighbor(int x, int y, int *dx, int *dy)
{
*dy = get_limited_coord(y+1, MAX_Y);
*dx = get_limited_coord(x , MAX_X);
printf("down neighbor = (%d,%d)\n\n",*dy,*dx);
}

//To give structure to my data
typedef struct SimulInfo
{
gstate grid[MAX_Y][MAX_X];
int particle1;
int particle2;
int particle3;
int availcells;
int fullcells;
} SimulInfo;

//function to fill a site with particle 1
int adsorb_particle1(SimulInfo * psi, int x, int y)
{
psi->grid[y][x] = P1_OCCUPIED;
psi->particle1++;
psi->availcells--;
psi->fullcells++;
return 0;
}

//function to fill a site with particle 2

int adsorb_particle2(SimulInfo * psi,int x, int y)
{
psi->grid[y][x] = P2_OCCUPIED;
psi->particle2++;
psi->availcells--;
psi->fullcells++;
return 0;
}

//function to form particle 3

int form_particle3(SimulInfo * psi, int x, int y)
{
psi->grid[y][x] = S_EMPTY;
psi->particle3++;
psi->availcells++;
psi->fullcells--;
return 0;
}

int main()
{
int i = 0, j = 0;
int rounds = 0;
int rx, ry, lx, ly, ux, uy, dx, dy;
double r=0, r1=0, r2=0;

SimulInfo si = {0}; // initialize the struct members with 0.
si.availcells = MAX_X * MAX_Y;
srand((unsigned)time(0));
grid_init(si.grid);// Initialize grid to be S_EMPTY

while(rounds<10)
{
//LOCATE AN ENTRY OF THE MATRIX RANDOMLY
generate_coords(&j, &i);

//EVALUATE THE CHOOSEN SITE
switch (si.grid[j][i])
{
case S_EMPTY:
//printf("IT'S S_EMPTY, LET'S FILL IT WITH A PARTICLE. FIRST LET'S GENERATE TO DECIDE IFIT WILL BE TRAPPED\n\n");
r = rand()/(float)RAND_MAX;
printf("r = %lf\n",r);
if( r<=Y )
{//The particle #1 is chosen
printf("r = %lf is less than Y = %lf. We choose the particle #1\n\n", r, Y);
//let's find between the nearest neighbors of the particle #1 at random
r1 = rand()/(float)RAND_MAX;
printf("r1 = %lf\n",r1);

rightneighbor(i, j, &rx, &ry);
leftneighbor(i, j, &lx, &ly);
upneighbor(i, j, &ux, &uy);
downneighbor(i, j, &dx, &dy);

if(r1<=0.25)
{
//selects the right neighbor
if(si.grid[ry][rx]==P2_OCCUPIED)
{//if the right neighbor is occupied with the particle #2, they react and form the particle #3
form_particle3(&si, rx, ry);
}
else
{//there is no site with particle #2, particle #1 reamins adsorbed
}
}
else if(r1<=0.50)
{///selects the left neighbor
if(si.grid[ly][lx]==P2_OCCUPIED)
{//if the left neighbor is occupied with the particle #2, they react and form the particle #3
form_particle3(&si, lx, ly);
}
else
{//there is no site with particle #2, particle #1 reamins adsorbed
}
}
else if(r1<=0.75)
{//selects the up neighbor
if(si.grid[uy][ux]==P2_OCCUPIED)
{//if the up neighbor is occupied with the particle #2, they react and form the particle #3
form_particle3(&si, ux, uy);
}
else
{//there is no site with particle #2, particle #1 reamins adsorbed
}
}
else if(r1<=1.00)
{ //selects the down neighbor
if(si.grid[dy][dx]==P2_OCCUPIED)
{//if the down neighbor is occupied with the particle #2, they react and form the particle #3
form_particle3(&si, dx, dy);
}
else
{//there is no site with particle #2, particle #1 reamins adsorbed
}
}
} // end of 'particle #1 is chosen'
else
{//The particle #2 is chosen
printf("r = %lf is greater than Y = %lf. We choose the particle #2\n\n", r, Y);
//let's find between the nearest neighbors of the particle #2 at random
r2 = rand()/(float)RAND_MAX;
printf("r2 = %lf\n",r2);
rightneighbor(i, j, &rx, &ry);
leftneighbor(i, j, &lx, &ly);
upneighbor(i, j, &ux, &uy);
downneighbor(i, j, &dx, &dy);
if(r2<=0.25)
{ //selects the right neighbor
if(si.grid[ry][rx]==P1_OCCUPIED)
{//if the right neighbor is occupied with the particle #1, they react and form the particle #3
form_particle3(&si, rx, ry);
}
else
{//there is no site with particle #1, particle #2 reamins adsorbed
}
}
else if(r2<=0.50)
{//selects the left neighbor
if(si.grid[ly][lx]==P1_OCCUPIED)
{//if the left neighbor is occupied with the particle #1, they react and form the particle #3
form_particle3(&si, lx, ly);
}
else
{//there is no site with particle #1, particle #2 reamins adsorbed
}
}
else if(r2<=0.75)
{//selects the up neighbor
if(si.grid[uy][ux]==P1_OCCUPIED)
{//if the up neighbor is occupied with the particle #1, they react and form the particle #3
form_particle3(&si, ux, uy);
}
else
{//there is no site with particle #1, particle #2 reamins adsorbed
}
}
else if(r2<=1.00)
{//selects the down neighbor
if(si.grid[dy][dx]==P1_OCCUPIED)
{//if the down neighbor is occupied with the particle #1, they react and form the particle #3
form_particle3(&si, dx, dy);
}
else
{//there is no site with particle #1, particle #2 reamins adsorbed
}
}
} // end of 'particle #2 is chosen'
break;
case P1_OCCUPIED:
//printf("IT'S OCCUPIED WITH THE PARTICLE #1. PLEASE, GENERATE ANOTHER SITE ON THE SURFACE\n\n");
break;
case P2_OCCUPIED:
//printf("IT'S OCCUPIED WITH THE PARTICLE #2. PLEASE, GENERATE ANOTHER SITE ON THE SURFACE\n\n");
break;
case S_NONE:
// what to do here?
break;
}// end of switch
rounds++;
} // endof of while
printf("The process took %d rounds\n\n", rounds);
printf("#particle1 = %d\n\n", si.particle1);//total of particle1 adsorbed
printf("#particle2 = %d\n\n", si.particle2);//total of particle2 adsorbed
printf("#particle3 = %d\n\n", si.particle3);//total of particle3 created
printf("#availcells = %d\n\n",si.availcells);
printf("#fullcells = %d\n\n", si.fullcells);
return 0;
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             ```

[/update]

v3
Auyik 27-Feb-23 13:19pm
Thanks! I hqve a question: why did you defined particle1, particle2, etc as integer arrays? Can I leave them as integers only?
CPallini 27-Feb-23 15:54pm
I defined an array in order to contain particle1, particle2, particle3. Generally speaking, when you have more than 2 (or 1?) equivalent items, it is better to use an array for them.
Auyik 27-Feb-23 13:44pm
I have another question ,why grid[y][x] inside "void absorb_particle1" hasn't the expression "psi ->" before?

Do I need to define psi, inside of the main function as "SimulInfo psi"?
CPallini 27-Feb-23 15:55pm
Sorry there were mistakes in my code. Hopefully they are fixed, now.
Sorry again.
Auyik 27-Feb-23 16:58pm
Thank you so much, no worries.

I applied your suggestion, but it seems that my code now, never counts the number of particles #1, #2 and #3. Also the counter for the fullcells remains zero :(

I also changed the new functions as "int" instead of "void", but that neither works.

## Solution 1

C
```//Function that prints individually the "right" neighbor of the chosen site
gstate rightneighbor(int *x, int *y, gstate grid[MAX_X][MAX_Y], int *rx, int *ry);```

I see no reason why x and y are always pointers here. Passing them as values seems to make more sense to me.
If you combine points in a structure you could also save typing and it would be more performant.
In the switch-case statement I would instead of page-long code subroutines and these if necessary also again into several subroutines divide.

//edit:
A serious problem could be that variables that are no longer needed are initialized, while those that are actually used remain uninitialized.
C
```int particle1 = 0, particle2 = 0, particle3 = 0; // counters for the number of particle1 and particle2
...
SimulInfo psi;```

It is noticeable that the exact same code section is used several times. Here again a function would be useful for simplification.
C
```react(SimulInfo* psi, int y, int x)
{
if (psi->grid[y][x] == P2_OCCUPIED) {
//if the neighbor is occupied with the particle #2, they react and form the particle #3
form_particle3(&psi, x, y);
}
else {
//there is no site with particle #2, particle #1 reamins adsorbed
}```

v3

Top Experts
Last 24hrsThis month
 k5054 40 rizlone 10 OriginalGriff 10 KarstenK 10 Graeme_Grant 10
 OriginalGriff 2,028 Richard Deeming 875 Dave Kreskowiak 591 Graeme_Grant 549 Richard MacCutchan 485

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